From cd3fac975109372a1de6b066d1f2f93195696808 Mon Sep 17 00:00:00 2001 From: GloriousEggroll Date: Wed, 10 May 2023 14:36:31 -0600 Subject: [PATCH] patches: huge patch cleanup --- VERSION | 2 +- patches/dxvk/2675.patch | 215 - .../FFVII-and-SpecialK-powerprof.patch | 170 - .../castlevania-advance-collection.patch | 12 - patches/game-patches/ffxiv-launcher-fix.patch | 37 - .../halo-infinite-twinapi.appcore.dll.patch | 634 - .../game-patches/origin-downloads_fix.patch | 11 - .../sword-art-online-gnutls.patch | 51 - .../01-proton-use_clock_monotonic.patch | 187 - patches/proton/03-proton-fsync_staging.patch | 3928 ----- patches/proton/04-proton-LAA_staging.patch | 134 - .../proton/08-proton-steamclient_swap.patch | 600 - .../proton/10-proton-protonify_staging.patch | 4175 ----- patches/proton/11-proton-pa-staging.patch | 695 - patches/proton/12-proton-steam-bits.patch | 778 - patches/proton/14-proton-sdl-joy.patch | 1002 -- .../proton/15-proton-gamepad-additions.patch | 1335 -- .../proton/16-proton-vrclient-wined3d.patch | 1621 -- patches/proton/18-proton-amd_ags.patch | 5784 ------ .../19-proton-msvcrt_nativebuiltin.patch | 81 - patches/proton/20-proton-atiadlxx.patch | 1865 -- .../21-proton-01_wolfenstein2_registry.patch | 22 - .../proton/22-proton-02_rdr2_registry.patch | 23 - ...3-proton-03_nier_sekiro_ds3_registry.patch | 25 - .../proton/24-proton-04_cod_registry.patch | 29 - patches/proton/25-proton-rdr2-fixes.patch | 190 - patches/proton/28-proton-win10_default.patch | 454 - patches/proton/29-proton-dxvk_config.patch | 90 - .../30-proton-mediafoundation_dllreg.patch | 142 - .../31-proton-mfplat-patches-valve.patch | 4884 ------ patches/proton/31-proton-mfplat-patches.patch | 14556 ---------------- .../32-proton-05_spellforce_registry.patch | 21 - .../33-proton-06_shadow_of_war_registry.patch | 29 - .../34-proton-winegstreamer_updates.patch | 214 - patches/proton/37-proton-OpenXR-patches.patch | 684 - ...keyboard-input-and-mouse-focus-fixes.patch | 1190 -- .../39-proton-cpu-topology-overrides.patch | 596 - .../proton/41-proton-07_nfs_registry.patch | 21 - .../proton/45-proton-08_FH4_registry.patch | 22 - .../proton/46-proton-09_nvapi_registry.patch | 93 - .../proton/47-proton-10_dirt_5_registry.patch | 22 - .../proton/49-proton_QPC-update-replace.patch | 285 - patches/proton/49-proton_QPC.patch | 1331 -- patches/proton/50-proton_LFH.patch | 3044 ---- patches/proton/51-proton_fonts.patch | 692 - .../52-proton_quake_champions_syscall.patch | 318 - .../54-proton-11_death_loop_registry.patch | 22 - .../proton/55-proton-bcrypt_rdr2_fixes.patch | 1611 -- ...roton-12_disable_libglesv2_for_nw.js.patch | 117 - patches/proton/57-fsync_futex_waitv.patch | 1246 -- ...-proton-13_atiadlxx_builtin_for_gotg.patch | 12 - .../proton/59-proton-battleye_patches.patch | 737 - .../60-proton-14-msedgewebview-registry.patch | 28 - .../61-proton-15-FH5-amd_ags_registry.patch | 23 - ...proton-16-Age-of-Empires-IV-registry.patch | 25 - ...dll-Support-x86_64-syscall-emulation.patch | 230 - ...e-check-before-returning-a-default-s.patch | 81 - patches/proton/66-proton-EAC-bridge.patch | 180 - patches/proton/67-protonify-2.patch | 5297 ------ .../68-proton-tabtip-uiautomationcore.patch | 13462 -------------- .../fshack/01-vulkan-1-prefer-builtin.patch | 22 - .../proton/fshack/02-vulkan-childwindow.patch | 1018 -- .../fshack/03-window-manager-fixes.patch | 1346 -- .../proton/fshack/04-fullscreen-hack.patch | 7060 -------- .../fshack/05-steam-overlay-fixes.patch | 483 - .../proton/fshack/06-post-fshack-tweaks.patch | 743 - patches/protonprep-valve-staging-7.0.sh | 418 - patches/protonprep-valve-staging.sh | 20 - ...efine-ControlMask-when-not-available.patch | 29 - ...d-THREAD_POWER_THROTTLING_STATE-type.patch | 32 - ...ccess-for-ThreadPowerThrottlingState.patch | 30 - patches/wine-hotfixes/pending/1152.patch | 173 - patches/wine-hotfixes/pending/181.patch | 23 - ...d2403f269e7f3595ad075a4afee9adbda51f.patch | 64 - .../pending/hotfix-update_mono_version.patch | 40 - ...test-for-file-attributes-of-files-wi.patch | 123 - ...n-code-hidden-file-handling-in-get_d.patch | 46 - ...den-file-names-inside-get_file_info-.patch | 91 - ...-hidden-attribute-from-file-name-if-.patch | 49 - ...in-NtCreateFile-if-inferred-and-requ.patch | 132 - ...rease-margins-in-timer-merging-tests.patch | 43 - ...port-for-calculating-secret-ecc-keys.patch | 476 - ...rt-for-OAEP-padded-asymmetric-key-de.patch | 319 - ...le32.tlb-Compile-typelib-with-oldtlb.patch | 10 - ...1-cryptext-Implement-CryptExtOpenCER.patch | 231 - .../cryptext-CryptExtOpenCER/definition | 2 - ...plement-D3DX11GetImageInfoFromMemory.patch | 254 - ...lement-D3DX11CreateTextureFromMemory.patch | 395 - .../definition | 4 - ...ment-FltBuildDefaultSecurityDescript.patch | 143 - ...002-fltmgr.sys-Create-import-library.patch | 23 - ...-FltBuildDefaultSecurityDescriptor-t.patch | 117 - .../definition | 2 - ...nt-CIF-reader-and-download-functions.patch | 3866 ---- .../inseng-Implementation/definition | 1 - .../0001-ntdll-Add-dummy-apiset-to-PEB.patch | 112 - .../staging-7.0/ntdll-ApiSetMap/definition | 1 - ...-versions-of-RtlEnterCriticalSection.patch | 65 - ...e-fast-CS-functions-for-heap-locking.patch | 128 - ...-CS-functions-for-threadpool-locking.patch | 396 - ...retrieving-DOS-attributes-in-fd_-get.patch | 122 - ...storing-DOS-attributes-in-NtSetInfor.patch | 168 - ...storing-DOS-attributes-in-NtCreateFi.patch | 154 - ...ort-for-Mac-OS-X-style-extended-attr.patch | 97 - ...ort-for-FreeBSD-style-extended-attri.patch | 116 - ...e-Unix-style-hidden-file-check-withi.patch | 80 - ...re-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch | 46 - .../ntdll-DOS_Attributes/definition | 2 - ...basic-tests-for-RtlQueryPackageIdent.patch | 144 - .../ntdll-RtlQueryPackageIdentity/definition | 1 - ...e-check-before-returning-a-default-s.patch | 82 - .../ntdll-Serial_Port_Detection/definition | 1 - ...-nvcuda-attempt-to-load-libcuda.so.1.patch | 29 - .../0001-packager-Prefer-native-version.patch | 25 - .../staging-7.0/packager-DllMain/definition | 1 - .../proton-staging-syscall-emu.patch | 85 - ...-relative-RawMotion-events-unprocess.patch | 106 - ...ignal-thread-until-it-is-really-gone.patch | 114 - .../server-Signal_Thread/definition | 1 - ...ocesses-using-a-limited-administrato.patch | 27 - ...002-shell32-Implement-the-runas-verb.patch | 76 - ...ine.inf-Set-the-EnableLUA-value-to-1.patch | 29 - ...ustom-action-server-as-an-elevated-p.patch | 68 - ...rt-the-initial-process-through-start.patch | 50 - ...te-processes-if-requested-in-CreateP.patch | 110 - ...ocesses-if-requested-in-RtlCreateUse.patch | 127 - .../server-default_integrity/definition | 2 - ...plement-NewMenu-with-new-folder-item.patch | 607 - .../shell32-NewMenu_Interface/definition | 1 - ...ove_ntdll_Junction_Points_dependency.patch | 44 - .../staging-revert-user32-msgbox.patch | 34 - .../staging-server-default-integrity.patch | 23 - ...lashWindowEx-message-and-return-valu.patch | 32 - .../user32-FlashWindowEx/definition | 1 - ...-windows.networking.connectivity.idl.patch | 400 - ...2-include-Add-windows.networking.idl.patch | 120 - ...networking.connectivity-Add-stub-dll.patch | 97 - ...ng.connectivity-Implement-IActivatio.patch | 136 - ...ng.connectivity-Implement-INetworkIn.patch | 301 - ...networking.connectivity-Registry-DLL.patch | 79 - ...ng.connectivity-Implement-INetworkIn.patch | 198 - ...ng.connectivity-IConnectionProfile-G.patch | 30 - .../definition | 1 - ...itialize-proxy-settings-registry-key.patch | 59 - .../wineboot-ProxySettings/definition | 1 - ...Create-desktop-shortcuts-with-absolu.patch | 67 - ...a-blending-in-X11DRV_UpdateLayeredWi.patch | 111 - .../winex11-UpdateLayeredWindow/definition | 1 - ...a-default-vulkan-driver-if-one-not-f.patch | 84 - .../winex11-Vulkan_support/definition | 1 - ...able-windows-when-they-are-un-mapped.patch | 56 - .../staging-7.0/winex11-XEMBED/definition | 1 - ...-warn-about-used-contexts-in-wglShar.patch | 53 - .../winex11-wglShareLists/definition | 2 - ...net-tests-Add-more-tests-for-cookies.patch | 145 - ...st-auth-credential-reusage-with-host.patch | 130 - ...eck-cookie-behaviour-when-overriding.patch | 132 - ...filename-if-no-path-is-set-in-cookie.patch | 82 - ...g-header-fields-should-fail-if-they-.patch | 241 - .../staging-7.0/wininet-Cleanup/definition | 1 - ...ameter-check-in-WTHelperGetProvCertF.patch | 26 - .../definition | 1 - ...eturn-TRUE-for-d-and-u-stub-switches.patch | 33 - .../wscript-support-d-u-switches/definition | 1 - ...01-x3daudio1_7-Create-import-library.patch | 23 - .../staging-7.0/xactengine-initial/definition | 5 - ...001-Add-support-for-private-contexts.patch | 159 - .../0002-xactengine3_7-notifications.patch | 155 - ...d-NOTIFY_CUESTOP-when-Stop-is-called.patch | 25 - ...n-t-use-switch-with-constant-integer.patch | 83 - .../xactengine3_7-callbacks/definition | 2 - ...port-for-calculating-secret-ecc-keys.patch | 476 - ...rt-for-OAEP-padded-asymmetric-key-de.patch | 319 - ...le32.tlb-Compile-typelib-with-oldtlb.patch | 10 - .../0001-ntdll-Add-dummy-apiset-to-PEB.patch | 112 - .../staging/ntdll-ApiSetMap/definition | 1 - ...-versions-of-RtlEnterCriticalSection.patch | 65 - ...e-fast-CS-functions-for-heap-locking.patch | 128 - ...-CS-functions-for-threadpool-locking.patch | 396 - ...retrieving-DOS-attributes-in-fd_-get.patch | 122 - ...storing-DOS-attributes-in-NtSetInfor.patch | 168 - ...storing-DOS-attributes-in-NtCreateFi.patch | 154 - ...ort-for-Mac-OS-X-style-extended-attr.patch | 97 - ...ort-for-FreeBSD-style-extended-attri.patch | 116 - ...e-Unix-style-hidden-file-check-withi.patch | 80 - ...re-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch | 46 - .../staging/ntdll-DOS_Attributes/definition | 2 - ...e-check-before-returning-a-default-s.patch | 81 - .../ntdll-Serial_Port_Detection/definition | 1 - ...-nvcuda-attempt-to-load-libcuda.so.1.patch | 29 - .../staging/proton-staging-syscall-emu.patch | 85 - ...ignal-thread-until-it-is-really-gone.patch | 114 - .../staging/server-Signal_Thread/definition | 1 - ...ocesses-using-a-limited-administrato.patch | 27 - ...002-shell32-Implement-the-runas-verb.patch | 76 - ...ine.inf-Set-the-EnableLUA-value-to-1.patch | 29 - ...ustom-action-server-as-an-elevated-p.patch | 68 - ...rt-the-initial-process-through-start.patch | 50 - ...te-processes-if-requested-in-CreateP.patch | 110 - ...ocesses-if-requested-in-RtlCreateUse.patch | 127 - .../server-default_integrity/definition | 2 - ...ove_ntdll_Junction_Points_dependency.patch | 44 - .../staging-revert-user32-msgbox.patch | 34 - .../staging-server-default-integrity.patch | 23 - ...Create-desktop-shortcuts-with-absolu.patch | 67 - ...Blacklist-desktop-integration-for-ce.patch | 174 - .../winemenubuilder-integration/definition | 2 - ...a-blending-in-X11DRV_UpdateLayeredWi.patch | 111 - .../winex11-UpdateLayeredWindow/definition | 1 - ...able-windows-when-they-are-un-mapped.patch | 56 - .../staging/winex11-XEMBED/definition | 1 - ...-warn-about-used-contexts-in-wglShar.patch | 53 - .../staging/winex11-wglShareLists/definition | 2 - ...001-Add-support-for-private-contexts.patch | 159 - .../0002-xactengine3_7-notifications.patch | 155 - ...d-NOTIFY_CUESTOP-when-Stop-is-called.patch | 25 - ...n-t-use-switch-with-constant-integer.patch | 83 - .../xactengine3_7-callbacks/definition | 2 - patches/wine-hotfixes/upstream/2326.patch | 75 - .../upstream/32-bit-ldap-upstream-fix.patch | 68 - ...2a9ae151f676a009e89b4b101679fd90b9ae.patch | 203 - patches/wine-hotfixes/upstream/481.patch | 108 - ...Fix-regression-introduced-by-0e7fd41.patch | 29 - .../upstream/visual-novel-doukyuusei.patch | 285 - 224 files changed, 1 insertion(+), 104393 deletions(-) delete mode 100644 patches/dxvk/2675.patch delete mode 100644 patches/game-patches/FFVII-and-SpecialK-powerprof.patch delete mode 100644 patches/game-patches/castlevania-advance-collection.patch delete mode 100644 patches/game-patches/ffxiv-launcher-fix.patch delete mode 100644 patches/game-patches/halo-infinite-twinapi.appcore.dll.patch delete mode 100755 patches/game-patches/origin-downloads_fix.patch delete mode 100755 patches/game-patches/sword-art-online-gnutls.patch delete mode 100755 patches/proton/01-proton-use_clock_monotonic.patch delete mode 100755 patches/proton/03-proton-fsync_staging.patch delete mode 100755 patches/proton/04-proton-LAA_staging.patch delete mode 100755 patches/proton/08-proton-steamclient_swap.patch delete mode 100644 patches/proton/10-proton-protonify_staging.patch delete mode 100644 patches/proton/11-proton-pa-staging.patch delete mode 100755 patches/proton/12-proton-steam-bits.patch delete mode 100644 patches/proton/14-proton-sdl-joy.patch delete mode 100644 patches/proton/15-proton-gamepad-additions.patch delete mode 100755 patches/proton/16-proton-vrclient-wined3d.patch delete mode 100755 patches/proton/18-proton-amd_ags.patch delete mode 100755 patches/proton/19-proton-msvcrt_nativebuiltin.patch delete mode 100755 patches/proton/20-proton-atiadlxx.patch delete mode 100755 patches/proton/21-proton-01_wolfenstein2_registry.patch delete mode 100755 patches/proton/22-proton-02_rdr2_registry.patch delete mode 100755 patches/proton/23-proton-03_nier_sekiro_ds3_registry.patch delete mode 100755 patches/proton/24-proton-04_cod_registry.patch delete mode 100644 patches/proton/25-proton-rdr2-fixes.patch delete mode 100755 patches/proton/28-proton-win10_default.patch delete mode 100755 patches/proton/29-proton-dxvk_config.patch delete mode 100755 patches/proton/30-proton-mediafoundation_dllreg.patch delete mode 100644 patches/proton/31-proton-mfplat-patches-valve.patch delete mode 100644 patches/proton/31-proton-mfplat-patches.patch delete mode 100644 patches/proton/32-proton-05_spellforce_registry.patch delete mode 100644 patches/proton/33-proton-06_shadow_of_war_registry.patch delete mode 100644 patches/proton/34-proton-winegstreamer_updates.patch delete mode 100644 patches/proton/37-proton-OpenXR-patches.patch delete mode 100644 patches/proton/38-proton-keyboard-input-and-mouse-focus-fixes.patch delete mode 100644 patches/proton/39-proton-cpu-topology-overrides.patch delete mode 100644 patches/proton/41-proton-07_nfs_registry.patch delete mode 100644 patches/proton/45-proton-08_FH4_registry.patch delete mode 100644 patches/proton/46-proton-09_nvapi_registry.patch delete mode 100644 patches/proton/47-proton-10_dirt_5_registry.patch delete mode 100644 patches/proton/49-proton_QPC-update-replace.patch delete mode 100644 patches/proton/49-proton_QPC.patch delete mode 100644 patches/proton/50-proton_LFH.patch delete mode 100644 patches/proton/51-proton_fonts.patch delete mode 100644 patches/proton/52-proton_quake_champions_syscall.patch delete mode 100644 patches/proton/54-proton-11_death_loop_registry.patch delete mode 100644 patches/proton/55-proton-bcrypt_rdr2_fixes.patch delete mode 100644 patches/proton/56-proton-12_disable_libglesv2_for_nw.js.patch delete mode 100644 patches/proton/57-fsync_futex_waitv.patch delete mode 100644 patches/proton/58-proton-13_atiadlxx_builtin_for_gotg.patch delete mode 100644 patches/proton/59-proton-battleye_patches.patch delete mode 100644 patches/proton/60-proton-14-msedgewebview-registry.patch delete mode 100644 patches/proton/61-proton-15-FH5-amd_ags_registry.patch delete mode 100644 patches/proton/62-proton-16-Age-of-Empires-IV-registry.patch delete mode 100644 patches/proton/63-ntdll-Support-x86_64-syscall-emulation.patch delete mode 100644 patches/proton/64-ntdll-Do-a-device-check-before-returning-a-default-s.patch delete mode 100644 patches/proton/66-proton-EAC-bridge.patch delete mode 100644 patches/proton/67-protonify-2.patch delete mode 100644 patches/proton/68-proton-tabtip-uiautomationcore.patch delete mode 100644 patches/proton/fshack/01-vulkan-1-prefer-builtin.patch delete mode 100644 patches/proton/fshack/02-vulkan-childwindow.patch delete mode 100644 patches/proton/fshack/03-window-manager-fixes.patch delete mode 100644 patches/proton/fshack/04-fullscreen-hack.patch delete mode 100644 patches/proton/fshack/05-steam-overlay-fixes.patch delete mode 100644 patches/proton/fshack/06-post-fshack-tweaks.patch delete mode 100755 patches/protonprep-valve-staging-7.0.sh delete mode 100644 patches/wine-hotfixes/pending/0001-winex11.drv-Define-ControlMask-when-not-available.patch delete mode 100644 patches/wine-hotfixes/pending/0002-include-Add-THREAD_POWER_THROTTLING_STATE-type.patch delete mode 100644 patches/wine-hotfixes/pending/0003-ntdll-Fake-success-for-ThreadPowerThrottlingState.patch delete mode 100644 patches/wine-hotfixes/pending/1152.patch delete mode 100644 patches/wine-hotfixes/pending/181.patch delete mode 100644 patches/wine-hotfixes/pending/4bf9d2403f269e7f3595ad075a4afee9adbda51f.patch delete mode 100644 patches/wine-hotfixes/pending/hotfix-update_mono_version.patch delete mode 100644 patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0001-ntdll-tests-Add-test-for-file-attributes-of-files-wi.patch delete mode 100644 patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0002-ntdll-Do-not-open-code-hidden-file-handling-in-get_d.patch delete mode 100644 patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0003-ntdll-Handle-hidden-file-names-inside-get_file_info-.patch delete mode 100644 patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0004-ntdll-Only-infer-hidden-attribute-from-file-name-if-.patch delete mode 100644 patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0005-ntdll-Set-xattr-in-NtCreateFile-if-inferred-and-requ.patch delete mode 100644 patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0006-ntdll-tests-Increase-margins-in-timer-merging-tests.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/0002-bcrypt-Add-support-for-calculating-secret-ecc-keys.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/0003-bcrypt-Add-support-for-OAEP-padded-asymmetric-key-de.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/0020-stdole32.tlb-Compile-typelib-with-oldtlb.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/0001-cryptext-Implement-CryptExtOpenCER.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0001-d3dx11_43-Implement-D3DX11GetImageInfoFromMemory.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0002-d3dx11_42-Implement-D3DX11CreateTextureFromMemory.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0001-fltmgr.sys-Implement-FltBuildDefaultSecurityDescript.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0002-fltmgr.sys-Create-import-library.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0003-ntoskrnl.exe-Add-FltBuildDefaultSecurityDescriptor-t.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/inseng-Implementation/0001-inseng-Implement-CIF-reader-and-download-functions.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/inseng-Implementation/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-ApiSetMap/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0002-ntdll-Add-inline-versions-of-RtlEnterCriticalSection.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0003-ntdll-Use-fast-CS-functions-for-heap-locking.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0004-ntdll-Use-fast-CS-functions-for-threadpool-locking.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/0003-ntdll-tests-Add-basic-tests-for-RtlQueryPackageIdent.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/packager-DllMain/0001-packager-Prefer-native-version.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/packager-DllMain/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/proton-staging-syscall-emu.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/rawinput/0006-winex11.drv-Send-relative-RawMotion-events-unprocess.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-Signal_Thread/0001-server-Do-not-signal-thread-until-it-is-really-gone.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-Signal_Thread/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-default_integrity/0002-shell32-Implement-the-runas-verb.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/server-default_integrity/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/0001-shell32-Implement-NewMenu-with-new-folder-item.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/staging-esync_remove_ntdll_Junction_Points_dependency.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/staging-revert-user32-msgbox.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/staging-server-default-integrity.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/0001-user32-Improve-FlashWindowEx-message-and-return-valu.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0001-include-Add-windows.networking.connectivity.idl.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0002-include-Add-windows.networking.idl.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0003-windows.networking.connectivity-Add-stub-dll.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0004-windows.networking.connectivity-Implement-IActivatio.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0005-windows.networking.connectivity-Implement-INetworkIn.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0006-windows.networking.connectivity-Registry-DLL.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0007-windows.networking.connectivity-Implement-INetworkIn.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0008-windows.networking.connectivity-IConnectionProfile-G.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/0001-wineboot-Initialize-proxy-settings-registry-key.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/winex11-UpdateLayeredWindow/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/0001-winex11-Specify-a-default-vulkan-driver-if-one-not-f.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/winex11-XEMBED/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0001-wininet-tests-Add-more-tests-for-cookies.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0002-wininet-tests-Test-auth-credential-reusage-with-host.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0003-wininet-tests-Check-cookie-behaviour-when-overriding.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0004-wininet-Strip-filename-if-no-path-is-set-in-cookie.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0005-wininet-Replacing-header-fields-should-fail-if-they-.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/wininet-Cleanup/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/0001-wintrust-Add-parameter-check-in-WTHelperGetProvCertF.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/0001-wscript-return-TRUE-for-d-and-u-stub-switches.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/xactengine-initial/0001-x3daudio1_7-Create-import-library.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/xactengine-initial/definition delete mode 100644 patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch delete mode 100644 patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/definition delete mode 100644 patches/wine-hotfixes/staging/0002-bcrypt-Add-support-for-calculating-secret-ecc-keys.patch delete mode 100644 patches/wine-hotfixes/staging/0003-bcrypt-Add-support-for-OAEP-padded-asymmetric-key-de.patch delete mode 100644 patches/wine-hotfixes/staging/0020-stdole32.tlb-Compile-typelib-with-oldtlb.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-ApiSetMap/definition delete mode 100644 patches/wine-hotfixes/staging/ntdll-CriticalSection/0002-ntdll-Add-inline-versions-of-RtlEnterCriticalSection.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-CriticalSection/0003-ntdll-Use-fast-CS-functions-for-heap-locking.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-CriticalSection/0004-ntdll-Use-fast-CS-functions-for-threadpool-locking.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-DOS_Attributes/definition delete mode 100644 patches/wine-hotfixes/staging/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch delete mode 100644 patches/wine-hotfixes/staging/ntdll-Serial_Port_Detection/definition delete mode 100644 patches/wine-hotfixes/staging/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch delete mode 100644 patches/wine-hotfixes/staging/proton-staging-syscall-emu.patch delete mode 100644 patches/wine-hotfixes/staging/server-Signal_Thread/0001-server-Do-not-signal-thread-until-it-is-really-gone.patch delete mode 100644 patches/wine-hotfixes/staging/server-Signal_Thread/definition delete mode 100644 patches/wine-hotfixes/staging/server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch delete mode 100644 patches/wine-hotfixes/staging/server-default_integrity/0002-shell32-Implement-the-runas-verb.patch delete mode 100644 patches/wine-hotfixes/staging/server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch delete mode 100644 patches/wine-hotfixes/staging/server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch delete mode 100644 patches/wine-hotfixes/staging/server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch delete mode 100644 patches/wine-hotfixes/staging/server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch delete mode 100644 patches/wine-hotfixes/staging/server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch delete mode 100644 patches/wine-hotfixes/staging/server-default_integrity/definition delete mode 100644 patches/wine-hotfixes/staging/staging-esync_remove_ntdll_Junction_Points_dependency.patch delete mode 100644 patches/wine-hotfixes/staging/staging-revert-user32-msgbox.patch delete mode 100644 patches/wine-hotfixes/staging/staging-server-default-integrity.patch delete mode 100644 patches/wine-hotfixes/staging/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch delete mode 100644 patches/wine-hotfixes/staging/winemenubuilder-integration/0001-winemenubuilder-Blacklist-desktop-integration-for-ce.patch delete mode 100644 patches/wine-hotfixes/staging/winemenubuilder-integration/definition delete mode 100644 patches/wine-hotfixes/staging/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch delete mode 100644 patches/wine-hotfixes/staging/winex11-UpdateLayeredWindow/definition delete mode 100644 patches/wine-hotfixes/staging/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch delete mode 100644 patches/wine-hotfixes/staging/winex11-XEMBED/definition delete mode 100644 patches/wine-hotfixes/staging/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch delete mode 100644 patches/wine-hotfixes/staging/winex11-wglShareLists/definition delete mode 100644 patches/wine-hotfixes/staging/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch delete mode 100644 patches/wine-hotfixes/staging/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch delete mode 100644 patches/wine-hotfixes/staging/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch delete mode 100644 patches/wine-hotfixes/staging/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch delete mode 100644 patches/wine-hotfixes/staging/xactengine3_7-callbacks/definition delete mode 100644 patches/wine-hotfixes/upstream/2326.patch delete mode 100644 patches/wine-hotfixes/upstream/32-bit-ldap-upstream-fix.patch delete mode 100644 patches/wine-hotfixes/upstream/381c2a9ae151f676a009e89b4b101679fd90b9ae.patch delete mode 100644 patches/wine-hotfixes/upstream/481.patch delete mode 100644 patches/wine-hotfixes/upstream/Fix-regression-introduced-by-0e7fd41.patch delete mode 100644 patches/wine-hotfixes/upstream/visual-novel-doukyuusei.patch diff --git a/VERSION b/VERSION index 9af2bae34..69fc95527 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -GE-Proton8-3 +GE-Proton8-2 diff --git a/patches/dxvk/2675.patch b/patches/dxvk/2675.patch deleted file mode 100644 index 98ea0e3b4..000000000 --- a/patches/dxvk/2675.patch +++ /dev/null @@ -1,215 +0,0 @@ -From a454ac20b3b503c1d4396b1ea2850e1ca5a1c1ba Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 9 Jun 2022 16:34:39 -0500 -Subject: [PATCH] [dxgi] Leave fullscreen mode when window looses focus - ---- - src/dxgi/dxgi_factory.cpp | 2 +- - src/dxgi/dxgi_swapchain.cpp | 23 ++++++++++++++++++++--- - src/dxgi/dxgi_swapchain.h | 7 +++++-- - src/wsi/glfw/wsi_window_glfw.cpp | 14 +++++++++++++- - src/wsi/sdl2/wsi_window_sdl2.cpp | 11 +++++++++++ - src/wsi/win32/wsi_window_win32.cpp | 10 ++++++++++ - src/wsi/wsi_window.h | 16 ++++++++++++++++ - 7 files changed, 76 insertions(+), 7 deletions(-) - -diff --git a/src/dxgi/dxgi_factory.cpp b/src/dxgi/dxgi_factory.cpp -index 3e218ecb4de..e0569b6387d 100644 ---- a/src/dxgi/dxgi_factory.cpp -+++ b/src/dxgi/dxgi_factory.cpp -@@ -215,7 +215,7 @@ namespace dxvk { - return hr; - } - -- frontendSwapChain = new DxgiSwapChain(this, presenter.ptr(), hWnd, &desc, &fsDesc); -+ frontendSwapChain = new DxgiSwapChain(this, presenter.ptr(), hWnd, &desc, &fsDesc, pDevice); - } else { - Logger::err("DXGI: CreateSwapChainForHwnd: Unsupported device type"); - return DXGI_ERROR_UNSUPPORTED; -diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp -index 226ba28d66a..3c71f82b057 100644 ---- a/src/dxgi/dxgi_swapchain.cpp -+++ b/src/dxgi/dxgi_swapchain.cpp -@@ -4,6 +4,8 @@ - - #include "../util/util_misc.h" - -+#include -+ - namespace dxvk { - - DxgiSwapChain::DxgiSwapChain( -@@ -11,14 +13,17 @@ namespace dxvk { - IDXGIVkSwapChain* pPresenter, - HWND hWnd, - const DXGI_SWAP_CHAIN_DESC1* pDesc, -- const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc) -+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, -+ IUnknown* pDevice) - : m_factory (pFactory), - m_window (hWnd), - m_desc (*pDesc), - m_descFs (*pFullscreenDesc), - m_presentCount(0u), - m_presenter (pPresenter), -- m_monitor (wsi::getWindowMonitor(m_window)) { -+ m_monitor (wsi::getWindowMonitor(m_window)), -+ m_is_d3d12(SUCCEEDED(pDevice->QueryInterface(__uuidof(ID3D12CommandQueue), reinterpret_cast(&Com())))) { -+ - if (FAILED(m_presenter->GetAdapter(__uuidof(IDXGIAdapter), reinterpret_cast(&m_adapter)))) - throw DxvkError("DXGI: Failed to get adapter for present device"); - -@@ -214,7 +219,9 @@ namespace dxvk { - BOOL* pFullscreen, - IDXGIOutput** ppTarget) { - HRESULT hr = S_OK; -- -+ -+ if (!m_is_d3d12 && !m_descFs.Windowed && wsi::isOccluded(m_window)) -+ SetFullscreenState(FALSE, nullptr); - if (pFullscreen != nullptr) - *pFullscreen = !m_descFs.Windowed; - -@@ -287,6 +294,16 @@ namespace dxvk { - if (SyncInterval > 4) - return DXGI_ERROR_INVALID_CALL; - -+ if (!m_is_d3d12 && wsi::isMinimized(m_window)) -+ return DXGI_STATUS_OCCLUDED; -+ -+ if (!m_descFs.Windowed && wsi::isOccluded(m_window)) -+ { -+ if (!(PresentFlags & DXGI_PRESENT_TEST)) -+ SetFullscreenState(FALSE, nullptr); -+ return DXGI_STATUS_OCCLUDED; -+ } -+ - std::lock_guard lockWin(m_lockWindow); - std::lock_guard lockBuf(m_lockBuffer); - -diff --git a/src/dxgi/dxgi_swapchain.h b/src/dxgi/dxgi_swapchain.h -index c32c2c7913d..1c977d47e0c 100644 ---- a/src/dxgi/dxgi_swapchain.h -+++ b/src/dxgi/dxgi_swapchain.h -@@ -31,7 +31,8 @@ namespace dxvk { - IDXGIVkSwapChain* pPresenter, - HWND hWnd, - const DXGI_SWAP_CHAIN_DESC1* pDesc, -- const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc); -+ const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, -+ IUnknown* pDevice); - - ~DxgiSwapChain(); - -@@ -189,7 +190,9 @@ namespace dxvk { - - HMONITOR m_monitor; - wsi::DxvkWindowState m_windowState; -- -+ -+ bool m_is_d3d12; -+ - HRESULT EnterFullscreenMode( - IDXGIOutput1 *pTarget); - -diff --git a/src/wsi/glfw/wsi_window_glfw.cpp b/src/wsi/glfw/wsi_window_glfw.cpp -index 700312507bc..4cae1f360c7 100644 ---- a/src/wsi/glfw/wsi_window_glfw.cpp -+++ b/src/wsi/glfw/wsi_window_glfw.cpp -@@ -124,6 +124,18 @@ namespace dxvk::wsi { - return window != nullptr; - } - -+ -+ bool isMinimized(HWND hWindow) { -+ GLFWwindow* window = fromHwnd(hWindow); -+ return glfwGetWindowAttrib(window, GLFW_ICONIFIED) != 0; -+ } -+ -+ -+ bool isOccluded(HWND hWindow) { -+ return false; -+ } -+ -+ - void updateFullscreenWindow( - HMONITOR hMonitor, - HWND hWindow, -@@ -141,4 +153,4 @@ namespace dxvk::wsi { - return glfwCreateWindowSurface(instance, window, nullptr, pSurface); - } - --} -\ No newline at end of file -+} -diff --git a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/wsi/sdl2/wsi_window_sdl2.cpp -index 1280b6c10ad..506c9b57bf5 100644 ---- a/src/wsi/sdl2/wsi_window_sdl2.cpp -+++ b/src/wsi/sdl2/wsi_window_sdl2.cpp -@@ -134,6 +134,17 @@ namespace dxvk::wsi { - } - - -+ bool isMinimized(HWND hWindow) { -+ SDL_Window* window = fromHwnd(hWindow); -+ return (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0; -+ } -+ -+ -+ bool isOccluded(HWND hWindow) { -+ return false; -+ } -+ -+ - void updateFullscreenWindow( - HMONITOR hMonitor, - HWND hWindow, -diff --git a/src/wsi/win32/wsi_window_win32.cpp b/src/wsi/win32/wsi_window_win32.cpp -index 597d7478f63..53b7e597996 100644 ---- a/src/wsi/win32/wsi_window_win32.cpp -+++ b/src/wsi/win32/wsi_window_win32.cpp -@@ -253,6 +253,16 @@ namespace dxvk::wsi { - } - - -+ bool isMinimized(HWND hWindow) { -+ return (::GetWindowLongW(hWindow, GWL_STYLE) & WS_MINIMIZE) != 0; -+ } -+ -+ -+ bool isOccluded(HWND hWindow) { -+ return ::GetForegroundWindow() != hWindow; -+ } -+ -+ - void updateFullscreenWindow( - HMONITOR hMonitor, - HWND hWindow, -diff --git a/src/wsi/wsi_window.h b/src/wsi/wsi_window.h -index e0587a0fd77..3b24075d6ca 100644 ---- a/src/wsi/wsi_window.h -+++ b/src/wsi/wsi_window.h -@@ -99,6 +99,22 @@ namespace dxvk::wsi { - */ - bool isWindow(HWND hWindow); - -+ /** -+ * \brief Is window minimized? -+ * -+ * \param [in] hWindow The window -+ * \returns Is window minimized? -+ */ -+ bool isMinimized(HWND hWindow); -+ -+ /** -+ * \brief Is window occluded? -+ * -+ * \param [in] hWindow The window -+ * \returns Is window occluded? -+ */ -+ bool isOccluded(HWND hWindow); -+ - /** - * \brief Update a fullscreen window's position/size - * - diff --git a/patches/game-patches/FFVII-and-SpecialK-powerprof.patch b/patches/game-patches/FFVII-and-SpecialK-powerprof.patch deleted file mode 100644 index 8dfb15a72..000000000 --- a/patches/game-patches/FFVII-and-SpecialK-powerprof.patch +++ /dev/null @@ -1,170 +0,0 @@ -From 2074e13a43ad07c635388fe3739225a2752b1754 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Sun, 27 Feb 2022 02:02:33 +0100 -Subject: [PATCH] powrprof: Add PowerUnregisterSuspendResumeNotification stub. - -Allegedly needed by Final Fantasy VII Remake to not crash on exit. - -Signed-off-by: Torge Matthies -Signed-off-by: Alexandre Julliard ---- - dlls/powrprof/powrprof.c | 7 +++++++ - dlls/powrprof/powrprof.spec | 1 + - include/powrprof.h | 1 + - 3 files changed, 9 insertions(+) - -diff --git a/dlls/powrprof/powrprof.c b/dlls/powrprof/powrprof.c -index c4af8ab9ce1..dc6e8bdaa15 100644 ---- a/dlls/powrprof/powrprof.c -+++ b/dlls/powrprof/powrprof.c -@@ -333,6 +333,13 @@ DWORD WINAPI PowerEnumerate(HKEY key, const GUID *scheme, const GUID *subgroup, - DWORD WINAPI PowerRegisterSuspendResumeNotification(DWORD flags, HANDLE recipient, PHPOWERNOTIFY handle) - { - FIXME("(0x%08x,%p,%p) stub!\n", flags, recipient, handle); -+ *handle = (HPOWERNOTIFY)0xdeadbeef; -+ return ERROR_SUCCESS; -+} -+ -+DWORD WINAPI PowerUnregisterSuspendResumeNotification(HPOWERNOTIFY handle) -+{ -+ FIXME("(%p) stub!\n", handle); - return ERROR_SUCCESS; - } - -diff --git a/dlls/powrprof/powrprof.spec b/dlls/powrprof/powrprof.spec -index bf12e14a323..cbd2e47c1f2 100644 ---- a/dlls/powrprof/powrprof.spec -+++ b/dlls/powrprof/powrprof.spec -@@ -18,6 +18,7 @@ - @ stdcall PowerReadDCValue (ptr ptr ptr ptr ptr ptr ptr) - @ stdcall PowerReadFriendlyName (ptr ptr ptr ptr ptr ptr) - @ stdcall PowerRegisterSuspendResumeNotification(long ptr ptr) -+@ stdcall PowerUnregisterSuspendResumeNotification(ptr) - @ stdcall ReadGlobalPwrPolicy (ptr) - @ stdcall ReadProcessorPwrScheme (long ptr) - @ stdcall ReadPwrScheme (long ptr) -diff --git a/include/powrprof.h b/include/powrprof.h -index 546e259a39a..6959a9aeb13 100644 ---- a/include/powrprof.h -+++ b/include/powrprof.h -@@ -161,6 +161,7 @@ BOOLEAN WINAPI IsPwrShutdownAllowed(VOID); - BOOLEAN WINAPI IsPwrSuspendAllowed(VOID); - DWORD WINAPI PowerEnumerate(HKEY, const GUID *, const GUID *, POWER_DATA_ACCESSOR, ULONG, UCHAR *, DWORD *); - DWORD WINAPI PowerRegisterSuspendResumeNotification(DWORD, HANDLE, PHPOWERNOTIFY); -+DWORD WINAPI PowerUnregisterSuspendResumeNotification(HPOWERNOTIFY); - BOOLEAN WINAPI ReadGlobalPwrPolicy(PGLOBAL_POWER_POLICY); - BOOLEAN WINAPI ReadProcessorPwrScheme(UINT, PMACHINE_PROCESSOR_POWER_POLICY); - BOOLEAN WINAPI ReadPwrScheme(UINT, PPOWER_POLICY); -From 7180a9b926214acc8ff984b4b8fc04287d238d2c Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Sun, 27 Feb 2022 02:02:34 +0100 -Subject: [PATCH] powrprof: Add PowerSettingRegisterNotification stub. - -Needed by old Special K versions according to -https://github.com/ValveSoftware/Proton/issues/5625. - -Signed-off-by: Torge Matthies -Signed-off-by: Alexandre Julliard ---- - dlls/powrprof/powrprof.c | 7 +++++++ - dlls/powrprof/powrprof.spec | 1 + - include/powrprof.h | 1 + - 3 files changed, 9 insertions(+) - -diff --git a/dlls/powrprof/powrprof.c b/dlls/powrprof/powrprof.c -index dc6e8bdaa15..3a5b93fed3c 100644 ---- a/dlls/powrprof/powrprof.c -+++ b/dlls/powrprof/powrprof.c -@@ -343,6 +343,13 @@ DWORD WINAPI PowerUnregisterSuspendResumeNotification(HPOWERNOTIFY handle) - return ERROR_SUCCESS; - } - -+DWORD WINAPI PowerSettingRegisterNotification(const GUID *setting, DWORD flags, HANDLE recipient, PHPOWERNOTIFY handle) -+{ -+ FIXME("(%s,0x%08x,%p,%p) stub!\n", debugstr_guid(setting), flags, recipient, handle); -+ *handle = (PHPOWERNOTIFY)0xdeadbeef; -+ return ERROR_SUCCESS; -+} -+ - BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) - { - switch(fdwReason) { -diff --git a/dlls/powrprof/powrprof.spec b/dlls/powrprof/powrprof.spec -index cbd2e47c1f2..3524be251a6 100644 ---- a/dlls/powrprof/powrprof.spec -+++ b/dlls/powrprof/powrprof.spec -@@ -19,6 +19,7 @@ - @ stdcall PowerReadFriendlyName (ptr ptr ptr ptr ptr ptr) - @ stdcall PowerRegisterSuspendResumeNotification(long ptr ptr) - @ stdcall PowerUnregisterSuspendResumeNotification(ptr) -+@ stdcall PowerSettingRegisterNotification(ptr long ptr ptr) - @ stdcall ReadGlobalPwrPolicy (ptr) - @ stdcall ReadProcessorPwrScheme (long ptr) - @ stdcall ReadPwrScheme (long ptr) -diff --git a/include/powrprof.h b/include/powrprof.h -index 6959a9aeb13..51fa158f239 100644 ---- a/include/powrprof.h -+++ b/include/powrprof.h -@@ -162,6 +162,7 @@ BOOLEAN WINAPI IsPwrSuspendAllowed(VOID); - DWORD WINAPI PowerEnumerate(HKEY, const GUID *, const GUID *, POWER_DATA_ACCESSOR, ULONG, UCHAR *, DWORD *); - DWORD WINAPI PowerRegisterSuspendResumeNotification(DWORD, HANDLE, PHPOWERNOTIFY); - DWORD WINAPI PowerUnregisterSuspendResumeNotification(HPOWERNOTIFY); -+DWORD WINAPI PowerSettingRegisterNotification(const GUID *, DWORD, HANDLE, PHPOWERNOTIFY); - BOOLEAN WINAPI ReadGlobalPwrPolicy(PGLOBAL_POWER_POLICY); - BOOLEAN WINAPI ReadProcessorPwrScheme(UINT, PMACHINE_PROCESSOR_POWER_POLICY); - BOOLEAN WINAPI ReadPwrScheme(UINT, PPOWER_POLICY); -From ce6365551b663472d9ad3bfd40c2b5fdfbefa84c Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Sun, 27 Feb 2022 02:02:35 +0100 -Subject: [PATCH] powrprof: Add PowerSettingUnregisterNotification stub. - -Signed-off-by: Torge Matthies -Signed-off-by: Alexandre Julliard ---- - dlls/powrprof/powrprof.c | 6 ++++++ - dlls/powrprof/powrprof.spec | 1 + - include/powrprof.h | 1 + - 3 files changed, 8 insertions(+) - -diff --git a/dlls/powrprof/powrprof.c b/dlls/powrprof/powrprof.c -index 3a5b93fed3c..ac1fa34bc05 100644 ---- a/dlls/powrprof/powrprof.c -+++ b/dlls/powrprof/powrprof.c -@@ -350,6 +350,12 @@ DWORD WINAPI PowerSettingRegisterNotification(const GUID *setting, DWORD flags, - return ERROR_SUCCESS; - } - -+DWORD WINAPI PowerSettingUnregisterNotification(HPOWERNOTIFY handle) -+{ -+ FIXME("(%p) stub!\n", handle); -+ return ERROR_SUCCESS; -+} -+ - BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) - { - switch(fdwReason) { -diff --git a/dlls/powrprof/powrprof.spec b/dlls/powrprof/powrprof.spec -index 3524be251a6..7a65fd37fc2 100644 ---- a/dlls/powrprof/powrprof.spec -+++ b/dlls/powrprof/powrprof.spec -@@ -20,6 +20,7 @@ - @ stdcall PowerRegisterSuspendResumeNotification(long ptr ptr) - @ stdcall PowerUnregisterSuspendResumeNotification(ptr) - @ stdcall PowerSettingRegisterNotification(ptr long ptr ptr) -+@ stdcall PowerSettingUnregisterNotification(ptr) - @ stdcall ReadGlobalPwrPolicy (ptr) - @ stdcall ReadProcessorPwrScheme (long ptr) - @ stdcall ReadPwrScheme (long ptr) -diff --git a/include/powrprof.h b/include/powrprof.h -index 51fa158f239..4c6cee41d16 100644 ---- a/include/powrprof.h -+++ b/include/powrprof.h -@@ -163,6 +163,7 @@ DWORD WINAPI PowerEnumerate(HKEY, const GUID *, const GUID *, POWER_DATA_ACCES - DWORD WINAPI PowerRegisterSuspendResumeNotification(DWORD, HANDLE, PHPOWERNOTIFY); - DWORD WINAPI PowerUnregisterSuspendResumeNotification(HPOWERNOTIFY); - DWORD WINAPI PowerSettingRegisterNotification(const GUID *, DWORD, HANDLE, PHPOWERNOTIFY); -+DWORD WINAPI PowerSettingUnregisterNotification(HPOWERNOTIFY); - BOOLEAN WINAPI ReadGlobalPwrPolicy(PGLOBAL_POWER_POLICY); - BOOLEAN WINAPI ReadProcessorPwrScheme(UINT, PMACHINE_PROCESSOR_POWER_POLICY); - BOOLEAN WINAPI ReadPwrScheme(UINT, PPOWER_POLICY); - diff --git a/patches/game-patches/castlevania-advance-collection.patch b/patches/game-patches/castlevania-advance-collection.patch deleted file mode 100644 index 9a2e03bf7..000000000 --- a/patches/game-patches/castlevania-advance-collection.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 7e47e32bab9..91d008475e1 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -3160,6 +3160,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer - { - if (!*ptr) return STATUS_OBJECT_NAME_INVALID; - if (is_unix) continue; -+ if (*ptr == '?') continue; // some games put a ? in filenames on failure of un-implemented features, ignore this - if (*ptr < 32 || wcschr( invalid_charsW, *ptr )) return STATUS_OBJECT_NAME_INVALID; - } - } diff --git a/patches/game-patches/ffxiv-launcher-fix.patch b/patches/game-patches/ffxiv-launcher-fix.patch deleted file mode 100644 index a166bf375..000000000 --- a/patches/game-patches/ffxiv-launcher-fix.patch +++ /dev/null @@ -1,37 +0,0 @@ -From ca5d9fa411ed3f06867ba823a02a8dbcd94638f9 Mon Sep 17 00:00:00 2001 -From: Jacek Caban -Date: Mon, 18 Feb 2019 18:00:06 +0100 -Subject: [PATCH] mshtml HACK: Use super_navigate for javascript: navigation. - -For old-style FFXIV launcher crash. - -CW-Bug-Id: #19624 ---- - dlls/mshtml/navigate.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c -index 233f58c89fd..dc12b0160fc 100644 ---- a/dlls/mshtml/navigate.c -+++ b/dlls/mshtml/navigate.c -@@ -2397,6 +2397,7 @@ static HRESULT navigate_uri(HTMLOuterWindow *window, IUri *uri, const WCHAR *dis - DWORD post_data_len = request_data ? request_data->post_data_len : 0; - void *post_data = post_data_len ? request_data->post_data : NULL; - const WCHAR *headers = request_data ? request_data->headers : NULL; -+ DWORD scheme; - - if(!(flags & BINDING_REFRESH)) { - BSTR frame_name = NULL; -@@ -2419,6 +2420,12 @@ static HRESULT navigate_uri(HTMLOuterWindow *window, IUri *uri, const WCHAR *dis - - if(is_main_content_window(window)) - return super_navigate(window, uri, flags, headers, post_data, post_data_len); -+ -+ hres = IUri_GetScheme(uri, &scheme); -+ if(SUCCEEDED(hres) && scheme == URL_SCHEME_JAVASCRIPT) { -+ FIXME("HACK Using super_navigate for javascript: navigation\n"); -+ return super_navigate(window, uri, flags, headers, post_data, post_data_len); -+ } - } - - if(is_main_content_window(window)) { diff --git a/patches/game-patches/halo-infinite-twinapi.appcore.dll.patch b/patches/game-patches/halo-infinite-twinapi.appcore.dll.patch deleted file mode 100644 index 8db849ed8..000000000 --- a/patches/game-patches/halo-infinite-twinapi.appcore.dll.patch +++ /dev/null @@ -1,634 +0,0 @@ -From 1d0ba2bd205ecff473b253135147719046c692ca Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 2 Nov 2021 18:20:25 -0700 -Subject: [PATCH] xinputuap.dll: Add DLL. - -Based on a patch by Yusuf Khan . - -CW-Bug-Id: #19649 - -For Halo Infinite. ---- - configure.ac | 1 + - dlls/xinputuap/Makefile.in | 8 ++++++++ - dlls/xinputuap/version.rc | 27 +++++++++++++++++++++++++++ - dlls/xinputuap/xinputuap.spec | 8 ++++++++ - 4 files changed, 44 insertions(+) - create mode 100644 dlls/xinputuap/Makefile.in - create mode 100644 dlls/xinputuap/version.rc - create mode 100644 dlls/xinputuap/xinputuap.spec - -diff --git a/configure.ac b/configure.ac -index ea5f35d6a7d..43a9e7946b1 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3524,6 +3524,7 @@ WINE_CONFIG_MAKEFILE(dlls/xinput1_3) - WINE_CONFIG_MAKEFILE(dlls/xinput1_3/tests) - WINE_CONFIG_MAKEFILE(dlls/xinput1_4) - WINE_CONFIG_MAKEFILE(dlls/xinput9_1_0) -+WINE_CONFIG_MAKEFILE(dlls/xinputuap) - WINE_CONFIG_MAKEFILE(dlls/xmllite) - WINE_CONFIG_MAKEFILE(dlls/xmllite/tests) - WINE_CONFIG_MAKEFILE(dlls/xolehlp) -diff --git a/dlls/xinputuap/Makefile.in b/dlls/xinputuap/Makefile.in -new file mode 100644 -index 00000000000..5d311fe7c31 ---- /dev/null -+++ b/dlls/xinputuap/Makefile.in -@@ -0,0 +1,8 @@ -+MODULE = xinputuap.dll -+IMPORTS = hid setupapi advapi32 user32 -+PARENTSRC = ../xinput1_3 -+ -+C_SRCS = \ -+ main.c -+ -+RC_SRCS = version.rc -diff --git a/dlls/xinputuap/version.rc b/dlls/xinputuap/version.rc -new file mode 100644 -index 00000000000..f16ae7b6880 ---- /dev/null -+++ b/dlls/xinputuap/version.rc -@@ -0,0 +1,27 @@ -+/* -+ * The Wine project - Xinput Joystick Library -+ * Copyright 2021 Yusuf Khan -+ * -+ * 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 WINE_FILEDESCRIPTION_STR "Wine Common Controller API" -+#define WINE_FILENAME_STR "xinputuap.dll" -+#define WINE_FILEVERSION 10,0,14393,0000 -+#define WINE_FILEVERSION_STR "10.0.14393.0000" -+#define WINE_PRODUCTVERSION 10,0,14393,0000 -+#define WINE_PRODUCTVERSION_STR "10.0" -+ -+#include "wine/wine_common_ver.rc" -diff --git a/dlls/xinputuap/xinputuap.spec b/dlls/xinputuap/xinputuap.spec -new file mode 100644 -index 00000000000..6ecf5415b91 ---- /dev/null -+++ b/dlls/xinputuap/xinputuap.spec -@@ -0,0 +1,8 @@ -+1 stdcall -private DllMain(long long ptr) -+2 stdcall XInputGetState(long ptr) -+3 stdcall XInputSetState(long ptr) -+4 stdcall XInputGetCapabilities(long long ptr) -+5 stdcall XInputEnable(long) -+7 stdcall XInputGetBatteryInformation(long long ptr) -+8 stdcall XInputGetKeystroke(long long ptr) -+100 stdcall XInputGetStateEx(long ptr) -From df886d4729dbcd691bf425ed1929d43f9f897b0e Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 17 Nov 2021 19:34:29 +0300 -Subject: [PATCH] twinapi.appcore.dll: Stub DLL. - -CW-Bug-Id: #19649 ---- - configure.ac | 1 + - dlls/twinapi.appcore.dll/Makefile.in | 5 + - dlls/twinapi.appcore.dll/main.c | 157 ++++++++++++++++++ - dlls/twinapi.appcore.dll/twinapi.appcore.spec | 3 + - 4 files changed, 166 insertions(+) - create mode 100644 dlls/twinapi.appcore.dll/Makefile.in - create mode 100644 dlls/twinapi.appcore.dll/main.c - create mode 100644 dlls/twinapi.appcore.dll/twinapi.appcore.spec - -diff --git a/configure.ac b/configure.ac -index 43a9e7946b1..9122a72353e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3318,6 +3318,7 @@ WINE_CONFIG_MAKEFILE(dlls/twain.dll16,enable_win16) - WINE_CONFIG_MAKEFILE(dlls/twain_32) - WINE_CONFIG_MAKEFILE(dlls/twain_32/tests) - WINE_CONFIG_MAKEFILE(dlls/typelib.dll16,enable_win16) -+WINE_CONFIG_MAKEFILE(dlls/twinapi.appcore.dll) - WINE_CONFIG_MAKEFILE(dlls/tzres) - WINE_CONFIG_MAKEFILE(dlls/ucrtbase) - WINE_CONFIG_MAKEFILE(dlls/ucrtbase/tests) -diff --git a/dlls/twinapi.appcore.dll/Makefile.in b/dlls/twinapi.appcore.dll/Makefile.in -new file mode 100644 -index 00000000000..b96bd5ff03e ---- /dev/null -+++ b/dlls/twinapi.appcore.dll/Makefile.in -@@ -0,0 +1,5 @@ -+MODULE = twinapi.appcore.dll -+IMPORTS = combase -+ -+C_SRCS = \ -+ main.c -diff --git a/dlls/twinapi.appcore.dll/main.c b/dlls/twinapi.appcore.dll/main.c -new file mode 100644 -index 00000000000..9de8b65f945 ---- /dev/null -+++ b/dlls/twinapi.appcore.dll/main.c -@@ -0,0 +1,157 @@ -+/* -+ * Copyright 2021 Paul Gofman 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 -+ -+#define COBJMACROS -+#include "initguid.h" -+#include "windef.h" -+#include "winbase.h" -+#include "winstring.h" -+#include "wine/debug.h" -+#include "objbase.h" -+ -+#include "activation.h" -+ -+#include "windows.foundation.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(twinapi); -+ -+static const char *debugstr_hstring(HSTRING hstr) -+{ -+ const WCHAR *str; -+ UINT32 len; -+ if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; -+ str = WindowsGetStringRawBuffer(hstr, &len); -+ return wine_dbgstr_wn(str, len); -+} -+ -+struct twinapi_appcore -+{ -+ IActivationFactory IActivationFactory_iface; -+ LONG ref; -+}; -+ -+static inline struct twinapi_appcore *impl_from_IActivationFactory(IActivationFactory *iface) -+{ -+ return CONTAINING_RECORD(iface, struct twinapi_appcore, IActivationFactory_iface); -+} -+ -+static HRESULT STDMETHODCALLTYPE twinapi_appcore_QueryInterface( -+ IActivationFactory *iface, REFIID iid, void **out) -+{ -+ TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); -+ -+ if (IsEqualGUID(iid, &IID_IUnknown) || -+ IsEqualGUID(iid, &IID_IInspectable) || -+ IsEqualGUID(iid, &IID_IAgileObject) || -+ IsEqualGUID(iid, &IID_IActivationFactory)) -+ { -+ IUnknown_AddRef(iface); -+ *out = iface; -+ return S_OK; -+ } -+ -+ FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); -+ *out = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG STDMETHODCALLTYPE twinapi_appcore_AddRef( -+ IActivationFactory *iface) -+{ -+ struct twinapi_appcore *impl = impl_from_IActivationFactory(iface); -+ ULONG ref = InterlockedIncrement(&impl->ref); -+ TRACE("iface %p, ref %u.\n", iface, ref); -+ return ref; -+} -+ -+static ULONG STDMETHODCALLTYPE twinapi_appcore_Release( -+ IActivationFactory *iface) -+{ -+ struct twinapi_appcore *impl = impl_from_IActivationFactory(iface); -+ ULONG ref = InterlockedDecrement(&impl->ref); -+ TRACE("iface %p, ref %u.\n", iface, ref); -+ return ref; -+} -+ -+static HRESULT STDMETHODCALLTYPE twinapi_appcore_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 STDMETHODCALLTYPE twinapi_appcore_GetRuntimeClassName( -+ IActivationFactory *iface, HSTRING *class_name) -+{ -+ FIXME("iface %p, class_name %p stub!\n", iface, class_name); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE twinapi_appcore_GetTrustLevel( -+ IActivationFactory *iface, TrustLevel *trust_level) -+{ -+ FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE twinapi_appcore_ActivateInstance( -+ IActivationFactory *iface, IInspectable **instance) -+{ -+ FIXME("iface %p, instance %p stub!\n", iface, instance); -+ return E_NOTIMPL; -+} -+ -+static const struct IActivationFactoryVtbl activation_factory_vtbl = -+{ -+ twinapi_appcore_QueryInterface, -+ twinapi_appcore_AddRef, -+ twinapi_appcore_Release, -+ /* IInspectable methods */ -+ twinapi_appcore_GetIids, -+ twinapi_appcore_GetRuntimeClassName, -+ twinapi_appcore_GetTrustLevel, -+ /* IActivationFactory methods */ -+ twinapi_appcore_ActivateInstance, -+}; -+ -+static struct twinapi_appcore twinapi_appcore = -+{ -+ {&activation_factory_vtbl}, -+ 1 -+}; -+ -+HRESULT WINAPI DllCanUnloadNow(void) -+{ -+ return S_FALSE; -+} -+ -+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) -+{ -+ TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory); -+ *factory = &twinapi_appcore.IActivationFactory_iface; -+ IUnknown_AddRef(*factory); -+ return S_OK; -+} -diff --git a/dlls/twinapi.appcore.dll/twinapi.appcore.spec b/dlls/twinapi.appcore.dll/twinapi.appcore.spec -new file mode 100644 -index 00000000000..721493229c2 ---- /dev/null -+++ b/dlls/twinapi.appcore.dll/twinapi.appcore.spec -@@ -0,0 +1,3 @@ -+1 stdcall -private DllCanUnloadNow() -+2 stdcall -private DllGetActivationFactory(ptr ptr) -+3 stdcall -private DllGetClassObject(ptr ptr ptr) -From f7483da74b31cb8fb43cfdb7b7aab7b9c5fe92af Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 17 Nov 2021 22:34:20 +0300 -Subject: [PATCH] twinapi.appcore.dll: Stub implement - IEasClientDeviceInformation. - -CW-Bug-Id: #19649 ---- - dlls/twinapi.appcore.dll/Makefile.in | 2 + - dlls/twinapi.appcore.dll/classes.idl | 23 +++ - dlls/twinapi.appcore.dll/main.c | 142 +++++++++++++++++- - include/Makefile.in | 1 + - ...ecurity.exchangeactivesyncprovisioning.idl | 61 ++++++++ - 5 files changed, 227 insertions(+), 2 deletions(-) - create mode 100644 dlls/twinapi.appcore.dll/classes.idl - create mode 100644 include/windows.security.exchangeactivesyncprovisioning.idl - -diff --git a/dlls/twinapi.appcore.dll/Makefile.in b/dlls/twinapi.appcore.dll/Makefile.in -index b96bd5ff03e..f7acd8eae2c 100644 ---- a/dlls/twinapi.appcore.dll/Makefile.in -+++ b/dlls/twinapi.appcore.dll/Makefile.in -@@ -3,3 +3,5 @@ IMPORTS = combase - - C_SRCS = \ - main.c -+ -+IDL_SRCS = classes.idl -diff --git a/dlls/twinapi.appcore.dll/classes.idl b/dlls/twinapi.appcore.dll/classes.idl -new file mode 100644 -index 00000000000..56ea8096642 ---- /dev/null -+++ b/dlls/twinapi.appcore.dll/classes.idl -@@ -0,0 +1,23 @@ -+/* -+ * Runtime Classes for windows.media.devices.dll -+ * -+ * Copyright 2021 Paul Gofman 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 register -+ -+#include "windows.security.exchangeactivesyncprovisioning.idl" -diff --git a/dlls/twinapi.appcore.dll/main.c b/dlls/twinapi.appcore.dll/main.c -index 9de8b65f945..3842e36153c 100644 ---- a/dlls/twinapi.appcore.dll/main.c -+++ b/dlls/twinapi.appcore.dll/main.c -@@ -28,7 +28,11 @@ - - #include "activation.h" - -+#define WIDL_using_Windows_Foundation -+#define WIDL_using_Windows_Foundation_Collections - #include "windows.foundation.h" -+#define WIDL_using_Windows_Security_ExchangeActiveSyncProvisioning -+#include "windows.security.exchangeactivesyncprovisioning.h" - - WINE_DEFAULT_DEBUG_CHANNEL(twinapi); - -@@ -44,9 +48,15 @@ static const char *debugstr_hstring(HSTRING hstr) - struct twinapi_appcore - { - IActivationFactory IActivationFactory_iface; -+ IEasClientDeviceInformation IEasClientDeviceInformation_iface; - LONG ref; - }; - -+static inline struct twinapi_appcore *impl_from_IEasClientDeviceInformation(IEasClientDeviceInformation *iface) -+{ -+ return CONTAINING_RECORD(iface, struct twinapi_appcore, IEasClientDeviceInformation_iface); -+} -+ - static inline struct twinapi_appcore *impl_from_IActivationFactory(IActivationFactory *iface) - { - return CONTAINING_RECORD(iface, struct twinapi_appcore, IActivationFactory_iface); -@@ -55,6 +65,8 @@ static inline struct twinapi_appcore *impl_from_IActivationFactory(IActivationFa - static HRESULT STDMETHODCALLTYPE twinapi_appcore_QueryInterface( - IActivationFactory *iface, REFIID iid, void **out) - { -+ struct twinapi_appcore *impl = impl_from_IActivationFactory(iface); -+ - TRACE("iface %p, iid %s, out %p stub!\n", iface, debugstr_guid(iid), out); - - if (IsEqualGUID(iid, &IID_IUnknown) || -@@ -67,6 +79,13 @@ static HRESULT STDMETHODCALLTYPE twinapi_appcore_QueryInterface( - return S_OK; - } - -+ if (IsEqualGUID(iid, &IID_IEasClientDeviceInformation)) -+ { -+ IUnknown_AddRef(iface); -+ *out = &impl->IEasClientDeviceInformation_iface; -+ return S_OK; -+ } -+ - FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - *out = NULL; - return E_NOINTERFACE; -@@ -114,8 +133,12 @@ static HRESULT STDMETHODCALLTYPE twinapi_appcore_GetTrustLevel( - static HRESULT STDMETHODCALLTYPE twinapi_appcore_ActivateInstance( - IActivationFactory *iface, IInspectable **instance) - { -- FIXME("iface %p, instance %p stub!\n", iface, instance); -- return E_NOTIMPL; -+ FIXME("iface %p, instance %p semi-stub!\n", iface, instance); -+ -+ IActivationFactory_AddRef(iface); -+ *instance = (IInspectable *)iface; -+ -+ return S_OK; - } - - static const struct IActivationFactoryVtbl activation_factory_vtbl = -@@ -131,9 +154,124 @@ static const struct IActivationFactoryVtbl activation_factory_vtbl = - twinapi_appcore_ActivateInstance, - }; - -+static HRESULT WINAPI eas_client_devinfo_QueryInterface(IEasClientDeviceInformation *iface, -+ REFIID riid, void **ppvObject) -+{ -+ struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); -+ return twinapi_appcore_QueryInterface(&This->IActivationFactory_iface, riid, ppvObject); -+} -+ -+static ULONG WINAPI eas_client_devinfo_AddRef(IEasClientDeviceInformation *iface) -+{ -+ struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); -+ return twinapi_appcore_AddRef(&This->IActivationFactory_iface); -+} -+ -+static ULONG WINAPI eas_client_devinfo_Release(IEasClientDeviceInformation *iface) -+{ -+ struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); -+ return twinapi_appcore_Release(&This->IActivationFactory_iface); -+} -+ -+static HRESULT WINAPI eas_client_devinfo_GetIids(IEasClientDeviceInformation *iface, -+ ULONG *iidCount, IID **iids) -+{ -+ struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); -+ return twinapi_appcore_GetIids(&This->IActivationFactory_iface, iidCount, iids); -+} -+ -+static HRESULT WINAPI eas_client_devinfo_GetRuntimeClassName(IEasClientDeviceInformation *iface, -+ HSTRING *className) -+{ -+ struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); -+ return twinapi_appcore_GetRuntimeClassName(&This->IActivationFactory_iface, className); -+} -+ -+static HRESULT WINAPI eas_client_devinfo_GetTrustLevel(IEasClientDeviceInformation *iface, -+ TrustLevel *trustLevel) -+{ -+ struct twinapi_appcore *This = impl_from_IEasClientDeviceInformation(iface); -+ return twinapi_appcore_GetTrustLevel(&This->IActivationFactory_iface, trustLevel); -+} -+ -+static HRESULT WINAPI eas_client_devinfo_get_Id(IEasClientDeviceInformation *iface, GUID* value) -+{ -+ FIXME("iface %p, value %p stub.\n", iface, value); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI eas_client_devinfo_get_OperatingSystem(IEasClientDeviceInformation *iface, -+ HSTRING* value) -+{ -+ FIXME("iface %p, value %p stub.\n", iface, value); -+ -+ WindowsCreateString(NULL, 0, value); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI eas_client_devinfo_get_FriendlyName(IEasClientDeviceInformation *iface, -+ HSTRING* value) -+{ -+ FIXME("iface %p, value %p stub.\n", iface, value); -+ -+ WindowsCreateString(NULL, 0, value); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI eas_client_devinfo_get_SystemManufacturer(IEasClientDeviceInformation *iface, -+ HSTRING* value) -+{ -+ FIXME("iface %p, value %p stub.\n", iface, value); -+ -+ WindowsCreateString(NULL, 0, value); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI eas_client_devinfo_get_SystemProductName(IEasClientDeviceInformation *iface, -+ HSTRING* value) -+{ -+ FIXME("iface %p, value %p stub.\n", iface, value); -+ -+ WindowsCreateString(NULL, 0, value); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI eas_client_devinfo_get_SystemSku(IEasClientDeviceInformation *iface, -+ HSTRING* value) -+{ -+ FIXME("iface %p, value %p stub.\n", iface, value); -+ -+ WindowsCreateString(NULL, 0, value); -+ -+ return E_NOTIMPL; -+} -+ -+static IEasClientDeviceInformationVtbl eas_client_devinfo_vtbl = { -+ eas_client_devinfo_QueryInterface, -+ eas_client_devinfo_AddRef, -+ eas_client_devinfo_Release, -+ /* IInspectable methods */ -+ eas_client_devinfo_GetIids, -+ eas_client_devinfo_GetRuntimeClassName, -+ eas_client_devinfo_GetTrustLevel, -+ /* IEasClientDeviceInformation methods */ -+ eas_client_devinfo_get_Id, -+ eas_client_devinfo_get_OperatingSystem, -+ eas_client_devinfo_get_FriendlyName, -+ eas_client_devinfo_get_SystemManufacturer, -+ eas_client_devinfo_get_SystemProductName, -+ eas_client_devinfo_get_SystemSku, -+}; -+ - static struct twinapi_appcore twinapi_appcore = - { - {&activation_factory_vtbl}, -+ {&eas_client_devinfo_vtbl}, - 1 - }; - -diff --git a/include/Makefile.in b/include/Makefile.in -index b1087f2ec9d..db0625eaf3b 100644 ---- a/include/Makefile.in -+++ b/include/Makefile.in -@@ -758,6 +758,7 @@ SOURCES = \ - windows.networking.idl \ - windows.networking.connectivity.idl \ - windows.storage.streams.idl \ -+ windows.security.exchangeactivesyncprovisioning.idl \ - windows.system.idl \ - windows.system.userprofile.idl \ - windowscontracts.idl \ -diff --git a/include/windows.security.exchangeactivesyncprovisioning.idl b/include/windows.security.exchangeactivesyncprovisioning.idl -new file mode 100644 -index 00000000000..1b2a743b057 ---- /dev/null -+++ b/include/windows.security.exchangeactivesyncprovisioning.idl -@@ -0,0 +1,61 @@ -+/* -+ * Copyright 2021 Paul Gofman 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 -+ */ -+ -+#ifdef __WIDL__ -+#pragma winrt ns_prefix -+#endif -+ -+import "inspectable.idl"; -+import "eventtoken.idl"; -+import "windows.foundation.idl"; -+ -+namespace Windows { -+ namespace Security { -+ namespace ExchangeActiveSyncProvisioning { -+ interface IEasClientDeviceInformation; -+ runtimeclass EasClientDeviceInformation; -+ } -+ } -+} -+ -+namespace Windows { -+ namespace Security { -+ namespace ExchangeActiveSyncProvisioning { -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Security.ExchangeActiveSyncProvisioning.EasClientDeviceInformation)] -+ [uuid(54DFD981-1968-4CA3-B958-E595D16505EB)] -+ interface IEasClientDeviceInformation : IInspectable -+ { -+ [propget] HRESULT Id([out] [retval] GUID* value); -+ [propget] HRESULT OperatingSystem([out] [retval] HSTRING* value); -+ [propget] HRESULT FriendlyName([out] [retval] HSTRING* value); -+ [propget] HRESULT SystemManufacturer([out] [retval] HSTRING* value); -+ [propget] HRESULT SystemProductName([out] [retval] HSTRING* value); -+ [propget] HRESULT SystemSku([out] [retval] HSTRING* value); -+ } -+ -+ [activatable(Windows.Foundation.UniversalApiContract, 1.0)] -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [threading(both)] -+ runtimeclass EasClientDeviceInformation -+ { -+ [default] interface Windows.Security.ExchangeActiveSyncProvisioning.IEasClientDeviceInformation; -+ } -+ } -+ } -+} diff --git a/patches/game-patches/origin-downloads_fix.patch b/patches/game-patches/origin-downloads_fix.patch deleted file mode 100755 index 5e74047ff..000000000 --- a/patches/game-patches/origin-downloads_fix.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- b/server/named_pipe.c -+++ a/server/named_pipe.c -@@ -1162,7 +1162,7 @@ - server->pipe_end.server_pid = get_process_id( current->process ); - init_async_queue( &server->listen_q ); - -+ list_add_head( &pipe->listeners, &server->entry ); -- list_add_tail( &pipe->listeners, &server->entry ); - if (!(server->pipe_end.fd = alloc_pseudo_fd( &pipe_server_fd_ops, &server->pipe_end.obj, options ))) - { - release_object( server ); diff --git a/patches/game-patches/sword-art-online-gnutls.patch b/patches/game-patches/sword-art-online-gnutls.patch deleted file mode 100755 index 28a75571e..000000000 --- a/patches/game-patches/sword-art-online-gnutls.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 4c6d12640c75999cbd745456e983fc344d0296cf Mon Sep 17 00:00:00 2001 -From: Jacek Caban -Date: Wed, 6 Mar 2019 09:29:45 -0600 -Subject: [PATCH] HACK secur32: Disable ECDHE-ECDSA ciphers on pre-TLS 1.3 - gnutls versions. - -For Sword Art Online: Fatal Bullet, and others, on gnutls 3.5. ---- - dlls/secur32/schannel_gnutls.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c -index cb90d1c40d7..cbf8104a984 100644 ---- a/dlls/secur32/schannel_gnutls.c -+++ b/dlls/secur32/schannel_gnutls.c -@@ -160,6 +160,7 @@ static const struct { - }; - - static DWORD supported_protocols; -+static char priority_quirks[128]; - - static void check_supported_protocols(void) - { -@@ -188,6 +189,17 @@ static void check_supported_protocols(void) - TRACE("%s is not supported\n", protocol_priority_flags[i].gnutls_flag); - } - -+ /* ECDHE-ECDSA cause problems with gnutls 3.5 and Sword Art Online: Fatal Bullet */ -+ /*if (!(supported_protocols & SP_PROT_TLS1_3_CLIENT)) previously restricted to older gnutls, but newer is affected, too */ -+ { -+ err = pgnutls_priority_set_direct(session, "NORMAL:-ECDHE-ECDSA", NULL); -+ if (err == GNUTLS_E_SUCCESS) -+ { -+ TRACE("disabling ECDHE-ECDSA\n"); -+ strcat(priority_quirks, ":-ECDHE-ECDSA"); -+ } -+ } -+ - pgnutls_deinit(session); - } - -@@ -235,6 +247,8 @@ BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cre - p += strlen(p); - } - -+ strcat(priority, priority_quirks); -+ - TRACE("Using %s priority\n", debugstr_a(priority)); - err = pgnutls_priority_set_direct(*s, priority, NULL); - if (err != GNUTLS_E_SUCCESS) - diff --git a/patches/proton/01-proton-use_clock_monotonic.patch b/patches/proton/01-proton-use_clock_monotonic.patch deleted file mode 100755 index 8ad90503d..000000000 --- a/patches/proton/01-proton-use_clock_monotonic.patch +++ /dev/null @@ -1,187 +0,0 @@ -From 557a113da7f85d62bb3c98b6860e6707fb014c5e Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 28 Aug 2018 12:57:32 -0500 -Subject: [PATCH] ntdll,server: Never use CLOCK_MONOTONIC_RAW - -Using CLOCK_MONOTONIC avoids a kernel call. ---- - dlls/ntdll/unix/sync.c | 2 +- - server/request.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index f15d35c4d4b..e040885f800 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -97,7 +97,7 @@ static inline ULONGLONG monotonic_counter(void) - return mach_absolute_time() * timebase.numer / timebase.denom / 100; - #elif defined(HAVE_CLOCK_GETTIME) - struct timespec ts; --#ifdef CLOCK_MONOTONIC_RAW -+#if 0 - if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) - return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; - #endif -diff --git a/server/request.c b/server/request.c -index c5fd378742a..f8aa63b03d1 100644 ---- a/server/request.c -+++ b/server/request.c -@@ -538,7 +538,7 @@ timeout_t monotonic_counter(void) - return mach_absolute_time() * timebase.numer / timebase.denom / 100; - #elif defined(HAVE_CLOCK_GETTIME) - struct timespec ts; --#ifdef CLOCK_MONOTONIC_RAW -+#if 0 - if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) - return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; - #endif -From 1777861cae08f9915c1b8ea2535ada6e3aa911db Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Wed, 20 Jan 2021 11:28:46 -0600 -Subject: [PATCH] ntdll: Use clock_gettime64 if supported. - ---- - dlls/ntdll/unix/sync.c | 50 +++++++++++++++++++++++++++++++++++++----- - server/request.c | 50 +++++++++++++++++++++++++++++++++++++----- - 2 files changed, 90 insertions(+), 10 deletions(-) - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 5d70ef577ad..f665f91342d 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -82,6 +82,46 @@ static const LARGE_INTEGER zero_timeout; - return wine_dbgstr_longlong( timeout->QuadPart ); - } - -+#ifndef __NR_clock_gettime64 -+#define __NR_clock_gettime64 403 -+#endif -+ -+struct timespec64 -+{ -+ long long tv_sec; -+ long long tv_nsec; -+}; -+ -+static inline int do_clock_gettime( clockid_t clock_id, ULONGLONG *ticks ) -+{ -+ static int clock_gettime64_supported = -1; -+ struct timespec64 ts64; -+ struct timespec ts; -+ int ret; -+ -+ if (clock_gettime64_supported < 0) -+ { -+ if (!syscall( __NR_clock_gettime64, clock_id, &ts64 )) -+ { -+ clock_gettime64_supported = 1; -+ *ticks = ts64.tv_sec * (ULONGLONG)TICKSPERSEC + ts64.tv_nsec / 100; -+ return 0; -+ } -+ clock_gettime64_supported = 0; -+ } -+ -+ if (clock_gettime64_supported) -+ { -+ if (!(ret = syscall( __NR_clock_gettime64, clock_id, &ts64 ))) -+ *ticks = ts64.tv_sec * (ULONGLONG)TICKSPERSEC + ts64.tv_nsec / 100; -+ return ret; -+ } -+ -+ if (!(ret = clock_gettime( clock_id, &ts ))) -+ *ticks = ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; -+ return ret; -+} -+ - /* return a monotonic time counter, in Win32 ticks */ - static inline ULONGLONG monotonic_counter(void) - { -@@ -96,13 +136,13 @@ static inline ULONGLONG monotonic_counter(void) - #endif - return mach_absolute_time() * timebase.numer / timebase.denom / 100; - #elif defined(HAVE_CLOCK_GETTIME) -- struct timespec ts; -+ ULONGLONG ticks; - #if 0 -- if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) -- return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; -+ if (!do_clock_gettime( CLOCK_MONOTONIC_RAW, &ticks )) -+ return ticks; - #endif -- if (!clock_gettime( CLOCK_MONOTONIC, &ts )) -- return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; -+ if (!do_clock_gettime( CLOCK_MONOTONIC, &ticks )) -+ return ticks; - #endif - gettimeofday( &now, 0 ); - return now.tv_sec * (ULONGLONG)TICKSPERSEC + now.tv_usec * 10 + TICKS_1601_TO_1970 - server_start_time; -diff --git a/server/request.c b/server/request.c -index f8aa63b03d1..e0c30c906dc 100644 ---- a/server/request.c -+++ b/server/request.c -@@ -524,6 +524,46 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle ) - return -1; - } - -+#ifndef __NR_clock_gettime64 -+#define __NR_clock_gettime64 403 -+#endif -+ -+struct timespec64 -+{ -+ long long tv_sec; -+ long long tv_nsec; -+}; -+ -+static inline int do_clock_gettime( clockid_t clock_id, ULONGLONG *ticks ) -+{ -+ static int clock_gettime64_supported = -1; -+ struct timespec64 ts64; -+ struct timespec ts; -+ int ret; -+ -+ if (clock_gettime64_supported < 0) -+ { -+ if (!syscall( __NR_clock_gettime64, clock_id, &ts64 )) -+ { -+ clock_gettime64_supported = 1; -+ *ticks = ts64.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts64.tv_nsec / 100; -+ return 0; -+ } -+ clock_gettime64_supported = 0; -+ } -+ -+ if (clock_gettime64_supported) -+ { -+ if (!(ret = syscall( __NR_clock_gettime64, clock_id, &ts64 ))) -+ *ticks = ts64.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts64.tv_nsec / 100; -+ return ret; -+ } -+ -+ if (!(ret = clock_gettime( clock_id, &ts ))) -+ *ticks = ts.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts.tv_nsec / 100; -+ return ret; -+} -+ - /* return a monotonic time counter */ - timeout_t monotonic_counter(void) - { -@@ -537,13 +577,13 @@ timeout_t monotonic_counter(void) - #endif - return mach_absolute_time() * timebase.numer / timebase.denom / 100; - #elif defined(HAVE_CLOCK_GETTIME) -- struct timespec ts; -+ ULONGLONG ticks; - #if 0 -- if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) -- return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; -+ if (!do_clock_gettime( CLOCK_MONOTONIC_RAW, &ticks )) -+ return ticks; - #endif -- if (!clock_gettime( CLOCK_MONOTONIC, &ts )) -- return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; -+ if (!do_clock_gettime( CLOCK_MONOTONIC, &ticks )) -+ return ticks; - #endif - return current_time - server_start_time; - } diff --git a/patches/proton/03-proton-fsync_staging.patch b/patches/proton/03-proton-fsync_staging.patch deleted file mode 100755 index 5a14f0b8a..000000000 --- a/patches/proton/03-proton-fsync_staging.patch +++ /dev/null @@ -1,3928 +0,0 @@ -From 1d3dadfd7707ac176b67b50a0dc573f799778836 Mon Sep 17 00:00:00 2001 -From: Tk-Glitch -Date: Fri, 16 Oct 2020 20:53:31 +0200 -Subject: Fsync rebased 5.13+ staging - - -diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in -index c96a62ae006..a9be561d87a 100644 ---- a/dlls/ntdll/Makefile.in -+++ b/dlls/ntdll/Makefile.in -@@ -48,6 +48,7 @@ C_SRCS = \ - unix/env.c \ - unix/esync.c \ - unix/file.c \ -+ unix/fsync.c \ - unix/loader.c \ - unix/process.c \ - unix/registry.c \ -diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c -index ed801c71991..ac0326b1aba 100644 ---- a/dlls/ntdll/unix/esync.c -+++ b/dlls/ntdll/unix/esync.c -@@ -57,6 +57,7 @@ - - #include "unix_private.h" - #include "esync.h" -+#include "fsync.h" - - WINE_DEFAULT_DEBUG_CHANNEL(esync); - -@@ -66,7 +67,7 @@ int do_esync(void) - static int do_esync_cached = -1; - - if (do_esync_cached == -1) -- do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); -+ do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_fsync(); - - return do_esync_cached; - #else -@@ -867,7 +868,7 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA - return ret; - } - -- if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE) -+ if (count && objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE) - msgwait = TRUE; - - if (has_esync && has_server) -@@ -896,7 +897,7 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA - } - } - -- if (wait_any || count == 1) -+ if (wait_any || count <= 1) - { - /* Try to check objects now, so we can obviate poll() at least. */ - for (i = 0; i < count; i++) -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -new file mode 100644 -index 00000000000..5012425b95a ---- /dev/null -+++ b/dlls/ntdll/unix/fsync.c -@@ -0,0 +1,1267 @@ -+/* -+ * futex-based synchronization objects -+ * -+ * Copyright (C) 2018 Zebediah Figura -+ * -+ * 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 -+ */ -+ -+#if 0 -+#pragma makedep unix -+#endif -+ -+#include "config.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef HAVE_SYS_STAT_H -+# include -+#endif -+#ifdef HAVE_SYS_SYSCALL_H -+# include -+#endif -+#include -+ -+#include "ntstatus.h" -+#define WIN32_NO_STATUS -+#define NONAMELESSUNION -+#include "windef.h" -+#include "winternl.h" -+#include "wine/debug.h" -+#include "wine/server.h" -+ -+#include "unix_private.h" -+#include "fsync.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(fsync); -+ -+#include "pshpack4.h" -+struct futex_wait_block -+{ -+ int *addr; -+#if __SIZEOF_POINTER__ == 4 -+ int pad; -+#endif -+ int val; -+ int bitset; -+}; -+#include "poppack.h" -+ -+static inline void small_pause(void) -+{ -+#if defined(__i386__) || defined(__x86_64__) -+ __asm__ __volatile__( "rep;nop" : : : "memory" ); -+#else -+ __asm__ __volatile__( "" : : : "memory" ); -+#endif -+} -+ -+static inline int futex_wait_multiple( const struct futex_wait_block *futexes, -+ int count, const struct timespec *timeout ) -+{ -+ return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); -+} -+ -+static inline int futex_wake( int *addr, int val ) -+{ -+ return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); -+} -+ -+static inline int futex_wait( int *addr, int val, struct timespec *timeout ) -+{ -+ return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); -+} -+ -+static unsigned int spincount = 100; -+ -+int do_fsync(void) -+{ -+#ifdef __linux__ -+ static int do_fsync_cached = -1; -+ -+ if (do_fsync_cached == -1) -+ { -+ static const struct timespec zero; -+ futex_wait_multiple( NULL, 0, &zero ); -+ do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; -+ if (getenv("WINEFSYNC_SPINCOUNT")) -+ spincount = atoi(getenv("WINEFSYNC_SPINCOUNT")); -+ } -+ -+ return do_fsync_cached; -+#else -+ static int once; -+ if (!once++) -+ FIXME("futexes not supported on this platform.\n"); -+ return 0; -+#endif -+} -+ -+struct fsync -+{ -+ enum fsync_type type; -+ void *shm; /* pointer to shm section */ -+}; -+ -+struct semaphore -+{ -+ int count; -+ int max; -+}; -+C_ASSERT(sizeof(struct semaphore) == 8); -+ -+struct event -+{ -+ int signaled; -+ int unused; -+}; -+C_ASSERT(sizeof(struct event) == 8); -+ -+struct mutex -+{ -+ int tid; -+ int count; /* recursion count */ -+}; -+C_ASSERT(sizeof(struct mutex) == 8); -+ -+static char shm_name[29]; -+static int shm_fd; -+static void **shm_addrs; -+static int shm_addrs_size; /* length of the allocated shm_addrs array */ -+static long pagesize; -+ -+static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; -+ -+static void *get_shm( unsigned int idx ) -+{ -+ int entry = (idx * 8) / pagesize; -+ int offset = (idx * 8) % pagesize; -+ void *ret; -+ -+ pthread_mutex_lock( &shm_addrs_mutex ); -+ -+ if (entry >= shm_addrs_size) -+ { -+ int new_size = max(shm_addrs_size * 2, entry + 1); -+ -+ if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) -+ ERR("Failed to grow shm_addrs array to size %d.\n", shm_addrs_size); -+ memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); -+ shm_addrs_size = new_size; -+ } -+ -+ if (!shm_addrs[entry]) -+ { -+ void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); -+ if (addr == (void *)-1) -+ ERR("Failed to map page %d (offset %#lx).\n", entry, entry * pagesize); -+ -+ TRACE("Mapping page %d at %p.\n", entry, addr); -+ -+ if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) -+ munmap( addr, pagesize ); /* someone beat us to it */ -+ } -+ -+ ret = (void *)((unsigned long)shm_addrs[entry] + offset); -+ -+ pthread_mutex_unlock( &shm_addrs_mutex ); -+ -+ return ret; -+} -+ -+/* We'd like lookup to be fast. To that end, we use a static list indexed by handle. -+ * This is copied and adapted from the fd cache code. */ -+ -+#define FSYNC_LIST_BLOCK_SIZE (65536 / sizeof(struct fsync)) -+#define FSYNC_LIST_ENTRIES 256 -+ -+static struct fsync *fsync_list[FSYNC_LIST_ENTRIES]; -+static struct fsync fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; -+ -+static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) -+{ -+ UINT_PTR idx = (((UINT_PTR)handle) >> 2) - 1; -+ *entry = idx / FSYNC_LIST_BLOCK_SIZE; -+ return idx % FSYNC_LIST_BLOCK_SIZE; -+} -+ -+static struct fsync *add_to_list( HANDLE handle, enum fsync_type type, void *shm ) -+{ -+ UINT_PTR entry, idx = handle_to_index( handle, &entry ); -+ -+ if (entry >= FSYNC_LIST_ENTRIES) -+ { -+ FIXME( "too many allocated handles, not caching %p\n", handle ); -+ return FALSE; -+ } -+ -+ if (!fsync_list[entry]) /* do we need to allocate a new block of entries? */ -+ { -+ if (!entry) fsync_list[0] = fsync_list_initial_block; -+ else -+ { -+ void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), -+ PROT_READ | PROT_WRITE ); -+ if (ptr == MAP_FAILED) return FALSE; -+ fsync_list[entry] = ptr; -+ } -+ } -+ -+ if (!__sync_val_compare_and_swap((int *)&fsync_list[entry][idx].type, 0, type )) -+ fsync_list[entry][idx].shm = shm; -+ -+ return &fsync_list[entry][idx]; -+} -+ -+static struct fsync *get_cached_object( HANDLE handle ) -+{ -+ UINT_PTR entry, idx = handle_to_index( handle, &entry ); -+ -+ if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return NULL; -+ if (!fsync_list[entry][idx].type) return NULL; -+ -+ return &fsync_list[entry][idx]; -+} -+ -+/* Gets an object. This is either a proper fsync object (i.e. an event, -+ * semaphore, etc. created using create_fsync) or a generic synchronizable -+ * server-side object which the server will signal (e.g. a process, thread, -+ * message queue, etc.) */ -+static NTSTATUS get_object( HANDLE handle, struct fsync **obj ) -+{ -+ NTSTATUS ret = STATUS_SUCCESS; -+ unsigned int shm_idx = 0; -+ enum fsync_type type; -+ -+ if ((*obj = get_cached_object( handle ))) return STATUS_SUCCESS; -+ -+ if ((INT_PTR)handle < 0) -+ { -+ /* We can deal with pseudo-handles, but it's just easier this way */ -+ return STATUS_NOT_IMPLEMENTED; -+ } -+ -+ /* We need to try grabbing it from the server. */ -+ SERVER_START_REQ( get_fsync_idx ) -+ { -+ req->handle = wine_server_obj_handle( handle ); -+ if (!(ret = wine_server_call( req ))) -+ { -+ shm_idx = reply->shm_idx; -+ type = reply->type; -+ } -+ } -+ SERVER_END_REQ; -+ -+ if (ret) -+ { -+ WARN("Failed to retrieve shm index for handle %p, status %#x.\n", handle, ret); -+ *obj = NULL; -+ return ret; -+ } -+ -+ TRACE("Got shm index %d for handle %p.\n", shm_idx, handle); -+ -+ *obj = add_to_list( handle, type, get_shm( shm_idx ) ); -+ return ret; -+} -+ -+NTSTATUS fsync_close( HANDLE handle ) -+{ -+ UINT_PTR entry, idx = handle_to_index( handle, &entry ); -+ -+ TRACE("%p.\n", handle); -+ -+ if (entry < FSYNC_LIST_ENTRIES && fsync_list[entry]) -+ { -+ if (__atomic_exchange_n( &fsync_list[entry][idx].type, 0, __ATOMIC_SEQ_CST )) -+ return STATUS_SUCCESS; -+ } -+ -+ return STATUS_INVALID_HANDLE; -+} -+ -+static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, -+ ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int low, int high ) -+{ -+ NTSTATUS ret; -+ data_size_t len; -+ struct object_attributes *objattr; -+ unsigned int shm_idx; -+ -+ if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; -+ -+ SERVER_START_REQ( create_fsync ) -+ { -+ req->access = access; -+ req->low = low; -+ req->high = high; -+ req->type = type; -+ wine_server_add_data( req, objattr, len ); -+ ret = wine_server_call( req ); -+ if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) -+ { -+ *handle = wine_server_ptr_handle( reply->handle ); -+ shm_idx = reply->shm_idx; -+ type = reply->type; -+ } -+ } -+ SERVER_END_REQ; -+ -+ if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) -+ { -+ add_to_list( *handle, type, get_shm( shm_idx )); -+ TRACE("-> handle %p, shm index %d.\n", *handle, shm_idx); -+ } -+ -+ free( objattr ); -+ return ret; -+} -+ -+static NTSTATUS open_fsync( enum fsync_type type, HANDLE *handle, -+ ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) -+{ -+ NTSTATUS ret; -+ unsigned int shm_idx; -+ -+ SERVER_START_REQ( open_fsync ) -+ { -+ req->access = access; -+ req->attributes = attr->Attributes; -+ req->rootdir = wine_server_obj_handle( attr->RootDirectory ); -+ req->type = type; -+ if (attr->ObjectName) -+ wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); -+ if (!(ret = wine_server_call( req ))) -+ { -+ *handle = wine_server_ptr_handle( reply->handle ); -+ type = reply->type; -+ shm_idx = reply->shm_idx; -+ } -+ } -+ SERVER_END_REQ; -+ -+ if (!ret) -+ { -+ add_to_list( *handle, type, get_shm( shm_idx ) ); -+ -+ TRACE("-> handle %p, shm index %u.\n", *handle, shm_idx); -+ } -+ return ret; -+} -+ -+void fsync_init(void) -+{ -+ struct stat st; -+ -+ if (!do_fsync()) -+ { -+ /* make sure the server isn't running with WINEFSYNC */ -+ HANDLE handle; -+ NTSTATUS ret; -+ -+ ret = create_fsync( 0, &handle, 0, NULL, 0, 0 ); -+ if (ret != STATUS_NOT_IMPLEMENTED) -+ { -+ ERR("Server is running with WINEFSYNC but this process is not, please enable WINEFSYNC or restart wineserver.\n"); -+ exit(1); -+ } -+ -+ return; -+ } -+ -+ if (stat( config_dir, &st ) == -1) -+ ERR("Cannot stat %s\n", config_dir); -+ -+ if (st.st_ino != (unsigned long)st.st_ino) -+ sprintf( shm_name, "/wine-%lx%08lx-fsync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); -+ else -+ sprintf( shm_name, "/wine-%lx-fsync", (unsigned long)st.st_ino ); -+ -+ if ((shm_fd = shm_open( shm_name, O_RDWR, 0644 )) == -1) -+ { -+ /* probably the server isn't running with WINEFSYNC, tell the user and bail */ -+ if (errno == ENOENT) -+ ERR("Failed to open fsync shared memory file; make sure no stale wineserver instances are running without WINEFSYNC.\n"); -+ else -+ ERR("Failed to initialize shared memory: %s\n", strerror( errno )); -+ exit(1); -+ } -+ -+ pagesize = sysconf( _SC_PAGESIZE ); -+ -+ shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); -+ shm_addrs_size = 128; -+} -+ -+NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max ) -+{ -+ TRACE("name %s, initial %d, max %d.\n", -+ attr ? debugstr_us(attr->ObjectName) : "", initial, max); -+ -+ return create_fsync( FSYNC_SEMAPHORE, handle, access, attr, initial, max ); -+} -+ -+NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr ) -+{ -+ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); -+ -+ return open_fsync( FSYNC_SEMAPHORE, handle, access, attr ); -+} -+ -+NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) -+{ -+ struct fsync *obj; -+ struct semaphore *semaphore; -+ ULONG current; -+ NTSTATUS ret; -+ -+ TRACE("%p, %d, %p.\n", handle, count, prev); -+ -+ if ((ret = get_object( handle, &obj ))) return ret; -+ semaphore = obj->shm; -+ -+ do -+ { -+ current = semaphore->count; -+ if (count + current > semaphore->max) -+ return STATUS_SEMAPHORE_LIMIT_EXCEEDED; -+ } while (__sync_val_compare_and_swap( &semaphore->count, current, count + current ) != current); -+ -+ if (prev) *prev = current; -+ -+ futex_wake( &semaphore->count, INT_MAX ); -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) -+{ -+ struct fsync *obj; -+ struct semaphore *semaphore; -+ SEMAPHORE_BASIC_INFORMATION *out = info; -+ NTSTATUS ret; -+ -+ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); -+ -+ if ((ret = get_object( handle, &obj ))) return ret; -+ semaphore = obj->shm; -+ -+ out->CurrentCount = semaphore->count; -+ out->MaximumCount = semaphore->max; -+ if (ret_len) *ret_len = sizeof(*out); -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) -+{ -+ enum fsync_type type = (event_type == SynchronizationEvent ? FSYNC_AUTO_EVENT : FSYNC_MANUAL_EVENT); -+ -+ TRACE("name %s, %s-reset, initial %d.\n", -+ attr ? debugstr_us(attr->ObjectName) : "", -+ event_type == NotificationEvent ? "manual" : "auto", initial); -+ -+ return create_fsync( type, handle, access, attr, initial, 0xdeadbeef ); -+} -+ -+NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr ) -+{ -+ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); -+ -+ return open_fsync( FSYNC_AUTO_EVENT, handle, access, attr ); -+} -+ -+NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) -+{ -+ struct event *event; -+ struct fsync *obj; -+ LONG current; -+ NTSTATUS ret; -+ -+ TRACE("%p.\n", handle); -+ -+ if ((ret = get_object( handle, &obj ))) return ret; -+ event = obj->shm; -+ -+ if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) -+ futex_wake( &event->signaled, INT_MAX ); -+ -+ if (prev) *prev = current; -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) -+{ -+ struct event *event; -+ struct fsync *obj; -+ LONG current; -+ NTSTATUS ret; -+ -+ TRACE("%p.\n", handle); -+ -+ if ((ret = get_object( handle, &obj ))) return ret; -+ event = obj->shm; -+ -+ current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); -+ -+ if (prev) *prev = current; -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) -+{ -+ struct event *event; -+ struct fsync *obj; -+ LONG current; -+ NTSTATUS ret; -+ -+ TRACE("%p.\n", handle); -+ -+ if ((ret = get_object( handle, &obj ))) return ret; -+ event = obj->shm; -+ -+ /* This isn't really correct; an application could miss the write. -+ * Unfortunately we can't really do much better. Fortunately this is rarely -+ * used (and publicly deprecated). */ -+ if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) -+ futex_wake( &event->signaled, INT_MAX ); -+ -+ /* Try to give other threads a chance to wake up. Hopefully erring on this -+ * side is the better thing to do... */ -+ usleep(0); -+ -+ __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); -+ -+ if (prev) *prev = current; -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) -+{ -+ struct event *event; -+ struct fsync *obj; -+ EVENT_BASIC_INFORMATION *out = info; -+ NTSTATUS ret; -+ -+ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); -+ -+ if ((ret = get_object( handle, &obj ))) return ret; -+ event = obj->shm; -+ -+ out->EventState = event->signaled; -+ out->EventType = (obj->type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); -+ if (ret_len) *ret_len = sizeof(*out); -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) -+{ -+ TRACE("name %s, initial %d.\n", -+ attr ? debugstr_us(attr->ObjectName) : "", initial); -+ -+ return create_fsync( FSYNC_MUTEX, handle, access, attr, -+ initial ? GetCurrentThreadId() : 0, initial ? 1 : 0 ); -+} -+ -+NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr ) -+{ -+ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); -+ -+ return open_fsync( FSYNC_MUTEX, handle, access, attr ); -+} -+ -+NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) -+{ -+ struct mutex *mutex; -+ struct fsync *obj; -+ NTSTATUS ret; -+ -+ TRACE("%p, %p.\n", handle, prev); -+ -+ if ((ret = get_object( handle, &obj ))) return ret; -+ mutex = obj->shm; -+ -+ if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; -+ -+ if (prev) *prev = mutex->count; -+ -+ if (!--mutex->count) -+ { -+ __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); -+ futex_wake( &mutex->tid, INT_MAX ); -+ } -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) -+{ -+ struct fsync *obj; -+ struct mutex *mutex; -+ MUTANT_BASIC_INFORMATION *out = info; -+ NTSTATUS ret; -+ -+ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); -+ -+ if ((ret = get_object( handle, &obj ))) return ret; -+ mutex = obj->shm; -+ -+ out->CurrentCount = 1 - mutex->count; -+ out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); -+ out->AbandonedState = (mutex->tid == ~0); -+ if (ret_len) *ret_len = sizeof(*out); -+ -+ return STATUS_SUCCESS; -+} -+ -+static LONGLONG update_timeout( ULONGLONG end ) -+{ -+ LARGE_INTEGER now; -+ LONGLONG timeleft; -+ -+ NtQuerySystemTime( &now ); -+ timeleft = end - now.QuadPart; -+ if (timeleft < 0) timeleft = 0; -+ return timeleft; -+} -+ -+static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) -+{ -+ int ret; -+ -+ if (alertable) -+ { -+ int *apc_futex = ntdll_get_thread_data()->fsync_apc_futex; -+ struct futex_wait_block futexes[2]; -+ -+ if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) -+ return STATUS_USER_APC; -+ -+ futexes[0].addr = addr; -+ futexes[0].val = val; -+ futexes[1].addr = apc_futex; -+ futexes[1].val = 0; -+#if __SIZEOF_POINTER__ == 4 -+ futexes[0].pad = futexes[1].pad = 0; -+#endif -+ futexes[0].bitset = futexes[1].bitset = ~0; -+ -+ if (end) -+ { -+ LONGLONG timeleft = update_timeout( *end ); -+ struct timespec tmo_p; -+ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -+ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; -+ ret = futex_wait_multiple( futexes, 2, &tmo_p ); -+ } -+ else -+ ret = futex_wait_multiple( futexes, 2, NULL ); -+ -+ if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) -+ return STATUS_USER_APC; -+ } -+ else -+ { -+ if (end) -+ { -+ LONGLONG timeleft = update_timeout( *end ); -+ struct timespec tmo_p; -+ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -+ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; -+ ret = futex_wait( addr, val, &tmo_p ); -+ } -+ else -+ ret = futex_wait( addr, val, NULL ); -+ } -+ -+ if (!ret) -+ return 0; -+ else if (ret < 0 && errno == ETIMEDOUT) -+ return STATUS_TIMEOUT; -+ else -+ return STATUS_PENDING; -+} -+ -+static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, -+ BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) -+{ -+ static const LARGE_INTEGER zero = {0}; -+ -+ struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS + 1]; -+ struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; -+ int has_fsync = 0, has_server = 0; -+ BOOL msgwait = FALSE; -+ int dummy_futex = 0; -+ unsigned int spin; -+ LONGLONG timeleft; -+ LARGE_INTEGER now; -+ DWORD waitcount; -+ ULONGLONG end; -+ int i, ret; -+ -+ /* Grab the APC futex if we don't already have it. */ -+ if (alertable && !ntdll_get_thread_data()->fsync_apc_futex) -+ { -+ unsigned int idx = 0; -+ SERVER_START_REQ( get_fsync_apc_idx ) -+ { -+ if (!(ret = wine_server_call( req ))) -+ idx = reply->shm_idx; -+ } -+ SERVER_END_REQ; -+ -+ if (idx) -+ { -+ struct event *apc_event = get_shm( idx ); -+ ntdll_get_thread_data()->fsync_apc_futex = &apc_event->signaled; -+ } -+ } -+ -+ NtQuerySystemTime( &now ); -+ if (timeout) -+ { -+ if (timeout->QuadPart == TIMEOUT_INFINITE) -+ timeout = NULL; -+ else if (timeout->QuadPart > 0) -+ end = timeout->QuadPart; -+ else -+ end = now.QuadPart - timeout->QuadPart; -+ } -+ -+ for (i = 0; i < count; i++) -+ { -+ ret = get_object( handles[i], &objs[i] ); -+ if (ret == STATUS_SUCCESS) -+ has_fsync = 1; -+ else if (ret == STATUS_NOT_IMPLEMENTED) -+ has_server = 1; -+ else -+ return ret; -+ } -+ -+ if (count && objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) -+ msgwait = TRUE; -+ -+ if (has_fsync && has_server) -+ FIXME("Can't wait on fsync and server objects at the same time!\n"); -+ else if (has_server) -+ return STATUS_NOT_IMPLEMENTED; -+ -+ if (TRACE_ON(fsync)) -+ { -+ TRACE("Waiting for %s of %d handles:", wait_any ? "any" : "all", count); -+ for (i = 0; i < count; i++) -+ TRACE(" %p", handles[i]); -+ -+ if (msgwait) -+ TRACE(" or driver events"); -+ if (alertable) -+ TRACE(", alertable"); -+ -+ if (!timeout) -+ TRACE(", timeout = INFINITE.\n"); -+ else -+ { -+ timeleft = update_timeout( end ); -+ TRACE(", timeout = %ld.%07ld sec.\n", -+ (long) (timeleft / TICKSPERSEC), (long) (timeleft % TICKSPERSEC)); -+ } -+ } -+ -+ if (wait_any || count <= 1) -+ { -+ while (1) -+ { -+ /* Try to grab anything. */ -+ -+ if (alertable) -+ { -+ /* We must check this first! The server may set an event that -+ * we're waiting on, but we need to return STATUS_USER_APC. */ -+ if (__atomic_load_n( ntdll_get_thread_data()->fsync_apc_futex, __ATOMIC_SEQ_CST )) -+ goto userapc; -+ } -+ -+ for (i = 0; i < count; i++) -+ { -+ struct fsync *obj = objs[i]; -+ -+ if (obj) -+ { -+ if (!obj->type) /* gcc complains if we put this in the switch */ -+ { -+ /* Someone probably closed an object while waiting on it. */ -+ WARN("Handle %p has type 0; was it closed?\n", handles[i]); -+ return STATUS_INVALID_HANDLE; -+ } -+ -+ switch (obj->type) -+ { -+ case FSYNC_SEMAPHORE: -+ { -+ struct semaphore *semaphore = obj->shm; -+ int current; -+ -+ /* It would be a little clearer (and less error-prone) -+ * to use a dedicated interlocked_dec_if_nonzero() -+ * helper, but nesting loops like that is probably not -+ * great for performance... */ -+ for (spin = 0; spin <= spincount || current; ++spin) -+ { -+ if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) -+ && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) -+ { -+ TRACE("Woken up by handle %p [%d].\n", handles[i], i); -+ return i; -+ } -+ small_pause(); -+ } -+ -+ futexes[i].addr = &semaphore->count; -+ futexes[i].val = 0; -+ break; -+ } -+ case FSYNC_MUTEX: -+ { -+ struct mutex *mutex = obj->shm; -+ int tid; -+ -+ if (mutex->tid == GetCurrentThreadId()) -+ { -+ TRACE("Woken up by handle %p [%d].\n", handles[i], i); -+ mutex->count++; -+ return i; -+ } -+ -+ for (spin = 0; spin <= spincount; ++spin) -+ { -+ if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) -+ { -+ TRACE("Woken up by handle %p [%d].\n", handles[i], i); -+ mutex->count = 1; -+ return i; -+ } -+ else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) -+ { -+ TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); -+ mutex->count = 1; -+ return STATUS_ABANDONED_WAIT_0 + i; -+ } -+ small_pause(); -+ } -+ -+ futexes[i].addr = &mutex->tid; -+ futexes[i].val = tid; -+ break; -+ } -+ case FSYNC_AUTO_EVENT: -+ case FSYNC_AUTO_SERVER: -+ { -+ struct event *event = obj->shm; -+ -+ for (spin = 0; spin <= spincount; ++spin) -+ { -+ if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) -+ { -+ TRACE("Woken up by handle %p [%d].\n", handles[i], i); -+ return i; -+ } -+ small_pause(); -+ } -+ -+ futexes[i].addr = &event->signaled; -+ futexes[i].val = 0; -+ break; -+ } -+ case FSYNC_MANUAL_EVENT: -+ case FSYNC_MANUAL_SERVER: -+ case FSYNC_QUEUE: -+ { -+ struct event *event = obj->shm; -+ -+ for (spin = 0; spin <= spincount; ++spin) -+ { -+ if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) -+ { -+ TRACE("Woken up by handle %p [%d].\n", handles[i], i); -+ return i; -+ } -+ small_pause(); -+ } -+ -+ futexes[i].addr = &event->signaled; -+ futexes[i].val = 0; -+ break; -+ } -+ default: -+ ERR("Invalid type %#x for handle %p.\n", obj->type, handles[i]); -+ assert(0); -+ } -+ } -+ else -+ { -+ /* Avoid breaking things entirely. */ -+ futexes[i].addr = &dummy_futex; -+ futexes[i].val = dummy_futex; -+ } -+ -+#if __SIZEOF_POINTER__ == 4 -+ futexes[i].pad = 0; -+#endif -+ futexes[i].bitset = ~0; -+ } -+ -+ if (alertable) -+ { -+ /* We already checked if it was signaled; don't bother doing it again. */ -+ futexes[i].addr = ntdll_get_thread_data()->fsync_apc_futex; -+ futexes[i].val = 0; -+#if __SIZEOF_POINTER__ == 4 -+ futexes[i].pad = 0; -+#endif -+ futexes[i].bitset = ~0; -+ i++; -+ } -+ waitcount = i; -+ -+ /* Looks like everything is contended, so wait. */ -+ -+ if (timeout && !timeout->QuadPart) -+ { -+ /* Unlike esync, we already know that we've timed out, so we -+ * can avoid a syscall. */ -+ TRACE("Wait timed out.\n"); -+ return STATUS_TIMEOUT; -+ } -+ else if (timeout) -+ { -+ LONGLONG timeleft = update_timeout( end ); -+ struct timespec tmo_p; -+ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -+ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; -+ -+ ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); -+ } -+ else -+ ret = futex_wait_multiple( futexes, waitcount, NULL ); -+ -+ /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, -+ * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to -+ * try again, bad address is already handled by the fact that we -+ * tried to read from it, so only break out on a timeout. */ -+ if (ret == -1 && errno == ETIMEDOUT) -+ { -+ TRACE("Wait timed out.\n"); -+ return STATUS_TIMEOUT; -+ } -+ } /* while (1) */ -+ } -+ else -+ { -+ /* Wait-all is a little trickier to implement correctly. Fortunately, -+ * it's not as common. -+ * -+ * The idea is basically just to wait in sequence on every object in the -+ * set. Then when we're done, try to grab them all in a tight loop. If -+ * that fails, release any resources we've grabbed (and yes, we can -+ * reliably do this—it's just mutexes and semaphores that we have to -+ * put back, and in both cases we just put back 1), and if any of that -+ * fails we start over. -+ * -+ * What makes this inherently bad is that we might temporarily grab a -+ * resource incorrectly. Hopefully it'll be quick (and hey, it won't -+ * block on wineserver) so nobody will notice. Besides, consider: if -+ * object A becomes signaled but someone grabs it before we can grab it -+ * and everything else, then they could just as well have grabbed it -+ * before it became signaled. Similarly if object A was signaled and we -+ * were blocking on object B, then B becomes available and someone grabs -+ * A before we can, then they might have grabbed A before B became -+ * signaled. In either case anyone who tries to wait on A or B will be -+ * waiting for an instant while we put things back. */ -+ -+ NTSTATUS status = STATUS_SUCCESS; -+ int current; -+ -+ while (1) -+ { -+ BOOL abandoned; -+ -+tryagain: -+ abandoned = FALSE; -+ -+ /* First step: try to wait on each object in sequence. */ -+ -+ for (i = 0; i < count; i++) -+ { -+ struct fsync *obj = objs[i]; -+ -+ if (obj && obj->type == FSYNC_MUTEX) -+ { -+ struct mutex *mutex = obj->shm; -+ -+ if (mutex->tid == GetCurrentThreadId()) -+ continue; -+ -+ while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) -+ { -+ status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL, alertable ); -+ if (status != STATUS_PENDING) -+ break; -+ } -+ } -+ else if (obj) -+ { -+ /* this works for semaphores too */ -+ struct event *event = obj->shm; -+ -+ while (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) -+ { -+ status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL, alertable ); -+ if (status != STATUS_PENDING) -+ break; -+ } -+ } -+ -+ if (status == STATUS_TIMEOUT) -+ { -+ TRACE("Wait timed out.\n"); -+ return status; -+ } -+ else if (status == STATUS_USER_APC) -+ goto userapc; -+ } -+ -+ /* If we got here and we haven't timed out, that means all of the -+ * handles were signaled. Check to make sure they still are. */ -+ for (i = 0; i < count; i++) -+ { -+ struct fsync *obj = objs[i]; -+ -+ if (obj && obj->type == FSYNC_MUTEX) -+ { -+ struct mutex *mutex = obj->shm; -+ int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); -+ -+ if (tid && tid != ~0 && tid != GetCurrentThreadId()) -+ goto tryagain; -+ } -+ else if (obj) -+ { -+ struct event *event = obj->shm; -+ -+ if (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) -+ goto tryagain; -+ } -+ } -+ -+ /* Yep, still signaled. Now quick, grab everything. */ -+ for (i = 0; i < count; i++) -+ { -+ struct fsync *obj = objs[i]; -+ switch (obj->type) -+ { -+ case FSYNC_MUTEX: -+ { -+ struct mutex *mutex = obj->shm; -+ int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); -+ if (tid == GetCurrentThreadId()) -+ break; -+ if (tid && tid != ~0) -+ goto tooslow; -+ if (__sync_val_compare_and_swap( &mutex->tid, tid, GetCurrentThreadId() ) != tid) -+ goto tooslow; -+ if (tid == ~0) -+ abandoned = TRUE; -+ break; -+ } -+ case FSYNC_SEMAPHORE: -+ { -+ struct semaphore *semaphore = obj->shm; -+ if (__sync_fetch_and_sub( &semaphore->count, 1 ) <= 0) -+ goto tooslow; -+ break; -+ } -+ case FSYNC_AUTO_EVENT: -+ case FSYNC_AUTO_SERVER: -+ { -+ struct event *event = obj->shm; -+ if (!__sync_val_compare_and_swap( &event->signaled, 1, 0 )) -+ goto tooslow; -+ break; -+ } -+ default: -+ /* If a manual-reset event changed between there and -+ * here, it's shouldn't be a problem. */ -+ break; -+ } -+ } -+ -+ /* If we got here, we successfully waited on every object. -+ * Make sure to let ourselves know that we grabbed the mutexes. */ -+ for (i = 0; i < count; i++) -+ { -+ if (objs[i] && objs[i]->type == FSYNC_MUTEX) -+ { -+ struct mutex *mutex = objs[i]->shm; -+ mutex->count++; -+ } -+ } -+ -+ if (abandoned) -+ { -+ TRACE("Wait successful, but some object(s) were abandoned.\n"); -+ return STATUS_ABANDONED; -+ } -+ TRACE("Wait successful.\n"); -+ return STATUS_SUCCESS; -+ -+tooslow: -+ for (--i; i >= 0; i--) -+ { -+ struct fsync *obj = objs[i]; -+ switch (obj->type) -+ { -+ case FSYNC_MUTEX: -+ { -+ struct mutex *mutex = obj->shm; -+ /* HACK: This won't do the right thing with abandoned -+ * mutexes, but fixing it is probably more trouble than -+ * it's worth. */ -+ __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); -+ break; -+ } -+ case FSYNC_SEMAPHORE: -+ { -+ struct semaphore *semaphore = obj->shm; -+ __sync_fetch_and_add( &semaphore->count, 1 ); -+ break; -+ } -+ case FSYNC_AUTO_EVENT: -+ case FSYNC_AUTO_SERVER: -+ { -+ struct event *event = obj->shm; -+ __atomic_store_n( &event->signaled, 1, __ATOMIC_SEQ_CST ); -+ break; -+ } -+ default: -+ /* doesn't need to be put back */ -+ break; -+ } -+ } -+ } /* while (1) */ -+ } /* else (wait-all) */ -+ -+ assert(0); /* shouldn't reach here... */ -+ -+userapc: -+ TRACE("Woken up by user APC.\n"); -+ -+ /* We have to make a server call anyway to get the APC to execute, so just -+ * delegate down to server_wait(). */ -+ ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero ); -+ -+ /* This can happen if we received a system APC, and the APC fd was woken up -+ * before we got SIGUSR1. poll() doesn't return EINTR in that case. The -+ * right thing to do seems to be to return STATUS_USER_APC anyway. */ -+ if (ret == STATUS_TIMEOUT) ret = STATUS_USER_APC; -+ return ret; -+} -+ -+/* Like esync, we need to let the server know when we are doing a message wait, -+ * and when we are done with one, so that all of the code surrounding hung -+ * queues works, and we also need this for WaitForInputIdle(). -+ * -+ * Unlike esync, we can't wait on the queue fd itself locally. Instead we let -+ * the server do that for us, the way it normally does. This could actually -+ * work for esync too, and that might be better. */ -+static void server_set_msgwait( int in_msgwait ) -+{ -+ SERVER_START_REQ( fsync_msgwait ) -+ { -+ req->in_msgwait = in_msgwait; -+ wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+} -+ -+/* This is a very thin wrapper around the proper implementation above. The -+ * purpose is to make sure the server knows when we are doing a message wait. -+ * This is separated into a wrapper function since there are at least a dozen -+ * exit paths from fsync_wait_objects(). */ -+NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, -+ BOOLEAN alertable, const LARGE_INTEGER *timeout ) -+{ -+ BOOL msgwait = FALSE; -+ struct fsync *obj; -+ NTSTATUS ret; -+ -+ if (count && !get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) -+ { -+ msgwait = TRUE; -+ server_set_msgwait( 1 ); -+ } -+ -+ ret = __fsync_wait_objects( count, handles, wait_any, alertable, timeout ); -+ -+ if (msgwait) -+ server_set_msgwait( 0 ); -+ -+ return ret; -+} -+ -+NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, -+ const LARGE_INTEGER *timeout ) -+{ -+ struct fsync *obj; -+ NTSTATUS ret; -+ -+ if ((ret = get_object( signal, &obj ))) return ret; -+ -+ switch (obj->type) -+ { -+ case FSYNC_SEMAPHORE: -+ ret = fsync_release_semaphore( signal, 1, NULL ); -+ break; -+ case FSYNC_AUTO_EVENT: -+ case FSYNC_MANUAL_EVENT: -+ ret = fsync_set_event( signal, NULL ); -+ break; -+ case FSYNC_MUTEX: -+ ret = fsync_release_mutex( signal, NULL ); -+ break; -+ default: -+ return STATUS_OBJECT_TYPE_MISMATCH; -+ } -+ if (ret) return ret; -+ -+ return fsync_wait_objects( 1, &wait, TRUE, alertable, timeout ); -+} -diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h -new file mode 100644 -index 00000000000..b3604548554 ---- /dev/null -+++ b/dlls/ntdll/unix/fsync.h -@@ -0,0 +1,49 @@ -+/* -+ * futex-based synchronization objects -+ * -+ * Copyright (C) 2018 Zebediah Figura -+ * -+ * 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 -+ */ -+ -+extern int do_fsync(void) DECLSPEC_HIDDEN; -+extern void fsync_init(void) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_close( HANDLE handle ) DECLSPEC_HIDDEN; -+ -+extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, -+ const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) DECLSPEC_HIDDEN; -+ -+extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, -+ BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; -+extern NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, -+ BOOLEAN alertable, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 19b73256ef2..d0d979248f8 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -87,6 +87,7 @@ - #include "winternl.h" - #include "unix_private.h" - #include "esync.h" -+#include "fsync.h" - #include "wine/list.h" - #include "wine/debug.h" - -@@ -1565,6 +1566,7 @@ static void start_main_thread(void) - signal_init_thread( teb ); - dbg_init(); - startup_info_size = server_init_process(); -+ fsync_init(); - esync_init(); - virtual_map_user_shared_data(); - init_cpu_info(); -diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c -index 34d4c80eee5..c48a6339fee 100644 ---- a/dlls/ntdll/unix/server.c -+++ b/dlls/ntdll/unix/server.c -@@ -95,6 +95,7 @@ - #include "wine/debug.h" - #include "unix_private.h" - #include "esync.h" -+#include "fsync.h" - #include "ddk/wdm.h" - - WINE_DEFAULT_DEBUG_CHANNEL(server); -@@ -1698,6 +1699,9 @@ NTSTATUS WINAPI NtClose( HANDLE handle ) - NTSTATUS ret; - int fd = remove_fd_from_cache( handle ); - -+ if (do_fsync()) -+ fsync_close( handle ); -+ - if (do_esync()) - esync_close( handle ); - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 051c672bd12..d8a8eb526a1 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -73,6 +73,7 @@ - #include "wine/debug.h" - #include "unix_private.h" - #include "esync.h" -+#include "fsync.h" - - WINE_DEFAULT_DEBUG_CHANNEL(sync); - -@@ -262,6 +262,9 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ - if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER; - if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; - -+ if (do_fsync()) -+ return fsync_create_semaphore( handle, access, attr, initial, max ); -+ - if (do_esync()) - return esync_create_semaphore( handle, access, attr, initial, max ); - -@@ -297,6 +297,9 @@ NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJEC - { - NTSTATUS ret; - -+ if (do_fsync()) -+ return fsync_open_semaphore( handle, access, attr ); -+ - if (do_esync()) - return esync_open_semaphore( handle, access, attr ); - -@@ -327,6 +327,9 @@ NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS cla - - if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - -+ if (do_fsync()) -+ return fsync_query_semaphore( handle, info, ret_len ); -+ - if (do_esync()) - return esync_query_semaphore( handle, info, ret_len ); - -@@ -367,6 +367,9 @@ NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous - { - NTSTATUS ret; - -+ if (do_fsync()) -+ return fsync_release_semaphore( handle, count, previous ); -+ - if (do_esync()) - return esync_release_semaphore( handle, count, previous ); - -@@ -394,6 +394,9 @@ NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ - data_size_t len; - struct object_attributes *objattr; - -+ if (do_fsync()) -+ return fsync_create_event( handle, access, attr, type, state ); -+ - if (do_esync()) - return esync_create_event( handle, access, attr, type, state ); - -@@ -428,6 +428,9 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT - - if ((ret = validate_open_object_attributes( attr ))) return ret; - -+ if (do_fsync()) -+ return fsync_open_event( handle, access, attr ); -+ - if (do_esync()) - return esync_open_event( handle, access, attr ); - -@@ -458,6 +458,9 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) - { - NTSTATUS ret; - -+ if (do_fsync()) -+ return fsync_set_event( handle, prev_state ); -+ - if (do_esync()) - return esync_set_event( handle ); - -@@ -480,6 +480,9 @@ NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state ) - { - NTSTATUS ret; - -+ if (do_fsync()) -+ return fsync_reset_event( handle, prev_state ); -+ - if (do_esync()) - return esync_reset_event( handle ); - -@@ -512,6 +512,9 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state ) - { - NTSTATUS ret; - -+ if (do_fsync()) -+ return fsync_pulse_event( handle, prev_state ); -+ - if (do_esync()) - return esync_pulse_event( handle ); - -@@ -537,6 +537,9 @@ NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class, - - if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - -+ if (do_fsync()) -+ return fsync_query_event( handle, info, ret_len ); -+ - if (do_esync()) - return esync_query_event( handle, info, ret_len ); - -@@ -578,6 +578,9 @@ NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT - data_size_t len; - struct object_attributes *objattr; - -+ if (do_fsync()) -+ return fsync_create_mutex( handle, access, attr, owned ); -+ - if (do_esync()) - return esync_create_mutex( handle, access, attr, owned ); - -@@ -611,6 +611,9 @@ NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_A - - if ((ret = validate_open_object_attributes( attr ))) return ret; - -+ if (do_fsync()) -+ return fsync_open_mutex( handle, access, attr ); -+ - if (do_esync()) - return esync_open_mutex( handle, access, attr ); - -@@ -641,6 +641,9 @@ NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count ) - { - NTSTATUS ret; - -+ if (do_fsync()) -+ return fsync_release_mutex( handle, prev_count ); -+ - if (do_esync()) - return esync_release_mutex( handle, prev_count ); - -@@ -665,6 +665,9 @@ NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class, - - if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - -+ if (do_fsync()) -+ return fsync_query_mutex( handle, info, ret_len ); -+ - if (do_esync()) - return esync_query_mutex( handle, info, ret_len ); - -@@ -1286,6 +1286,13 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO - - if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1; - -+ if (do_fsync()) -+ { -+ NTSTATUS ret = fsync_wait_objects( count, handles, wait_any, alertable, timeout ); -+ if (ret != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ } -+ - if (do_esync()) - { - NTSTATUS ret = esync_wait_objects( count, handles, wait_any, alertable, timeout ); -@@ -1323,6 +1323,9 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, - select_op_t select_op; - UINT flags = SELECT_INTERRUPTIBLE; - -+ if (do_fsync()) -+ return fsync_signal_and_wait( signal, wait, alertable, timeout ); -+ - if (do_esync()) - return esync_signal_and_wait( signal, wait, alertable, timeout ); - -@@ -1348,7 +1348,24 @@ NTSTATUS WINAPI NtYieldExecution(void) - NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout ) - { - /* if alertable, we need to query the server */ -- if (alertable) return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout ); -+ if (alertable) -+ { -+ if (do_fsync()) -+ { -+ NTSTATUS ret = fsync_wait_objects( 0, NULL, TRUE, TRUE, timeout ); -+ if (ret != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ } -+ -+ if (do_esync()) -+ { -+ NTSTATUS ret = esync_wait_objects( 0, NULL, TRUE, TRUE, timeout ); -+ if (ret != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ } -+ -+ return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout ); -+ } - - if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */ - { -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index e7033932bcb..a2f485d892f 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -59,6 +59,7 @@ struct ntdll_thread_data - struct debug_info *debug_info; /* info for debugstr functions */ - void *start_stack; /* stack for thread startup */ - int esync_apc_fd; /* fd to wait on for user APCs */ -+ int *fsync_apc_futex; - int request_fd; /* fd for sending server requests */ - int reply_fd; /* fd for receiving server replies */ - int wait_fd[2]; /* fd for sleeping server requests */ -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index bd89649e769..608c83b579c 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -2683,6 +2683,7 @@ static void init_teb( TEB *teb, PEB *peb ) - teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; - teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); - thread_data->esync_apc_fd = -1; -+ thread_data->fsync_apc_futex = NULL; - thread_data->request_fd = -1; - thread_data->reply_fd = -1; - thread_data->wait_fd[0] = -1; -diff --git a/server/Makefile.in b/server/Makefile.in -index 8bd612b4728..6dc5c465e52 100644 ---- a/server/Makefile.in -+++ b/server/Makefile.in -@@ -15,6 +15,7 @@ C_SRCS = \ - event.c \ - fd.c \ - file.c \ -+ fsync.c \ - handle.c \ - hook.c \ - mach.c \ -diff --git a/server/async.c b/server/async.c -index 1b4f86a1b8b..ceff9c75c27 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -71,6 +71,7 @@ static const struct object_ops async_ops = - remove_queue, /* remove_queue */ - async_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - async_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -486,6 +487,7 @@ static const struct object_ops iosb_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/atom.c b/server/atom.c -index 73d858fef82..7acef97c30d 100644 ---- a/server/atom.c -+++ b/server/atom.c -@@ -81,6 +81,7 @@ static const struct object_ops atom_table_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/change.c b/server/change.c -index 85afb0cbdc5..7eea72757c5 100644 ---- a/server/change.c -+++ b/server/change.c -@@ -116,6 +116,7 @@ static const struct object_ops dir_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - default_fd_get_esync_fd, /* get_esync_fd */ -+ default_fd_get_fsync_idx, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - dir_get_fd, /* get_fd */ -diff --git a/server/clipboard.c b/server/clipboard.c -index 54a5fb683cc..1fa61b67a88 100644 ---- a/server/clipboard.c -+++ b/server/clipboard.c -@@ -78,6 +78,7 @@ static const struct object_ops clipboard_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/completion.c b/server/completion.c -index ef66260c991..2149d0bbf32 100644 ---- a/server/completion.c -+++ b/server/completion.c -@@ -65,6 +65,7 @@ static const struct object_ops completion_ops = - remove_queue, /* remove_queue */ - completion_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/console.c b/server/console.c -index 78635f3fae1..824b930bba0 100644 ---- a/server/console.c -+++ b/server/console.c -@@ -43,6 +43,7 @@ - #include "winternl.h" - #include "wine/condrv.h" - #include "esync.h" -+#include "fsync.h" - - struct screen_buffer; - -@@ -82,6 +83,7 @@ static const struct object_ops console_input_ops = - remove_queue, /* remove_queue */ - console_input_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - console_input_get_fd, /* get_fd */ -@@ -136,6 +138,7 @@ struct console_server - int term_fd; /* UNIX terminal fd */ - struct termios termios; /* original termios */ - int esync_fd; -+ unsigned int fsync_idx; - }; - - static void console_server_dump( struct object *obj, int verbose ); -@@ -146,6 +149,7 @@ static struct object *console_server_lookup_name( struct object *obj, struct uni - static void console_server_destroy( struct object *obj ); - static int console_server_signaled( struct object *obj, struct wait_queue_entry *entry ); - static int console_server_get_esync_fd( struct object *obj, enum esync_type *type ); -+static unsigned int console_server_get_fsync_idx( struct object *obj, enum fsync_type *type ); - static struct fd *console_server_get_fd( struct object *obj ); - static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attr ); - static struct object *console_server_open_file( struct object *obj, unsigned int access, -@@ -156,6 +160,7 @@ static const struct object_ops console_server_ops = - remove_queue, /* remove_queue */ - console_server_signaled, /* signaled */ - console_server_get_esync_fd, /* get_esync_fd */ -+ console_server_get_fsync_idx, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - console_server_get_fd, /* get_fd */ -@@ -224,6 +229,7 @@ static const struct object_ops screen_buffer_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - screen_buffer_get_fd, /* get_fd */ -@@ -272,6 +278,7 @@ static const struct object_ops console_device_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -297,6 +301,7 @@ static const struct object_ops input_device_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - input_device_get_fd, /* get_fd */ -@@ -327,6 +332,7 @@ static const struct object_ops output_device_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - output_device_get_fd, /* get_fd */ -@@ -365,6 +371,7 @@ static const struct object_ops console_connection_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - console_connection_get_fd, /* get_fd */ -@@ -587,8 +587,13 @@ static void disconnect_console_server( struct console_server *server ) - list_remove( &call->entry ); - console_host_ioctl_terminate( call, STATUS_CANCELLED ); - } -+ -+ if (do_fsync()) -+ fsync_clear_futex( server->fsync_idx ); -+ - if (do_esync()) - esync_clear( server->esync_fd ); -+ - while (!list_empty( &server->read_queue )) - { - struct console_host_ioctl *call = LIST_ENTRY( list_head( &server->read_queue ), struct console_host_ioctl, entry ); -@@ -774,6 +787,13 @@ static int console_server_get_esync_fd( struct object *obj, enum esync_type *typ - return server->esync_fd; - } - -+static unsigned int console_server_get_fsync_idx( struct object *obj, enum fsync_type *type ) -+{ -+ struct console_server *server = (struct console_server*)obj; -+ *type = FSYNC_MANUAL_SERVER; -+ return server->fsync_idx; -+} -+ - static struct fd *console_server_get_fd( struct object* obj ) - { - struct console_server *server = (struct console_server*)obj; -@@ -806,6 +828,9 @@ static struct object *create_console_server( void ) - } - allow_fd_caching(server->fd); - -+ if (do_fsync()) -+ server->fsync_idx = fsync_alloc_shm( 0, 0 ); -+ - if (do_esync()) - server->esync_fd = esync_create_fd( 0, 0 ); - -@@ -1545,6 +1560,10 @@ DECL_HANDLER(get_next_console_request) - /* set result of previous ioctl */ - ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry ); - list_remove( &ioctl->entry ); -+ -+ if (do_fsync() && list_empty( &server->queue )) -+ fsync_clear_futex( server->fsync_idx ); -+ - if (do_esync() && list_empty( &server->queue )) - esync_clear( server->esync_fd ); - } -@@ -1645,6 +1664,10 @@ DECL_HANDLER(get_next_console_request) - { - set_error( STATUS_PENDING ); - } -+ -+ if (do_fsync() && list_empty( &server->queue )) -+ fsync_clear_futex( server->fsync_idx ); -+ - if (do_esync() && list_empty( &server->queue )) - esync_clear( server->esync_fd ); - -diff --git a/server/debugger.c b/server/debugger.c -index c37f97aa0b6..b7d88cfd2f2 100644 ---- a/server/debugger.c -+++ b/server/debugger.c -@@ -74,6 +74,7 @@ static const struct object_ops debug_event_ops = - remove_queue, /* remove_queue */ - debug_event_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -103,6 +104,7 @@ static const struct object_ops debug_ctx_ops = - remove_queue, /* remove_queue */ - debug_obj_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/device.c b/server/device.c -index b8ce131c732..c56151c9b18 100644 ---- a/server/device.c -+++ b/server/device.c -@@ -40,6 +40,7 @@ - #include "request.h" - #include "process.h" - #include "esync.h" -+#include "fsync.h" - - /* IRP object */ - -@@ -70,6 +71,7 @@ static const struct object_ops irp_call_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -97,11 +99,13 @@ struct device_manager - struct irp_call *current_call; /* call currently executed on client side */ - struct wine_rb_tree kernel_objects; /* map of objects that have client side pointer associated */ - int esync_fd; /* esync file descriptor */ -+ unsigned int fsync_idx; - }; - - static void device_manager_dump( struct object *obj, int verbose ); - static int device_manager_signaled( struct object *obj, struct wait_queue_entry *entry ); - static int device_manager_get_esync_fd( struct object *obj, enum esync_type *type ); -+static unsigned int device_manager_get_fsync_idx( struct object *obj, enum fsync_type *type ); - static void device_manager_destroy( struct object *obj ); - - static const struct object_ops device_manager_ops = -@@ -113,6 +117,7 @@ static const struct object_ops device_manager_ops = - remove_queue, /* remove_queue */ - device_manager_signaled, /* signaled */ - device_manager_get_esync_fd, /* get_esync_fd */ -+ device_manager_get_fsync_idx, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -158,6 +163,7 @@ static const struct object_ops device_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -210,6 +216,7 @@ static const struct object_ops device_file_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - device_file_get_fd, /* get_fd */ -@@ -754,6 +761,9 @@ static void delete_file( struct device_file *file ) - /* terminate all pending requests */ - LIST_FOR_EACH_ENTRY_SAFE( irp, next, &file->requests, struct irp_call, dev_entry ) - { -+ if (do_fsync() && file->device->manager && list_empty( &file->device->manager->requests )) -+ fsync_clear( &file->device->manager->obj ); -+ - if (do_esync() && file->device->manager && list_empty( &file->device->manager->requests )) - esync_clear( file->device->manager->esync_fd ); - -@@ -799,6 +809,13 @@ static int device_manager_get_esync_fd( struct object *obj, enum esync_type *typ - return manager->esync_fd; - } - -+static unsigned int device_manager_get_fsync_idx( struct object *obj, enum fsync_type *type ) -+{ -+ struct device_manager *manager = (struct device_manager *)obj; -+ *type = FSYNC_MANUAL_SERVER; -+ return manager->fsync_idx; -+} -+ - static void device_manager_destroy( struct object *obj ) - { - struct device_manager *manager = (struct device_manager *)obj; -@@ -849,6 +866,9 @@ static struct device_manager *create_device_manager(void) - list_init( &manager->requests ); - wine_rb_init( &manager->kernel_objects, compare_kernel_object ); - -+ if (do_fsync()) -+ manager->fsync_idx = fsync_alloc_shm( 0, 0 ); -+ - if (do_esync()) - manager->esync_fd = esync_create_fd( 0, 0 ); - } -@@ -1017,6 +1037,9 @@ DECL_HANDLER(get_next_device_request) - if (irp->file) grab_object( irp ); - manager->current_call = irp; - -+ if (do_fsync() && list_empty( &manager->requests )) -+ fsync_clear( &manager->obj ); -+ - if (do_esync() && list_empty( &manager->requests )) - esync_clear( manager->esync_fd ); - } -diff --git a/server/directory.c b/server/directory.c -index 007ec1002ac..62f2e50916f 100644 ---- a/server/directory.c -+++ b/server/directory.c -@@ -59,6 +59,7 @@ static const struct object_ops object_type_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -99,6 +100,7 @@ static const struct object_ops directory_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/esync.c b/server/esync.c -index 5c641fdbe01..6395ba4378c 100644 ---- a/server/esync.c -+++ b/server/esync.c -@@ -44,6 +44,7 @@ - #include "request.h" - #include "file.h" - #include "esync.h" -+#include "fsync.h" - - int do_esync(void) - { -@@ -51,7 +52,7 @@ int do_esync(void) - static int do_esync_cached = -1; - - if (do_esync_cached == -1) -- do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); -+ do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_fsync(); - - return do_esync_cached; - #else -@@ -130,6 +131,7 @@ const struct object_ops esync_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - esync_get_esync_fd, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/event.c b/server/event.c -index 8607b494b6d..28a52e61d00 100644 ---- a/server/event.c -+++ b/server/event.c -@@ -36,6 +36,7 @@ - #include "request.h" - #include "security.h" - #include "esync.h" -+#include "fsync.h" - - static const WCHAR event_name[] = {'E','v','e','n','t'}; - -@@ -44,6 +45,7 @@ struct event - int manual_reset; /* is it a manual reset event? */ - int signaled; /* event has been signaled */ - int esync_fd; /* esync file descriptor */ -+ unsigned int fsync_idx; - }; - - static void event_dump( struct object *obj, int verbose ); -@@ -51,6 +53,7 @@ static void event_dump( struct object *obj, int verbose ); - static int event_signaled( struct object *obj, struct wait_queue_entry *entry ); - static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ); - static int event_get_esync_fd( struct object *obj, enum esync_type *type ); -+static unsigned int event_get_fsync_idx( struct object *obj, enum fsync_type *type ); - static int event_signal( struct object *obj, unsigned int access); - static struct list *event_get_kernel_obj_list( struct object *obj ); - static void event_destroy( struct object *obj ); -@@ -65,6 +68,7 @@ static const struct object_ops event_ops = - remove_queue, /* remove_queue */ - event_signaled, /* signaled */ - event_get_esync_fd, /* get_esync_fd */ -+ event_get_fsync_idx, /* get_fsync_idx */ - event_satisfied, /* satisfied */ - event_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -101,6 +105,7 @@ static const struct object_ops keyed_event_ops = - remove_queue, /* remove_queue */ - keyed_event_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -133,6 +138,9 @@ struct event *create_event( struct object *root, const struct unicode_str *name, - event->manual_reset = manual_reset; - event->signaled = initial_state; - -+ if (do_fsync()) -+ event->fsync_idx = fsync_alloc_shm( initial_state, 0 ); -+ - if (do_esync()) - event->esync_fd = esync_create_fd( initial_state, 0 ); - } -@@ -143,6 +151,10 @@ struct event *create_event( struct object *root, const struct unicode_str *name, - struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ) - { - struct object *obj; -+ -+ if (do_fsync() && (obj = get_handle_obj( process, handle, access, &fsync_ops))) -+ return (struct event *)obj; /* even though it's not an event */ -+ - if (do_esync() && (obj = get_handle_obj( process, handle, access, &esync_ops))) - return (struct event *)obj; /* even though it's not an event */ - -@@ -155,10 +167,19 @@ void pulse_event( struct event *event ) - /* wake up all waiters if manual reset, a single one otherwise */ - wake_up( &event->obj, !event->manual_reset ); - event->signaled = 0; -+ -+ if (do_fsync()) -+ fsync_clear( &event->obj ); - } - - void set_event( struct event *event ) - { -+ if (do_fsync() && event->obj.ops == &fsync_ops) -+ { -+ fsync_set_event( (struct fsync *)event ); -+ return; -+ } -+ - if (do_esync() && event->obj.ops == &esync_ops) - { - esync_set_event( (struct esync *)event ); -@@ -172,6 +193,12 @@ void set_event( struct event *event ) - - void reset_event( struct event *event ) - { -+ if (do_fsync() && event->obj.ops == &fsync_ops) -+ { -+ fsync_reset_event( (struct fsync *)event ); -+ return; -+ } -+ - if (do_esync() && event->obj.ops == &esync_ops) - { - esync_reset_event( (struct esync *)event ); -@@ -179,6 +206,9 @@ void reset_event( struct event *event ) - } - event->signaled = 0; - -+ if (do_fsync()) -+ fsync_clear( &event->obj ); -+ - if (do_esync()) - esync_clear( event->esync_fd ); - } -@@ -211,6 +241,13 @@ static int event_get_esync_fd( struct object *obj, enum esync_type *type ) - return event->esync_fd; - } - -+static unsigned int event_get_fsync_idx( struct object *obj, enum fsync_type *type ) -+{ -+ struct event *event = (struct event *)obj; -+ *type = FSYNC_MANUAL_SERVER; -+ return event->fsync_idx; -+} -+ - static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ) - { - struct event *event = (struct event *)obj; -diff --git a/server/fd.c b/server/fd.c -index bbc2462163d..c558229c3c8 100644 ---- a/server/fd.c -+++ b/server/fd.c -@@ -103,6 +103,7 @@ - #include "process.h" - #include "request.h" - #include "esync.h" -+#include "fsync.h" - - #include "winternl.h" - #include "winioctl.h" -@@ -205,6 +206,7 @@ struct fd - apc_param_t comp_key; /* completion key to set in completion events */ - unsigned int comp_flags; /* completion flags */ - int esync_fd; /* esync file descriptor */ -+ unsigned int fsync_idx; /* fsync shm index */ - }; - - static void fd_dump( struct object *obj, int verbose ); -@@ -219,6 +221,7 @@ static const struct object_ops fd_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -261,6 +264,7 @@ static const struct object_ops device_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -302,6 +306,7 @@ static const struct object_ops inode_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -345,6 +350,7 @@ static const struct object_ops file_lock_ops = - remove_queue, /* remove_queue */ - file_lock_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -1714,6 +1720,7 @@ static struct fd *alloc_fd_object(void) - fd->completion = NULL; - fd->comp_flags = 0; - fd->esync_fd = -1; -+ fd->fsync_idx = 0; - init_async_queue( &fd->read_q ); - init_async_queue( &fd->write_q ); - init_async_queue( &fd->wait_q ); -@@ -1723,6 +1730,9 @@ static struct fd *alloc_fd_object(void) - if (do_esync()) - fd->esync_fd = esync_create_fd( 1, 0 ); - -+ if (do_fsync()) -+ fd->fsync_idx = fsync_alloc_shm( 1, 0 ); -+ - if ((fd->poll_index = add_poll_user( fd )) == -1) - { - release_object( fd ); -@@ -1756,14 +1766,19 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use - fd->comp_flags = 0; - fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; - fd->esync_fd = -1; -+ fd->fsync_idx = 0; - init_async_queue( &fd->read_q ); - init_async_queue( &fd->write_q ); - init_async_queue( &fd->wait_q ); - list_init( &fd->inode_entry ); - list_init( &fd->locks ); - -+ if (do_fsync()) -+ fd->fsync_idx = fsync_alloc_shm( 0, 0 ); -+ - if (do_esync()) - fd->esync_fd = esync_create_fd( 0, 0 ); -+ - return fd; - } - -@@ -2190,6 +2205,9 @@ void set_fd_signaled( struct fd *fd, int signaled ) - fd->signaled = signaled; - if (signaled) wake_up( fd->user, 0 ); - -+ if (do_fsync() && !signaled) -+ fsync_clear( fd->user ); -+ - if (do_esync() && !signaled) - esync_clear( fd->esync_fd ); - } -@@ -2232,6 +2250,15 @@ int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ) - return ret; - } - -+unsigned int default_fd_get_fsync_idx( struct object *obj, enum fsync_type *type ) -+{ -+ struct fd *fd = get_obj_fd( obj ); -+ unsigned int ret = fd->fsync_idx; -+ *type = FSYNC_MANUAL_SERVER; -+ release_object( fd ); -+ return ret; -+} -+ - int default_fd_get_poll_events( struct fd *fd ) - { - int events = 0; -diff --git a/server/file.c b/server/file.c -index 49c4ba32b42..829c8685d63 100644 ---- a/server/file.c -+++ b/server/file.c -@@ -112,6 +112,7 @@ static const struct object_ops file_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - file_get_fd, /* get_fd */ -diff --git a/server/file.h b/server/file.h -index cae0ac1e395..ed030af8d8f 100644 ---- a/server/file.h -+++ b/server/file.h -@@ -103,6 +103,7 @@ extern char *dup_fd_name( struct fd *root, const char *name ); - - extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); - extern int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ); -+extern unsigned int default_fd_get_fsync_idx( struct object *obj, enum fsync_type *type ); - extern int default_fd_get_poll_events( struct fd *fd ); - extern void default_poll_event( struct fd *fd, int event ); - extern void fd_queue_async( struct fd *fd, struct async *async, int type ); -diff --git a/server/fsync.c b/server/fsync.c -new file mode 100644 -index 00000000000..0a88ecdd3f6 ---- /dev/null -+++ b/server/fsync.c -@@ -0,0 +1,524 @@ -+/* -+ * futex-based synchronization objects -+ * -+ * Copyright (C) 2018 Zebediah Figura -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#include "config.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef HAVE_SYS_STAT_H -+# include -+#endif -+#ifdef HAVE_SYS_SYSCALL_H -+# include -+#endif -+#include -+ -+#include "ntstatus.h" -+#define WIN32_NO_STATUS -+#include "windef.h" -+#include "winternl.h" -+ -+#include "handle.h" -+#include "request.h" -+#include "fsync.h" -+ -+#include "pshpack4.h" -+struct futex_wait_block -+{ -+ int *addr; -+#if __SIZEOF_POINTER__ == 4 -+ int pad; -+#endif -+ int val; -+}; -+#include "poppack.h" -+ -+static inline int futex_wait_multiple( const struct futex_wait_block *futexes, -+ int count, const struct timespec *timeout ) -+{ -+ return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); -+} -+ -+int do_fsync(void) -+{ -+#ifdef __linux__ -+ static int do_fsync_cached = -1; -+ -+ if (do_fsync_cached == -1) -+ { -+ static const struct timespec zero; -+ futex_wait_multiple( NULL, 0, &zero ); -+ do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; -+ } -+ -+ return do_fsync_cached; -+#else -+ return 0; -+#endif -+} -+ -+static char shm_name[29]; -+static int shm_fd; -+static off_t shm_size; -+static void **shm_addrs; -+static int shm_addrs_size; /* length of the allocated shm_addrs array */ -+static long pagesize; -+ -+static int is_fsync_initialized; -+ -+static void shm_cleanup(void) -+{ -+ close( shm_fd ); -+ if (shm_unlink( shm_name ) == -1) -+ perror( "shm_unlink" ); -+} -+ -+void fsync_init(void) -+{ -+ struct stat st; -+ -+ if (fstat( config_dir_fd, &st ) == -1) -+ fatal_error( "cannot stat config dir\n" ); -+ -+ if (st.st_ino != (unsigned long)st.st_ino) -+ sprintf( shm_name, "/wine-%lx%08lx-fsync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); -+ else -+ sprintf( shm_name, "/wine-%lx-fsync", (unsigned long)st.st_ino ); -+ -+ if (!shm_unlink( shm_name )) -+ fprintf( stderr, "fsync: warning: a previous shm file %s was not properly removed\n", shm_name ); -+ -+ shm_fd = shm_open( shm_name, O_RDWR | O_CREAT | O_EXCL, 0644 ); -+ if (shm_fd == -1) -+ perror( "shm_open" ); -+ -+ pagesize = sysconf( _SC_PAGESIZE ); -+ -+ shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); -+ shm_addrs_size = 128; -+ -+ shm_size = pagesize; -+ if (ftruncate( shm_fd, shm_size ) == -1) -+ perror( "ftruncate" ); -+ -+ is_fsync_initialized = 1; -+ -+ fprintf( stderr, "fsync: up and running.\n" ); -+ -+ atexit( shm_cleanup ); -+} -+ -+static struct list mutex_list = LIST_INIT(mutex_list); -+ -+struct fsync -+{ -+ struct object obj; -+ unsigned int shm_idx; -+ enum fsync_type type; -+ struct list mutex_entry; -+}; -+ -+static void fsync_dump( struct object *obj, int verbose ); -+static unsigned int fsync_get_fsync_idx( struct object *obj, enum fsync_type *type ); -+static unsigned int fsync_map_access( struct object *obj, unsigned int access ); -+static void fsync_destroy( struct object *obj ); -+ -+const struct object_ops fsync_ops = -+{ -+ sizeof(struct fsync), /* size */ -+ &no_type, /* type */ -+ fsync_dump, /* dump */ -+ no_add_queue, /* add_queue */ -+ NULL, /* remove_queue */ -+ NULL, /* signaled */ -+ NULL, /* get_esync_fd */ -+ fsync_get_fsync_idx, /* get_fsync_idx */ -+ NULL, /* satisfied */ -+ no_signal, /* signal */ -+ no_get_fd, /* get_fd */ -+ fsync_map_access, /* map_access */ -+ default_get_sd, /* get_sd */ -+ default_set_sd, /* set_sd */ -+ no_get_full_name, /* get_full_name */ -+ no_lookup_name, /* lookup_name */ -+ directory_link_name, /* link_name */ -+ default_unlink_name, /* unlink_name */ -+ no_open_file, /* open_file */ -+ no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_close_handle, /* close_handle */ -+ fsync_destroy /* destroy */ -+}; -+ -+static void fsync_dump( struct object *obj, int verbose ) -+{ -+ struct fsync *fsync = (struct fsync *)obj; -+ assert( obj->ops == &fsync_ops ); -+ fprintf( stderr, "fsync idx=%d\n", fsync->shm_idx ); -+} -+ -+static unsigned int fsync_get_fsync_idx( struct object *obj, enum fsync_type *type) -+{ -+ struct fsync *fsync = (struct fsync *)obj; -+ *type = fsync->type; -+ return fsync->shm_idx; -+} -+ -+static unsigned int fsync_map_access( struct object *obj, unsigned int access ) -+{ -+ /* Sync objects have the same flags. */ -+ if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | EVENT_QUERY_STATE; -+ if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE; -+ if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE; -+ if (access & GENERIC_ALL) access |= STANDARD_RIGHTS_ALL | EVENT_QUERY_STATE | EVENT_MODIFY_STATE; -+ return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); -+} -+ -+static void fsync_destroy( struct object *obj ) -+{ -+ struct fsync *fsync = (struct fsync *)obj; -+ if (fsync->type == FSYNC_MUTEX) -+ list_remove( &fsync->mutex_entry ); -+} -+ -+static void *get_shm( unsigned int idx ) -+{ -+ int entry = (idx * 8) / pagesize; -+ int offset = (idx * 8) % pagesize; -+ -+ if (entry >= shm_addrs_size) -+ { -+ int new_size = max(shm_addrs_size * 2, entry + 1); -+ -+ if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) -+ fprintf( stderr, "fsync: couldn't expand shm_addrs array to size %d\n", entry + 1 ); -+ -+ memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); -+ -+ shm_addrs_size = new_size; -+ } -+ -+ if (!shm_addrs[entry]) -+ { -+ void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); -+ if (addr == (void *)-1) -+ { -+ fprintf( stderr, "fsync: failed to map page %d (offset %#lx): ", entry, entry * pagesize ); -+ perror( "mmap" ); -+ } -+ -+ if (debug_level) -+ fprintf( stderr, "fsync: Mapping page %d at %p.\n", entry, addr ); -+ -+ if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) -+ munmap( addr, pagesize ); /* someone beat us to it */ -+ } -+ -+ return (void *)((unsigned long)shm_addrs[entry] + offset); -+} -+ -+/* FIXME: This is rather inefficient... */ -+static unsigned int shm_idx_counter = 1; -+ -+unsigned int fsync_alloc_shm( int low, int high ) -+{ -+#ifdef __linux__ -+ int shm_idx; -+ int *shm; -+ -+ /* this is arguably a bit of a hack, but we need some way to prevent -+ * allocating shm for the master socket */ -+ if (!is_fsync_initialized) -+ return 0; -+ -+ shm_idx = shm_idx_counter++; -+ -+ while (shm_idx * 8 >= shm_size) -+ { -+ /* Better expand the shm section. */ -+ shm_size += pagesize; -+ if (ftruncate( shm_fd, shm_size ) == -1) -+ { -+ fprintf( stderr, "fsync: couldn't expand %s to size %jd: ", -+ shm_name, shm_size ); -+ perror( "ftruncate" ); -+ } -+ } -+ -+ shm = get_shm( shm_idx ); -+ assert(shm); -+ shm[0] = low; -+ shm[1] = high; -+ -+ return shm_idx; -+#else -+ return 0; -+#endif -+} -+ -+static int type_matches( enum fsync_type type1, enum fsync_type type2 ) -+{ -+ return (type1 == type2) || -+ ((type1 == FSYNC_AUTO_EVENT || type1 == FSYNC_MANUAL_EVENT) && -+ (type2 == FSYNC_AUTO_EVENT || type2 == FSYNC_MANUAL_EVENT)); -+} -+ -+struct fsync *create_fsync( struct object *root, const struct unicode_str *name, -+ unsigned int attr, int low, int high, enum fsync_type type, -+ const struct security_descriptor *sd ) -+{ -+#ifdef __linux__ -+ struct fsync *fsync; -+ -+ if ((fsync = create_named_object( root, &fsync_ops, name, attr, sd ))) -+ { -+ if (get_error() != STATUS_OBJECT_NAME_EXISTS) -+ { -+ /* initialize it if it didn't already exist */ -+ -+ /* Initialize the shared memory portion. We want to do this on the -+ * server side to avoid a potential though unlikely race whereby -+ * the same object is opened and used between the time it's created -+ * and the time its shared memory portion is initialized. */ -+ -+ fsync->shm_idx = fsync_alloc_shm( low, high ); -+ fsync->type = type; -+ if (type == FSYNC_MUTEX) -+ list_add_tail( &mutex_list, &fsync->mutex_entry ); -+ } -+ else -+ { -+ /* validate the type */ -+ if (!type_matches( type, fsync->type )) -+ { -+ release_object( &fsync->obj ); -+ set_error( STATUS_OBJECT_TYPE_MISMATCH ); -+ return NULL; -+ } -+ } -+ } -+ -+ return fsync; -+#else -+ set_error( STATUS_NOT_IMPLEMENTED ); -+ return NULL; -+#endif -+} -+ -+static inline int futex_wake( int *addr, int val ) -+{ -+ return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); -+} -+ -+/* shm layout for events or event-like objects. */ -+struct fsync_event -+{ -+ int signaled; -+ int unused; -+}; -+ -+void fsync_wake_futex( unsigned int shm_idx ) -+{ -+ struct fsync_event *event; -+ -+ if (debug_level) -+ fprintf( stderr, "fsync_wake_futex: index %u\n", shm_idx ); -+ -+ if (!shm_idx) -+ return; -+ -+ event = get_shm( shm_idx ); -+ if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) -+ futex_wake( &event->signaled, INT_MAX ); -+} -+ -+void fsync_wake_up( struct object *obj ) -+{ -+ enum fsync_type type; -+ -+ if (debug_level) -+ fprintf( stderr, "fsync_wake_up: object %p\n", obj ); -+ -+ if (obj->ops->get_fsync_idx) -+ fsync_wake_futex( obj->ops->get_fsync_idx( obj, &type ) ); -+} -+ -+void fsync_clear_futex( unsigned int shm_idx ) -+{ -+ struct fsync_event *event; -+ -+ if (debug_level) -+ fprintf( stderr, "fsync_clear_futex: index %u\n", shm_idx ); -+ -+ if (!shm_idx) -+ return; -+ -+ event = get_shm( shm_idx ); -+ __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); -+} -+ -+void fsync_clear( struct object *obj ) -+{ -+ enum fsync_type type; -+ -+ if (debug_level) -+ fprintf( stderr, "fsync_clear: object %p\n", obj ); -+ -+ if (obj->ops->get_fsync_idx) -+ fsync_clear_futex( obj->ops->get_fsync_idx( obj, &type ) ); -+} -+ -+void fsync_set_event( struct fsync *fsync ) -+{ -+ struct fsync_event *event = get_shm( fsync->shm_idx ); -+ assert( fsync->obj.ops == &fsync_ops ); -+ -+ if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) -+ futex_wake( &event->signaled, INT_MAX ); -+} -+ -+void fsync_reset_event( struct fsync *fsync ) -+{ -+ struct fsync_event *event = get_shm( fsync->shm_idx ); -+ assert( fsync->obj.ops == &fsync_ops ); -+ -+ __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); -+} -+ -+struct mutex -+{ -+ int tid; -+ int count; /* recursion count */ -+}; -+ -+void fsync_abandon_mutexes( struct thread *thread ) -+{ -+ struct fsync *fsync; -+ -+ LIST_FOR_EACH_ENTRY( fsync, &mutex_list, struct fsync, mutex_entry ) -+ { -+ struct mutex *mutex = get_shm( fsync->shm_idx ); -+ -+ if (mutex->tid == thread->id) -+ { -+ if (debug_level) -+ fprintf( stderr, "fsync_abandon_mutexes() idx=%d\n", fsync->shm_idx ); -+ mutex->tid = ~0; -+ mutex->count = 0; -+ futex_wake( &mutex->tid, INT_MAX ); -+ } -+ } -+} -+ -+DECL_HANDLER(create_fsync) -+{ -+ struct fsync *fsync; -+ struct unicode_str name; -+ struct object *root; -+ const struct security_descriptor *sd; -+ const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); -+ -+ if (!do_fsync()) -+ { -+ set_error( STATUS_NOT_IMPLEMENTED ); -+ return; -+ } -+ -+ if (!objattr) return; -+ -+ if ((fsync = create_fsync( root, &name, objattr->attributes, req->low, -+ req->high, req->type, sd ))) -+ { -+ if (get_error() == STATUS_OBJECT_NAME_EXISTS) -+ reply->handle = alloc_handle( current->process, fsync, req->access, objattr->attributes ); -+ else -+ reply->handle = alloc_handle_no_access_check( current->process, fsync, -+ req->access, objattr->attributes ); -+ -+ reply->shm_idx = fsync->shm_idx; -+ reply->type = fsync->type; -+ release_object( fsync ); -+ } -+ -+ if (root) release_object( root ); -+} -+ -+DECL_HANDLER(open_fsync) -+{ -+ struct unicode_str name = get_req_unicode_str(); -+ -+ reply->handle = open_object( current->process, req->rootdir, req->access, -+ &fsync_ops, &name, req->attributes ); -+ -+ if (reply->handle) -+ { -+ struct fsync *fsync; -+ -+ if (!(fsync = (struct fsync *)get_handle_obj( current->process, reply->handle, -+ 0, &fsync_ops ))) -+ return; -+ -+ if (!type_matches( req->type, fsync->type )) -+ { -+ set_error( STATUS_OBJECT_TYPE_MISMATCH ); -+ release_object( fsync ); -+ return; -+ } -+ -+ reply->type = fsync->type; -+ reply->shm_idx = fsync->shm_idx; -+ release_object( fsync ); -+ } -+} -+ -+/* Retrieve the index of a shm section which will be signaled by the server. */ -+DECL_HANDLER(get_fsync_idx) -+{ -+ struct object *obj; -+ enum fsync_type type; -+ -+ if (!(obj = get_handle_obj( current->process, req->handle, SYNCHRONIZE, NULL ))) -+ return; -+ -+ if (obj->ops->get_fsync_idx) -+ { -+ reply->shm_idx = obj->ops->get_fsync_idx( obj, &type ); -+ reply->type = type; -+ } -+ else -+ { -+ if (debug_level) -+ { -+ fprintf( stderr, "%04x: fsync: can't wait on object: ", current->id ); -+ obj->ops->dump( obj, 0 ); -+ } -+ set_error( STATUS_NOT_IMPLEMENTED ); -+ } -+ -+ release_object( obj ); -+} -+ -+DECL_HANDLER(get_fsync_apc_idx) -+{ -+ reply->shm_idx = current->fsync_apc_idx; -+} -diff --git a/server/fsync.h b/server/fsync.h -new file mode 100644 -index 00000000000..a91939b7f0a ---- /dev/null -+++ b/server/fsync.h -@@ -0,0 +1,34 @@ -+/* -+ * futex-based synchronization objects -+ * -+ * Copyright (C) 2018 Zebediah Figura -+ * -+ * 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 -+ */ -+ -+extern int do_fsync(void); -+extern void fsync_init(void); -+extern unsigned int fsync_alloc_shm( int low, int high ); -+extern void fsync_wake_futex( unsigned int shm_idx ); -+extern void fsync_clear_futex( unsigned int shm_idx ); -+extern void fsync_wake_up( struct object *obj ); -+extern void fsync_clear( struct object *obj ); -+ -+struct fsync; -+ -+extern const struct object_ops fsync_ops; -+extern void fsync_set_event( struct fsync *fsync ); -+extern void fsync_reset_event( struct fsync *fsync ); -+extern void fsync_abandon_mutexes( struct thread *thread ); -diff --git a/server/handle.c b/server/handle.c -index cb5628b7e06..ff44446acc9 100644 ---- a/server/handle.c -+++ b/server/handle.c -@@ -124,6 +124,7 @@ static const struct object_ops handle_table_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/hook.c b/server/hook.c -index 61b5014c442..379f9c074d5 100644 ---- a/server/hook.c -+++ b/server/hook.c -@@ -82,6 +82,7 @@ static const struct object_ops hook_table_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/mailslot.c b/server/mailslot.c -index 18fef4b0466..b541524c9a4 100644 ---- a/server/mailslot.c -+++ b/server/mailslot.c -@@ -79,6 +79,7 @@ static const struct object_ops mailslot_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - mailslot_get_fd, /* get_fd */ -@@ -138,6 +139,7 @@ static const struct object_ops mail_writer_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - mail_writer_get_fd, /* get_fd */ -@@ -202,6 +204,7 @@ static const struct object_ops mailslot_device_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -233,6 +236,7 @@ static const struct object_ops mailslot_device_file_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - mailslot_device_file_get_fd, /* get_fd */ -diff --git a/server/main.c b/server/main.c -index 3e02cbb3832..7a09436b637 100644 ---- a/server/main.c -+++ b/server/main.c -@@ -37,6 +37,7 @@ - #include "thread.h" - #include "request.h" - #include "esync.h" -+#include "fsync.h" - - /* command-line options */ - int debug_level = 0; -@@ -141,8 +142,14 @@ int main( int argc, char *argv[] ) - sock_init(); - open_master_socket(); - -+ if (do_fsync()) -+ fsync_init(); -+ - if (do_esync()) - esync_init(); -+ -+ if (!do_fsync() && !do_esync()) -+ fprintf( stderr, "wineserver: using server-side synchronization.\n" ); - - if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() ); - set_current_time(); -diff --git a/server/mapping.c b/server/mapping.c -index 10def3ca694..d55df5145f7 100644 ---- a/server/mapping.c -+++ b/server/mapping.c -@@ -69,6 +69,7 @@ static const struct object_ops ranges_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -106,6 +107,7 @@ static const struct object_ops shared_map_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -165,6 +167,7 @@ static const struct object_ops mapping_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - mapping_get_fd, /* get_fd */ -diff --git a/server/mutex.c b/server/mutex.c -index 1235ab4731f..ccdc383f0df 100644 ---- a/server/mutex.c -+++ b/server/mutex.c -@@ -62,6 +62,7 @@ static const struct object_ops mutex_ops = - remove_queue, /* remove_queue */ - mutex_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - mutex_satisfied, /* satisfied */ - mutex_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/named_pipe.c b/server/named_pipe.c -index e59a5b6c183..d0ea32a24d5 100644 ---- a/server/named_pipe.c -+++ b/server/named_pipe.c -@@ -119,6 +119,7 @@ static const struct object_ops named_pipe_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -164,6 +165,7 @@ static const struct object_ops pipe_server_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - default_fd_get_esync_fd, /* get_esync_fd */ -+ default_fd_get_fsync_idx, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - pipe_end_get_fd, /* get_fd */ -@@ -208,6 +210,7 @@ static const struct object_ops pipe_client_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - default_fd_get_esync_fd, /* get_esync_fd */ -+ default_fd_get_fsync_idx, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - pipe_end_get_fd, /* get_fd */ -@@ -256,6 +259,7 @@ static const struct object_ops named_pipe_device_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -288,6 +292,7 @@ static const struct object_ops named_pipe_device_file_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - named_pipe_device_file_get_fd, /* get_fd */ -diff --git a/server/object.h b/server/object.h -index 5b6bb9cbfe1..4c92b174ef3 100644 ---- a/server/object.h -+++ b/server/object.h -@@ -70,6 +70,8 @@ struct object_ops - int (*signaled)(struct object *,struct wait_queue_entry *); - /* return the esync fd for this object */ - int (*get_esync_fd)(struct object *, enum esync_type *type); -+ /* return the fsync shm idx for this object */ -+ unsigned int (*get_fsync_idx)(struct object *, enum fsync_type *type); - /* wait satisfied */ - void (*satisfied)(struct object *,struct wait_queue_entry *); - /* signal an object */ -diff --git a/server/process.c b/server/process.c -index df50955f621..c4f51dcad30 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -50,6 +50,7 @@ - #include "user.h" - #include "security.h" - #include "esync.h" -+#include "fsync.h" - - /* process object */ - -@@ -70,6 +71,7 @@ static void process_poll_event( struct fd *fd, int event ); - static struct list *process_get_kernel_obj_list( struct object *obj ); - static void process_destroy( struct object *obj ); - static int process_get_esync_fd( struct object *obj, enum esync_type *type ); -+static unsigned int process_get_fsync_idx( struct object *obj, enum fsync_type *type ); - static void terminate_process( struct process *process, struct thread *skip, int exit_code ); - - static const struct object_ops process_ops = -@@ -81,6 +83,7 @@ static const struct object_ops process_ops = - remove_queue, /* remove_queue */ - process_signaled, /* signaled */ - process_get_esync_fd, /* get_esync_fd */ -+ process_get_fsync_idx, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -133,6 +136,7 @@ static const struct object_ops startup_info_ops = - remove_queue, /* remove_queue */ - startup_info_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -180,6 +184,7 @@ static const struct object_ops job_ops = - remove_queue, /* remove_queue */ - job_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -547,6 +552,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all, - process->rawinput_mouse = NULL; - process->rawinput_kbd = NULL; - process->esync_fd = -1; -+ process->fsync_idx = 0; - list_init( &process->kernel_object ); - list_init( &process->thread_list ); - list_init( &process->locks ); -@@ -603,6 +609,9 @@ struct process *create_process( int fd, struct process *parent, int inherit_all, - if (!token_assign_label( process->token, security_high_label_sid )) - goto error; - -+ if (do_fsync()) -+ process->fsync_idx = fsync_alloc_shm( 0, 0 ); -+ - if (do_esync()) - process->esync_fd = esync_create_fd( 0, 0 ); - -@@ -685,6 +694,13 @@ static int process_get_esync_fd( struct object *obj, enum esync_type *type ) - return process->esync_fd; - } - -+static unsigned int process_get_fsync_idx( struct object *obj, enum fsync_type *type ) -+{ -+ struct process *process = (struct process *)obj; -+ *type = FSYNC_MANUAL_SERVER; -+ return process->fsync_idx; -+} -+ - static unsigned int process_map_access( struct object *obj, unsigned int access ) - { - access = default_map_access( obj, access ); -diff --git a/server/process.h b/server/process.h -index eec69ddbcaf..abb4ed31b48 100644 ---- a/server/process.h -+++ b/server/process.h -@@ -99,6 +99,7 @@ struct process - const struct rawinput_device *rawinput_kbd; /* rawinput keyboard device, if any */ - struct list kernel_object; /* list of kernel object pointers */ - int esync_fd; /* esync file descriptor (signaled on exit) */ -+ unsigned int fsync_idx; - }; - - #define CPU_FLAG(cpu) (1 << (cpu)) -diff --git a/server/protocol.def b/server/protocol.def -index 2a8662354f6..381bd8d8218 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -3766,3 +3766,57 @@ enum esync_type - /* Retrieve the fd to wait on for user APCs. */ - @REQ(get_esync_apc_fd) - @END -+ -+enum fsync_type -+{ -+ FSYNC_SEMAPHORE = 1, -+ FSYNC_AUTO_EVENT, -+ FSYNC_MANUAL_EVENT, -+ FSYNC_MUTEX, -+ FSYNC_AUTO_SERVER, -+ FSYNC_MANUAL_SERVER, -+ FSYNC_QUEUE, -+}; -+ -+/* Create a new futex-based synchronization object */ -+@REQ(create_fsync) -+ unsigned int access; /* wanted access rights */ -+ int low; /* initial value of low word */ -+ int high; /* initial value of high word */ -+ int type; /* type of fsync object */ -+ VARARG(objattr,object_attributes); /* object attributes */ -+@REPLY -+ obj_handle_t handle; /* handle to the object */ -+ int type; /* type of fsync object */ -+ unsigned int shm_idx; /* this object's index into the shm section */ -+@END -+ -+/* Open an fsync object */ -+@REQ(open_fsync) -+ unsigned int access; /* wanted access rights */ -+ unsigned int attributes; /* object attributes */ -+ obj_handle_t rootdir; /* root directory */ -+ int type; /* type of fsync object */ -+ VARARG(name,unicode_str); /* object name */ -+@REPLY -+ obj_handle_t handle; /* handle to the event */ -+ int type; /* type of fsync object */ -+ unsigned int shm_idx; /* this object's index into the shm section */ -+@END -+ -+/* Retrieve the shm index for an object. */ -+@REQ(get_fsync_idx) -+ obj_handle_t handle; /* handle to the object */ -+@REPLY -+ int type; -+ unsigned int shm_idx; -+@END -+ -+@REQ(fsync_msgwait) -+ int in_msgwait; /* are we in a message wait? */ -+@END -+ -+@REQ(get_fsync_apc_idx) -+@REPLY -+ unsigned int shm_idx; -+@END -diff --git a/server/queue.c b/server/queue.c -index a78748b96ca..dccf43197cf 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -44,6 +44,7 @@ - #include "request.h" - #include "user.h" - #include "esync.h" -+#include "fsync.h" - - #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE - #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST)) -@@ -147,6 +148,8 @@ struct msg_queue - unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */ - int esync_fd; /* esync file descriptor (signalled on message) */ - int esync_in_msgwait; /* our thread is currently waiting on us */ -+ unsigned int fsync_idx; -+ int fsync_in_msgwait; /* our thread is currently waiting on us */ - }; - - struct hotkey -@@ -164,6 +167,7 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent - static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry ); - static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry ); - static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ); -+static unsigned int msg_queue_get_fsync_idx( struct object *obj, enum fsync_type *type ); - static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ); - static void msg_queue_destroy( struct object *obj ); - static void msg_queue_poll_event( struct fd *fd, int event ); -@@ -180,6 +184,7 @@ static const struct object_ops msg_queue_ops = - msg_queue_remove_queue, /* remove_queue */ - msg_queue_signaled, /* signaled */ - msg_queue_get_esync_fd, /* get_esync_fd */ -+ msg_queue_get_fsync_idx, /* get_fsync_idx */ - msg_queue_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -218,6 +223,7 @@ static const struct object_ops thread_input_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -321,12 +327,17 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ - queue->ignore_post_msg = 0; - queue->esync_fd = -1; - queue->esync_in_msgwait = 0; -+ queue->fsync_idx = 0; -+ queue->fsync_in_msgwait = 0; - list_init( &queue->send_result ); - list_init( &queue->callback_result ); - list_init( &queue->pending_timers ); - list_init( &queue->expired_timers ); - for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] ); - -+ if (do_fsync()) -+ queue->fsync_idx = fsync_alloc_shm( 0, 0 ); -+ - if (do_esync()) - queue->esync_fd = esync_create_fd( 0, 0 ); - -@@ -509,6 +520,9 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits - queue->keystate_lock = 0; - } - -+ if (do_fsync() && !is_signaled( queue )) -+ fsync_clear( &queue->obj ); -+ - if (do_esync() && !is_signaled( queue )) - esync_clear( queue->esync_fd ); - } -@@ -970,6 +984,9 @@ static int is_queue_hung( struct msg_queue *queue ) - return 0; /* thread is waiting on queue -> not hung */ - } - -+ if (do_fsync() && queue->fsync_in_msgwait) -+ return 0; /* thread is waiting on queue in absentia -> not hung */ -+ - if (do_esync() && queue->esync_in_msgwait) - return 0; /* thread is waiting on queue in absentia -> not hung */ - -@@ -1035,6 +1052,13 @@ static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ) - return queue->esync_fd; - } - -+static unsigned int msg_queue_get_fsync_idx( struct object *obj, enum fsync_type *type ) -+{ -+ struct msg_queue *queue = (struct msg_queue *)obj; -+ *type = FSYNC_QUEUE; -+ return queue->fsync_idx; -+} -+ - static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ) - { - struct msg_queue *queue = (struct msg_queue *)obj; -@@ -2517,6 +2541,9 @@ DECL_HANDLER(get_queue_status) - reply->changed_bits = queue->changed_bits; - queue->changed_bits &= ~req->clear_bits; - -+ if (do_fsync() && !is_signaled( queue )) -+ fsync_clear( &queue->obj ); -+ - if (do_esync() && !is_signaled( queue )) - esync_clear( queue->esync_fd ); - } -@@ -3536,3 +3563,18 @@ DECL_HANDLER(esync_msgwait) - if (queue->fd) - set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); - } -+ -+DECL_HANDLER(fsync_msgwait) -+{ -+ struct msg_queue *queue = get_current_queue(); -+ -+ if (!queue) return; -+ queue->fsync_in_msgwait = req->in_msgwait; -+ -+ if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT)) -+ set_event( current->process->idle_event ); -+ -+ /* and start/stop waiting on the driver */ -+ if (queue->fd) -+ set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); -+} -diff --git a/server/registry.c b/server/registry.c -index 996bff5ef6d..50b600b4853 100644 ---- a/server/registry.c -+++ b/server/registry.c -@@ -168,6 +168,7 @@ static const struct object_ops key_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/request.c b/server/request.c -index 20b0ec309f3..9fd08139375 100644 ---- a/server/request.c -+++ b/server/request.c -@@ -97,6 +97,7 @@ static const struct object_ops master_socket_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/semaphore.c b/server/semaphore.c -index d7d3a24e48f..604721d0d5f 100644 ---- a/server/semaphore.c -+++ b/server/semaphore.c -@@ -59,6 +59,7 @@ static const struct object_ops semaphore_ops = - remove_queue, /* remove_queue */ - semaphore_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - semaphore_satisfied, /* satisfied */ - semaphore_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/serial.c b/server/serial.c -index a50ace9903f..78d33460892 100644 ---- a/server/serial.c -+++ b/server/serial.c -@@ -93,6 +93,7 @@ static const struct object_ops serial_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - serial_get_fd, /* get_fd */ -diff --git a/server/signal.c b/server/signal.c -index b6d6dcfc4b6..f5ac61b6975 100644 ---- a/server/signal.c -+++ b/server/signal.c -@@ -68,6 +68,7 @@ static const struct object_ops handler_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/sock.c b/server/sock.c -index c2dfa8fb8ce..080efc98942 100644 ---- a/server/sock.c -+++ b/server/sock.c -@@ -173,6 +173,7 @@ static const struct object_ops sock_ops = - remove_queue, /* remove_queue */ - default_fd_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - sock_get_fd, /* get_fd */ -@@ -1175,6 +1176,7 @@ static const struct object_ops ifchange_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - ifchange_get_fd, /* get_fd */ -@@ -1396,6 +1398,7 @@ static const struct object_ops socket_device_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/symlink.c b/server/symlink.c -index 07f3c924f25..0e3e9ee9864 100644 ---- a/server/symlink.c -+++ b/server/symlink.c -@@ -61,6 +61,7 @@ static const struct object_ops symlink_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/thread.c b/server/thread.c -index 1a245c58396..1fb3603f2a7 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -52,6 +52,7 @@ - #include "user.h" - #include "security.h" - #include "esync.h" -+#include "fsync.h" - - - #ifdef __i386__ -@@ -112,6 +113,7 @@ static const struct object_ops thread_apc_ops = - remove_queue, /* remove_queue */ - thread_apc_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -150,6 +152,7 @@ static const struct object_ops context_ops = - remove_queue, /* remove_queue */ - context_signaled, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -173,6 +176,7 @@ - static void dump_thread( struct object *obj, int verbose ); - static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ); - static int thread_get_esync_fd( struct object *obj, enum esync_type *type ); -+static unsigned int thread_get_fsync_idx( struct object *obj, enum fsync_type *type ); - static unsigned int thread_map_access( struct object *obj, unsigned int access ); - static void thread_poll_event( struct fd *fd, int event ); - static struct list *thread_get_kernel_obj_list( struct object *obj ); -@@ -187,6 +191,7 @@ static const struct object_ops thread_ops = - remove_queue, /* remove_queue */ - thread_signaled, /* signaled */ - thread_get_esync_fd, /* get_esync_fd */ -+ thread_get_fsync_idx, /* get_fsync_idx */ - no_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -228,6 +233,7 @@ static inline void init_thread_structure( struct thread *thread ) - thread->entry_point = 0; - thread->esync_fd = -1; - thread->esync_apc_fd = -1; -+ thread->fsync_idx = 0; - thread->system_regs = 0; - thread->queue = NULL; - thread->wait = NULL; -@@ -364,6 +370,12 @@ struct thread *create_thread( int fd, struct process *process, const struct secu - return NULL; - } - -+ if (do_fsync()) -+ { -+ thread->fsync_idx = fsync_alloc_shm( 0, 0 ); -+ thread->fsync_apc_idx = fsync_alloc_shm( 0, 0 ); -+ } -+ - if (do_esync()) - { - thread->esync_fd = esync_create_fd( 0, 0 ); -@@ -484,6 +496,13 @@ static int thread_get_esync_fd( struct object *obj, enum esync_type *type ) - return thread->esync_fd; - } - -+static unsigned int thread_get_fsync_idx( struct object *obj, enum fsync_type *type ) -+{ -+ struct thread *thread = (struct thread *)obj; -+ *type = FSYNC_MANUAL_SERVER; -+ return thread->fsync_idx; -+} -+ - static unsigned int thread_map_access( struct object *obj, unsigned int access ) - { - access = default_map_access( obj, access ); -@@ -533,6 +552,7 @@ static struct thread_apc *create_apc( struct object *owner, const apc_call_t *ca - apc->result.type = APC_NONE; - if (owner) grab_object( owner ); - } -+ - return apc; - } - -@@ -1068,6 +1088,9 @@ void wake_up( struct object *obj, int max ) - struct list *ptr; - int ret; - -+ if (do_fsync()) -+ fsync_wake_up( obj ); -+ - if (do_esync()) - esync_wake_up( obj ); - -@@ -1158,6 +1181,9 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr - { - wake_thread( thread ); - -+ if (do_fsync() && queue == &thread->user_apc) -+ fsync_wake_futex( thread->fsync_apc_idx ); -+ - if (do_esync() && queue == &thread->user_apc) - esync_wake_fd( thread->esync_apc_fd ); - } -@@ -1208,6 +1234,9 @@ static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system - list_remove( ptr ); - } - -+ if (do_fsync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc )) -+ fsync_clear_futex( thread->fsync_apc_idx ); -+ - if (do_esync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc )) - esync_clear( thread->esync_apc_fd ); - -@@ -1327,6 +1356,8 @@ void kill_thread( struct thread *thread, int violent_death ) - } - kill_console_processes( thread, 0 ); - abandon_mutexes( thread ); -+ if (do_fsync()) -+ fsync_abandon_mutexes( thread ); - if (do_esync()) - esync_abandon_mutexes( thread ); - if (violent_death) -diff --git a/server/thread.h b/server/thread.h -index 0f6108b684a..53627631343 100644 ---- a/server/thread.h -+++ b/server/thread.h -@@ -56,6 +56,8 @@ struct thread - struct list mutex_list; /* list of currently owned mutexes */ - int esync_fd; /* esync file descriptor (signalled on exit) */ - int esync_apc_fd; /* esync apc fd (signalled when APCs are present) */ -+ unsigned int fsync_idx; -+ unsigned int fsync_apc_idx; - unsigned int system_regs; /* which system regs have been set */ - struct msg_queue *queue; /* message queue */ - struct thread_wait *wait; /* current wait condition if sleeping */ -diff --git a/server/timer.c b/server/timer.c -index dcbc9e2ece5..9d9d7b8b40c 100644 ---- a/server/timer.c -+++ b/server/timer.c -@@ -37,6 +37,7 @@ - #include "handle.h" - #include "request.h" - #include "esync.h" -+#include "fsync.h" - - static const WCHAR timer_name[] = {'T','i','m','e','r'}; - -@@ -50,11 +51,13 @@ struct timer - client_ptr_t callback; /* callback APC function */ - client_ptr_t arg; /* callback argument */ - int esync_fd; /* esync file descriptor */ -+ unsigned int fsync_idx; /* fsync shm index */ - }; - - static void timer_dump( struct object *obj, int verbose ); - static int timer_signaled( struct object *obj, struct wait_queue_entry *entry ); - static int timer_get_esync_fd( struct object *obj, enum esync_type *type ); -+static unsigned int timer_get_fsync_idx( struct object *obj, enum fsync_type *type ); - static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ); - static void timer_destroy( struct object *obj ); - -@@ -69,6 +72,7 @@ static const struct object_ops timer_ops = - remove_queue, /* remove_queue */ - timer_signaled, /* signaled */ - timer_get_esync_fd, /* get_esync_fd */ -+ timer_get_fsync_idx, /* get_fsync_idx */ - timer_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -105,6 +109,9 @@ static struct timer *create_timer( struct object *root, const struct unicode_str - timer->thread = NULL; - timer->esync_fd = -1; - -+ if (do_fsync()) -+ timer->fsync_idx = fsync_alloc_shm( 0, 0 ); -+ - if (do_esync()) - timer->esync_fd = esync_create_fd( 0, 0 ); - } -@@ -181,6 +188,9 @@ static int set_timer( struct timer *timer, timeout_t expire, unsigned int period - period = 0; /* period doesn't make any sense for a manual timer */ - timer->signaled = 0; - -+ if (do_fsync()) -+ fsync_clear( &timer->obj ); -+ - if (do_esync()) - esync_clear( timer->esync_fd ); - } -@@ -223,6 +233,13 @@ static int timer_get_esync_fd( struct object *obj, enum esync_type *type ) - return timer->esync_fd; - } - -+static unsigned int timer_get_fsync_idx( struct object *obj, enum fsync_type *type ) -+{ -+ struct timer *timer = (struct timer *)obj; -+ *type = timer->manual ? FSYNC_MANUAL_SERVER : FSYNC_AUTO_SERVER; -+ return timer->fsync_idx; -+} -+ - static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ) - { - struct timer *timer = (struct timer *)obj; -diff --git a/server/token.c b/server/token.c -index 0f128728b0f..5a80b6fd50e 100644 ---- a/server/token.c -+++ b/server/token.c -@@ -148,6 +148,7 @@ static const struct object_ops token_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -diff --git a/server/winstation.c b/server/winstation.c -index 1a031248a7c..388b116bc67 100644 ---- a/server/winstation.c -+++ b/server/winstation.c -@@ -65,6 +65,7 @@ static const struct object_ops winstation_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -@@ -91,6 +92,7 @@ static const struct object_ops desktop_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -From fba9f1e54417eb8096fe7967b94dc17508969ef7 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 1 Apr 2021 20:19:35 +0300 -Subject: [PATCH] esync, fsync: Yield execution before alertable wait for AC - Odyssey. - -CW-Bug-ID: #18881 ---- - dlls/ntdll/unix/esync.c | 11 +++++++++++ - dlls/ntdll/unix/fsync.c | 9 +++++++++ - dlls/ntdll/unix/loader.c | 21 +++++++++++++++++++++ - dlls/ntdll/unix/unix_private.h | 2 ++ - 4 files changed, 43 insertions(+) - -diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c -index 29d65d275c4..55c5695964d 100644 ---- a/dlls/ntdll/unix/esync.c -+++ b/dlls/ntdll/unix/esync.c -@@ -948,6 +948,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA - - if (event->signaled) - { -+ if (ac_odyssey && alertable) -+ usleep( 0 ); - if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) - { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); -@@ -963,6 +965,12 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA - - if (event->signaled) - { -+ if (ac_odyssey && alertable) -+ { -+ usleep( 0 ); -+ if (!event->signaled) -+ break; -+ } - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - return i; - } -@@ -991,6 +999,9 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA - - while (1) - { -+ if (ac_odyssey && alertable) -+ usleep( 0 ); -+ - ret = do_poll( fds, pollcount, timeout ? &end : NULL ); - if (ret > 0) - { -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index 8b54f82a5f5..39d969f061d 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -925,6 +925,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - { - if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) - { -+ if (ac_odyssey && alertable) -+ usleep( 0 ); -+ - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - return i; - } -@@ -944,6 +947,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - { - if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) - { -+ if (ac_odyssey && alertable) -+ usleep( 0 ); -+ - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - return i; - } -@@ -974,6 +980,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - - /* Looks like everything is contended, so wait. */ - -+ if (ac_odyssey && alertable) -+ usleep( 0 ); -+ - if (timeout && !timeout->QuadPart) - { - /* Unlike esync, we already know that we've timed out, so we -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 3790baa9fae..7f3d7834a6c 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -2194,6 +2194,26 @@ static struct unix_funcs unix_funcs = - write_crash_log, - }; - -+BOOL ac_odyssey; -+ -+static void hacks_init(void) -+{ -+ static const char ac_odyssey_exe[] = "ACOdyssey.exe"; -+ char cur_exe[MAX_PATH]; -+ DWORD cur_exe_len; -+ int fd; -+ -+ fd = open("/proc/self/comm", O_RDONLY); -+ cur_exe_len = read(fd, cur_exe, sizeof(cur_exe)); -+ close(fd); -+ cur_exe[cur_exe_len - 1] = 0; -+ -+ if (!strcasecmp(cur_exe, ac_odyssey_exe)) -+ { -+ ERR("HACK: AC Odyssey sync tweak on.\n"); -+ ac_odyssey = TRUE; -+ } -+} - - /*********************************************************************** - * start_main_thread -@@ -2209,6 +2229,7 @@ static void start_main_thread(void) - signal_init_thread( teb ); - dbg_init(); - startup_info_size = server_init_process(); -+ hacks_init(); - fsync_init(); - esync_init(); - virtual_map_user_shared_data(); -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index 61d41c817ac..8e2e7d93a38 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -146,6 +146,8 @@ extern BOOL is_wow64 DECLSPEC_HIDDEN; - extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN; - #endif - -+extern BOOL ac_odyssey DECLSPEC_HIDDEN; -+ - extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; - extern void init_startup_info(void) DECLSPEC_HIDDEN; - extern void *create_startup_info( const UNICODE_STRING *nt_image, const RTL_USER_PROCESS_PARAMETERS *params, -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index e565c324eef..999eb3e23e1 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -1820,6 +1820,26 @@ static struct unix_funcs unix_funcs = - steamclient_setup_trampolines, - }; - -+BOOL ac_odyssey; -+ -+static void hacks_init(void) -+{ -+ static const char ac_odyssey_exe[] = "ACOdyssey.exe"; -+ char cur_exe[MAX_PATH]; -+ DWORD cur_exe_len; -+ int fd; -+ -+ fd = open("/proc/self/comm", O_RDONLY); -+ cur_exe_len = read(fd, cur_exe, sizeof(cur_exe)); -+ close(fd); -+ cur_exe[cur_exe_len - 1] = 0; -+ -+ if (!strcasecmp(cur_exe, ac_odyssey_exe)) -+ { -+ ERR("HACK: AC Odyssey sync tweak on.\n"); -+ ac_odyssey = TRUE; -+ } -+} - - /*********************************************************************** - * start_main_thread -@@ -1834,6 +1854,7 @@ static void start_main_thread(void) - signal_init_thread( teb ); - dbg_init(); - startup_info_size = server_init_process(); -+ hacks_init(); - fsync_init(); - esync_init(); - virtual_map_user_shared_data(); -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index 65801df3a61..d8499efa00d 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -137,6 +137,8 @@ extern SYSTEM_CPU_INFORMATION cpu_info DECLSPEC_HIDDEN; - extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN; - #endif - -+extern BOOL ac_odyssey DECLSPEC_HIDDEN; -+ - extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; - extern void init_startup_info(void) DECLSPEC_HIDDEN; - extern DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen ) DECLSPEC_HIDDEN; -diff --git a/server/window.c b/server/window.c -index bc8e049f40a..de9d4b04ece 100644 ---- a/server/window.c -+++ b/server/window.c -@@ -109,6 +109,7 @@ static const struct object_ops window_ops = - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_fd */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ -From 69afcb164ccf8d3ecd5e94cf79c1e31698e14e5c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 2 Feb 2022 17:02:44 -0500 -Subject: [PATCH] esync: Type-check HANDLE in esync_set_event. - -Signed-off-by: Derek Lesho ---- - dlls/ntdll/unix/esync.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c -index 55c5695964d..4663374653a 100644 ---- a/dlls/ntdll/unix/esync.c -+++ b/dlls/ntdll/unix/esync.c -@@ -526,6 +526,9 @@ NTSTATUS esync_set_event( HANDLE handle ) - if ((ret = get_object( handle, &obj ))) return ret; - event = obj->shm; - -+ if (obj->type != ESYNC_MANUAL_EVENT && obj->type != ESYNC_AUTO_EVENT) -+ return STATUS_OBJECT_TYPE_MISMATCH; -+ - if (obj->type == ESYNC_MANUAL_EVENT) - { - /* Acquire the spinlock. */ - -From f072cf6366aa8385efdcb4a7b4c49e122f00b750 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 14 Feb 2022 12:51:27 -0500 -Subject: [PATCH] fsync: Type-check HANDLE in esync_set_event. - -Signed-off-by: Derek Lesho ---- - dlls/ntdll/unix/fsync.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index 39d969f061d..d468782667a 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -576,6 +576,9 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) - if ((ret = get_object( handle, &obj ))) return ret; - event = obj->shm; - -+ if (obj->type != FSYNC_MANUAL_EVENT && obj->type != FSYNC_AUTO_EVENT) -+ return STATUS_OBJECT_TYPE_MISMATCH; -+ - if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) - futex_wake( &event->signaled, INT_MAX ); - diff --git a/patches/proton/04-proton-LAA_staging.patch b/patches/proton/04-proton-LAA_staging.patch deleted file mode 100755 index 1cb3a3718..000000000 --- a/patches/proton/04-proton-LAA_staging.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 6a1159fd49718165c61100ea70b0054d5a484ea6 Mon Sep 17 00:00:00 2001 -From: Steven Noonan -Date: Wed, 17 Oct 2018 04:13:37 -0700 -Subject: [PATCH] ntdll/loader: add support for overriding - IMAGE_FILE_LARGE_ADDRESS_AWARE - -Signed-off-by: Steven Noonan ---- - dlls/kernel32/heap.c | 9 ++++++++- - dlls/ntdll/ntdll.spec | 1 + - dlls/ntdll/unix/server.c | 3 ++- - dlls/ntdll/unix/unix_private.h | 2 ++ - dlls/ntdll/unix/virtual.c | 13 +++++++++++++ - 5 files changed, 26 insertions(+), 2 deletions(-) - -diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c -index b7bd6f5f91d..fef060e9c22 100644 ---- a/dlls/kernel32/heap.c -+++ b/dlls/kernel32/heap.c -@@ -44,6 +44,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(globalmem); - - static HANDLE systemHeap; /* globally shared heap */ - -+extern BOOL CDECL __wine_needs_override_large_address_aware(void); -+ - - /*********************************************************************** - * HEAP_CreateSystemHeap -@@ -544,6 +546,10 @@ VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) - #ifndef _WIN64 - IMAGE_NT_HEADERS *nt = RtlImageNtHeader( GetModuleHandleW(0) ); - #endif -+ static int force_large_address_aware = -1; -+ -+ if (force_large_address_aware == -1) -+ force_large_address_aware = __wine_needs_override_large_address_aware(); - - /* Because GlobalMemoryStatus is identical to GlobalMemoryStatusEX save - for one extra field in the struct, and the lack of a bug, we simply -@@ -584,7 +590,8 @@ VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer ) - - /* values are limited to 2Gb unless the app has the IMAGE_FILE_LARGE_ADDRESS_AWARE flag */ - /* page file sizes are not limited (Adobe Illustrator 8 depends on this) */ -- if (!(nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) -+ if (!(nt->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) && -+ !force_large_address_aware) - { - if (lpBuffer->dwTotalPhys > MAXLONG) lpBuffer->dwTotalPhys = MAXLONG; - if (lpBuffer->dwAvailPhys > MAXLONG) lpBuffer->dwAvailPhys = MAXLONG; -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index ca427c46c04..10327373959 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -1625,6 +1625,9 @@ - @ cdecl -norelay __wine_dbg_output(str) - @ cdecl -norelay __wine_dbg_strdup(str) - -+# Virtual memory -+@ cdecl -syscall __wine_needs_override_large_address_aware() -+ - # Version - @ cdecl wine_get_version() - @ cdecl wine_get_build_id() -diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c -index 7236f0acb83..e34abd88093 100644 ---- a/dlls/ntdll/unix/server.c -+++ b/dlls/ntdll/unix/server.c -@@ -1471,8 +1471,8 @@ void server_init_process_done(void) - #ifdef __APPLE__ - send_server_task_port(); - #endif -- if (main_image_info.ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) -- virtual_set_large_address_space(); -+ if (main_image_info.ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE -+ || __wine_needs_override_large_address_aware()) virtual_set_large_address_space(); - - /* Install signal handlers; this cannot be done earlier, since we cannot - * send exceptions to the debugger before the create process event that -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index c3ad0a41098..e0326f88a21 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -470,4 +470,6 @@ static inline int ntdll_wcsnicmp( const WCHAR *str1, const WCHAR *str2, int n ) - #define towupper(c) ntdll_towupper(c) - #define towlower(c) ntdll_towlower(c) - -+BOOL CDECL __wine_needs_override_large_address_aware(void); -+ - #endif /* __NTDLL_UNIX_PRIVATE_H */ -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index 1337e2de861..200a777eb5c 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -3420,6 +3420,19 @@ void CDECL virtual_release_address_space(void) - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - } - -+BOOL CDECL __wine_needs_override_large_address_aware(void) -+{ -+ static int needs_override = -1; -+ -+ if (needs_override == -1) -+ { -+ const char *str = getenv( "WINE_LARGE_ADDRESS_AWARE" ); -+ -+ needs_override = !str || atoi(str) == 1; -+ } -+ return needs_override; -+} -+ - - /*********************************************************************** - * virtual_set_large_address_space --- -2.26.2 - -From 67150fb21e93e2a1d40047355de3c8c7ff2d73ca Mon Sep 17 00:00:00 2001 -From: Tk-Glitch -Date: Wed, 1 Sep 2021 15:58:29 +0200 -Subject: Add LAA syscall to ntdll loader array following ea6308e364b669adfcb8b1e448c8b08d715bcf6d - - -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 75266672f0b..428e13fea1f 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -347,6 +349,7 @@ static void * const syscalls[] = - NtWriteVirtualMemory, - NtYieldExecution, - __wine_dbg_write, -+ __wine_needs_override_large_address_aware, - __wine_unix_call, - wine_nt_to_unix_file_name, - wine_server_call, diff --git a/patches/proton/08-proton-steamclient_swap.patch b/patches/proton/08-proton-steamclient_swap.patch deleted file mode 100755 index 5caadd67e..000000000 --- a/patches/proton/08-proton-steamclient_swap.patch +++ /dev/null @@ -1,600 +0,0 @@ -From b9bb042502857bf088bdde3cdb0f998b6fbdcedc Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 13 Jun 2017 12:35:56 -0500 -Subject: [PATCH] HACK: steam: ntdll: Append C:/Program Files (x86)/Steam to - PATH. - ---- - dlls/ntdll/loader.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c -index bf072af84ac..15d6dde0377 100644 ---- a/dlls/ntdll/loader.c -+++ b/dlls/ntdll/loader.c -@@ -84,7 +84,7 @@ const WCHAR system_dir[] = L"C:\\windows\\system32\\"; - HMODULE kernel32_handle = 0; - - /* system search path */ --static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows"; -+static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows;C:\\Program Files (x86)\\Steam"; - - static BOOL is_prefix_bootstrap; /* are we bootstrapping the prefix? */ - static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */ -From 6fa5dfc0bd079bd18e1f457b1e6ae0bcf7eb383d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 5 Nov 2021 23:37:54 +0100 -Subject: [PATCH] HACK: steam: ntdll: Setup steamclient trampolines to - lsteamclient. - -This uses exec page faults to jump from native steamclient into our -lsteamclient entry points. ---- - dlls/ntdll/loader.c | 22 +++++++++++ - dlls/ntdll/unix/loader.c | 67 +++++++++++++++++++++++++++++++++ - dlls/ntdll/unix/signal_i386.c | 7 ++++ - dlls/ntdll/unix/signal_x86_64.c | 7 ++++ - dlls/ntdll/unix/unix_private.h | 3 ++ - dlls/ntdll/unixlib.h | 3 ++ - 6 files changed, 109 insertions(+) - -diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c -index 15d6dde0377..62987663d98 100644 ---- a/dlls/ntdll/loader.c -+++ b/dlls/ntdll/loader.c -@@ -2000,12 +2000,16 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, - DWORD flags, BOOL system, WINE_MODREF **pwm ) - { - static const char builtin_signature[] = "Wine builtin DLL"; -+ static HMODULE lsteamclient = NULL; - char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1); -+ UNICODE_STRING lsteamclient_us; - BOOL is_builtin; - IMAGE_NT_HEADERS *nt; - WINE_MODREF *wm; - NTSTATUS status; - SIZE_T map_size; -+ WCHAR *basename, *tmp; -+ ULONG basename_len; - - if (!(nt = RtlImageNtHeader( *module ))) return STATUS_INVALID_IMAGE_FORMAT; - -@@ -2026,6 +2030,24 @@ static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, - - set_security_cookie( *module, map_size ); - -+ basename = nt_name->Buffer; -+ if ((tmp = wcsrchr(basename, '\\'))) basename = tmp + 1; -+ if ((tmp = wcsrchr(basename, '/'))) basename = tmp + 1; -+ basename_len = wcslen(basename); -+ if (basename_len >= 4 && !wcscmp(basename + basename_len - 4, L".dll")) basename_len -= 4; -+ -+ if ((!RtlCompareUnicodeStrings(basename, basename_len, L"steamclient", 11, TRUE) || -+ !RtlCompareUnicodeStrings(basename, basename_len, L"steamclient64", 13, TRUE) || -+ !RtlCompareUnicodeStrings(basename, basename_len, L"gameoverlayrenderer", 19, TRUE) || -+ !RtlCompareUnicodeStrings(basename, basename_len, L"gameoverlayrenderer64", 21, TRUE)) && -+ RtlCreateUnicodeStringFromAsciiz(&lsteamclient_us, "lsteamclient.dll") && -+ (lsteamclient || LdrLoadDll(load_path, 0, &lsteamclient_us, &lsteamclient) == STATUS_SUCCESS)) -+ { -+ unix_funcs->steamclient_setup_trampolines( *module, lsteamclient ); -+ wm->ldr.Flags |= LDR_DONT_RESOLVE_REFS; -+ flags |= DONT_RESOLVE_DLL_REFERENCES; -+ } -+ - /* fixup imports */ - - if (!(flags & DONT_RESOLVE_DLL_REFERENCES) && -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 5dcab3455a0..ecf3cf33947 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -2057,6 +2057,72 @@ static ULONG_PTR get_image_address(void) - } - - -+static void *steamclient_srcs[128]; -+static void *steamclient_tgts[128]; -+static int steamclient_count; -+ -+void *steamclient_handle_fault( LPCVOID addr, DWORD err ) -+{ -+ int i; -+ -+ if (!(err & EXCEPTION_EXECUTE_FAULT)) return NULL; -+ -+ for (i = 0; i < steamclient_count; ++i) -+ { -+ if (addr == steamclient_srcs[i]) -+ return steamclient_tgts[i]; -+ } -+ -+ return NULL; -+} -+ -+static void CDECL steamclient_setup_trampolines(HMODULE src_mod, HMODULE tgt_mod) -+{ -+ SYSTEM_BASIC_INFORMATION info; -+ IMAGE_NT_HEADERS *src_nt = (IMAGE_NT_HEADERS *)((UINT_PTR)src_mod + ((IMAGE_DOS_HEADER *)src_mod)->e_lfanew); -+ IMAGE_NT_HEADERS *tgt_nt = (IMAGE_NT_HEADERS *)((UINT_PTR)tgt_mod + ((IMAGE_DOS_HEADER *)tgt_mod)->e_lfanew); -+ IMAGE_SECTION_HEADER *src_sec = (IMAGE_SECTION_HEADER *)(src_nt + 1); -+ const IMAGE_EXPORT_DIRECTORY *src_exp, *tgt_exp; -+ const DWORD *names; -+ SIZE_T size; -+ void *addr, *src_addr, *tgt_addr; -+ char *name; -+ UINT_PTR page_mask; -+ int i; -+ -+ virtual_get_system_info( &info, !!NtCurrentTeb()->WowTebOffset ); -+ page_mask = info.PageSize - 1; -+ -+ for (i = 0; i < src_nt->FileHeader.NumberOfSections; ++i) -+ { -+ if (memcmp(src_sec[i].Name, ".text", 5)) continue; -+ addr = (void *)(((UINT_PTR)src_mod + src_sec[i].VirtualAddress) & ~page_mask); -+ size = (src_sec[i].Misc.VirtualSize + page_mask) & ~page_mask; -+ mprotect(addr, size, PROT_READ); -+ } -+ -+ src_exp = get_module_data_dir( src_mod, IMAGE_FILE_EXPORT_DIRECTORY, NULL ); -+ tgt_exp = get_module_data_dir( tgt_mod, IMAGE_FILE_EXPORT_DIRECTORY, NULL ); -+ names = (const DWORD *)((UINT_PTR)src_mod + src_exp->AddressOfNames); -+ for (i = 0; i < src_exp->NumberOfNames; ++i) -+ { -+ if (!names[i] || !(name = (char *)((UINT_PTR)src_mod + names[i]))) continue; -+ if (!(src_addr = (void *)find_named_export(src_mod, src_exp, name))) continue; -+ if (!(tgt_addr = (void *)find_named_export(tgt_mod, tgt_exp, name))) continue; -+ assert(steamclient_count < ARRAY_SIZE(steamclient_srcs)); -+ steamclient_srcs[steamclient_count] = src_addr; -+ steamclient_tgts[steamclient_count] = tgt_addr; -+ steamclient_count++; -+ } -+ -+ src_addr = (void *)((UINT_PTR)src_mod + src_nt->OptionalHeader.AddressOfEntryPoint); -+ tgt_addr = (void *)((UINT_PTR)tgt_mod + tgt_nt->OptionalHeader.AddressOfEntryPoint); -+ assert(steamclient_count < ARRAY_SIZE(steamclient_srcs)); -+ steamclient_srcs[steamclient_count] = src_addr; -+ steamclient_tgts[steamclient_count] = tgt_addr; -+ steamclient_count++; -+} -+ - /*********************************************************************** - * unix_funcs - */ -@@ -2069,6 +2135,7 @@ static struct unix_funcs unix_funcs = - #ifdef __aarch64__ - NtCurrentTeb, - #endif -+ steamclient_setup_trampolines, - }; - - -diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c -index 6bb5649e2b5..4f471ffb03b 100644 ---- a/dlls/ntdll/unix/signal_i386.c -+++ b/dlls/ntdll/unix/signal_i386.c -@@ -1781,6 +1781,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) - struct xcontext xcontext; - ucontext_t *ucontext = sigcontext; - void *stack = setup_exception_record( sigcontext, &rec, &xcontext ); -+ void *steamclient_addr = NULL; - - switch (TRAP_sig(ucontext)) - { -@@ -1815,6 +1816,12 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) - } - break; - case TRAP_x86_PAGEFLT: /* Page fault */ -+ if ((steamclient_addr = steamclient_handle_fault( siginfo->si_addr, (ERROR_sig(ucontext) >> 1) & 0x09 ))) -+ { -+ EIP_sig(ucontext) = (intptr_t)steamclient_addr; -+ return; -+ } -+ - rec.NumberParameters = 2; - rec.ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09; - rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 68e0c7ce66e..aa5dd47d789 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -2559,6 +2559,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) - EXCEPTION_RECORD rec = { 0 }; - struct xcontext context; - ucontext_t *ucontext = sigcontext; -+ void *steamclient_addr = NULL; - - rec.ExceptionAddress = (void *)RIP_sig(ucontext); - save_context( &context, sigcontext ); -@@ -2590,6 +2591,12 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) - } - break; - case TRAP_x86_PAGEFLT: /* Page fault */ -+ if ((steamclient_addr = steamclient_handle_fault( siginfo->si_addr, (ERROR_sig(ucontext) >> 1) & 0x09 ))) -+ { -+ RIP_sig(ucontext) = (intptr_t)steamclient_addr; -+ return; -+ } -+ - rec.NumberParameters = 2; - rec.ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09; - rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index e736dd3c456..aee0103dd59 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -195,6 +195,9 @@ extern NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct o - - extern void *anon_mmap_fixed( void *start, size_t size, int prot, int flags ) DECLSPEC_HIDDEN; - extern void *anon_mmap_alloc( size_t size, int prot ) DECLSPEC_HIDDEN; -+ -+extern void *steamclient_handle_fault( LPCVOID addr, DWORD err ) DECLSPEC_HIDDEN; -+ - extern void virtual_init(void) DECLSPEC_HIDDEN; - extern ULONG_PTR get_system_affinity_mask(void) DECLSPEC_HIDDEN; - extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info, BOOL wow64 ) DECLSPEC_HIDDEN; -diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h -index cb184431f82..8aca8fe31c3 100644 ---- a/dlls/ntdll/unixlib.h -+++ b/dlls/ntdll/unixlib.h -@@ -40,6 +40,9 @@ struct unix_funcs - #ifdef __aarch64__ - TEB * (WINAPI *NtCurrentTeb)(void); - #endif -+ -+ /* steamclient HACK */ -+ void (CDECL *steamclient_setup_trampolines)( HMODULE src_mod, HMODULE tgt_mod ); - }; - - #endif /* __NTDLL_UNIXLIB_H */ -From b25e4e6251675172321a561e1398874fd2dd0126 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 5 Aug 2020 10:35:50 +0200 -Subject: [PATCH] HACK: steam: ntdll: Patch entry points with jumps. - -As a preferred alternative to noexec pages which makes debugging -painful. The noexec can be enabled with WINESTEAMNOEXEC=1 environmnent -variable. ---- - dlls/ntdll/unix/loader.c | 29 +++++++++++++++++++++++++---- - 1 file changed, 25 insertions(+), 4 deletions(-) - -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index ecf3cf33947..5390b8f6779 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -2076,8 +2076,23 @@ void *steamclient_handle_fault( LPCVOID addr, DWORD err ) - return NULL; - } - -+static void steamclient_write_jump(void *src_addr, void *tgt_addr) -+{ -+#ifdef _WIN64 -+ static const char mov[] = {0x48, 0xb8}; -+#else -+ static const char mov[] = {0xb8}; -+#endif -+ static const char jmp[] = {0xff, 0xe0}; -+ memcpy(src_addr, mov, sizeof(mov)); -+ memcpy((char *)src_addr + sizeof(mov), &tgt_addr, sizeof(tgt_addr)); -+ memcpy((char *)src_addr + sizeof(mov) + sizeof(tgt_addr), jmp, sizeof(jmp)); -+} -+ - static void CDECL steamclient_setup_trampolines(HMODULE src_mod, HMODULE tgt_mod) - { -+ static int noexec_cached = -1; -+ - SYSTEM_BASIC_INFORMATION info; - IMAGE_NT_HEADERS *src_nt = (IMAGE_NT_HEADERS *)((UINT_PTR)src_mod + ((IMAGE_DOS_HEADER *)src_mod)->e_lfanew); - IMAGE_NT_HEADERS *tgt_nt = (IMAGE_NT_HEADERS *)((UINT_PTR)tgt_mod + ((IMAGE_DOS_HEADER *)tgt_mod)->e_lfanew); -@@ -2086,10 +2101,13 @@ static void CDECL steamclient_setup_trampolines(HMODULE src_mod, HMODULE tgt_mod - const DWORD *names; - SIZE_T size; - void *addr, *src_addr, *tgt_addr; -- char *name; -+ char *name, *wsne; - UINT_PTR page_mask; - int i; - -+ if (noexec_cached == -1) -+ noexec_cached = (wsne = getenv("WINESTEAMNOEXEC")) && atoi(wsne); -+ - virtual_get_system_info( &info, !!NtCurrentTeb()->WowTebOffset ); - page_mask = info.PageSize - 1; - -@@ -2098,7 +2116,8 @@ static void CDECL steamclient_setup_trampolines(HMODULE src_mod, HMODULE tgt_mod - if (memcmp(src_sec[i].Name, ".text", 5)) continue; - addr = (void *)(((UINT_PTR)src_mod + src_sec[i].VirtualAddress) & ~page_mask); - size = (src_sec[i].Misc.VirtualSize + page_mask) & ~page_mask; -- mprotect(addr, size, PROT_READ); -+ if (noexec_cached) mprotect(addr, size, PROT_READ); -+ else mprotect(addr, size, PROT_READ|PROT_WRITE|PROT_EXEC); - } - - src_exp = get_module_data_dir( src_mod, IMAGE_FILE_EXPORT_DIRECTORY, NULL ); -@@ -2112,7 +2131,8 @@ static void CDECL steamclient_setup_trampolines(HMODULE src_mod, HMODULE tgt_mod - assert(steamclient_count < ARRAY_SIZE(steamclient_srcs)); - steamclient_srcs[steamclient_count] = src_addr; - steamclient_tgts[steamclient_count] = tgt_addr; -- steamclient_count++; -+ if (!noexec_cached) steamclient_write_jump(src_addr, tgt_addr); -+ else steamclient_count++; - } - - src_addr = (void *)((UINT_PTR)src_mod + src_nt->OptionalHeader.AddressOfEntryPoint); -@@ -2120,7 +2140,8 @@ static void CDECL steamclient_setup_trampolines(HMODULE src_mod, HMODULE tgt_mod - assert(steamclient_count < ARRAY_SIZE(steamclient_srcs)); - steamclient_srcs[steamclient_count] = src_addr; - steamclient_tgts[steamclient_count] = tgt_addr; -- steamclient_count++; -+ if (!noexec_cached) steamclient_write_jump(src_addr, tgt_addr); -+ else steamclient_count++; - } - - /*********************************************************************** -From 901e614e8f3d8913e7f75ccd6cdbabbd0502c53f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 18 Dec 2019 13:49:00 +0100 -Subject: [PATCH] HACK: proton: ntdll: Strip gameoverlayrenderer.so from - LD_PRELOAD before executing explorer.exe. - -Work around a bug in gameoverlayrenderer which introduces 50ms hangs -during XCheckIfEvent after approx 40 minutes of gameplay. - -The original user32 hack broke Steam overlay in Origin games, and Steam -Input consequently. This ntdll implementation should be safer as it'll -modify the environment after the new process has started forking. - -Link: https://github.com/ValveSoftware/Proton/issues/3316 -CW-Bug-Id: #18946 ---- - dlls/ntdll/unix/loader.c | 31 +++++++++++++++++++++++++++++++ - 1 file changed, 31 insertions(+) - -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index a7e79a828ca..3df74d45bd7 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -725,6 +725,7 @@ NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_i - ULONGLONG res_end = pe_info->base + pe_info->map_size; - const char *loader = argv0; - const char *loader_env = getenv( "WINELOADER" ); -+ const char *ld_preload = getenv( "LD_PRELOAD" ); - char preloader_reserve[64], socket_env[64]; - BOOL is_child_64bit; - -@@ -759,6 +760,36 @@ NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_i - else loader = is_child_64bit ? "wine64" : "wine"; - } - -+ /* HACK: Unset LD_PRELOAD before executing explorer.exe to disable buggy gameoverlayrenderer.so */ -+ if (ld_preload && argv[2] && !strcmp( argv[2], "C:\\windows\\system32\\explorer.exe" ) && -+ argv[3] && !strcmp( argv[3], "/desktop" )) -+ { -+ static char const gorso[] = "gameoverlayrenderer.so"; -+ static int gorso_len = sizeof(gorso) - 1; -+ int len = strlen( ld_preload ); -+ char *next, *tmp, *env = malloc( sizeof("LD_PRELOAD=") + len ); -+ -+ if (!env) return STATUS_NO_MEMORY; -+ strcpy( env, "LD_PRELOAD=" ); -+ strcat( env, ld_preload ); -+ -+ tmp = env + 11; -+ do -+ { -+ if (!(next = strchr( tmp, ':' ))) next = tmp + strlen( tmp ); -+ if (next - tmp >= gorso_len && strncmp( next - gorso_len, gorso, gorso_len ) == 0) -+ { -+ if (*next) memmove( tmp, next + 1, strlen(next) ); -+ else *tmp = 0; -+ next = tmp; -+ } -+ else tmp = next + 1; -+ } -+ while (*next); -+ -+ putenv( env ); -+ } -+ - signal( SIGPIPE, SIG_DFL ); - - sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd ); -From bf6233be8f8b7c2e729daa91160dd41fbbb3c64e Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 5 Apr 2021 13:20:41 -0500 -Subject: [PATCH] HACK: proton: ntdll: Export a function to set a Unix - environment variable - ---- - dlls/ntdll/env.c | 5 +++++ - dlls/ntdll/ntdll.spec | 1 + - dlls/ntdll/unix/env.c | 5 +++++ - dlls/ntdll/unix/loader.c | 1 + - dlls/ntdll/unix/unix_private.h | 2 ++ - dlls/ntdll/unixlib.h | 1 + - include/wine/debug.h | 1 + - 7 files changed, 16 insertions(+) - -diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c -index bb8931a556b..0353d6dc501 100644 ---- a/dlls/ntdll/env.c -+++ b/dlls/ntdll/env.c -@@ -684,3 +684,8 @@ void init_user_process_params(void) - set_wow64_environment( &new_params->Environment ); - new_params->EnvironmentSize = RtlSizeHeap( GetProcessHeap(), 0, new_params->Environment ); - } -+ -+void __cdecl __wine_set_unix_env( const char *var, const char *val) -+{ -+ unix_funcs->set_unix_env( var, val ); -+} -diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec -index bd8e1f5efe6..e361fac3a3b 100644 ---- a/dlls/ntdll/ntdll.spec -+++ b/dlls/ntdll/ntdll.spec -@@ -1636,6 +1636,7 @@ - @ stdcall __wine_ctrl_routine(ptr) - @ extern __wine_syscall_dispatcher - @ extern -arch=i386 __wine_ldt_copy -+@ cdecl __wine_set_unix_env(ptr ptr) - - # Debugging - @ stdcall -syscall -norelay __wine_dbg_write(ptr long) -diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c -index c7e0674e083..c2c420100d1 100644 ---- a/dlls/ntdll/unix/env.c -+++ b/dlls/ntdll/unix/env.c -@@ -2616,3 +2616,8 @@ ULONG WINAPI RtlNtStatusToDosError( NTSTATUS status ) - - return map_status( status ); - } -+ -+void CDECL set_unix_env( const char *var, const char *val ) -+{ -+ setenv(var, val, 1); -+} -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 5390b8f6779..a7e79a828ca 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -2157,6 +2157,7 @@ static struct unix_funcs unix_funcs = - NtCurrentTeb, - #endif - steamclient_setup_trampolines, -+ set_unix_env, - }; - - -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index aee0103dd59..25e1445be44 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -290,6 +290,8 @@ extern void call_raise_user_exception_dispatcher(void) DECLSPEC_HIDDEN; - - #define IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE 0x0010 /* Wine extension */ - -+extern void CDECL set_unix_env(const char *var, const char *val) DECLSPEC_HIDDEN; -+ - #define TICKSPERSEC 10000000 - #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)86400) - -diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h -index 8aca8fe31c3..595c3931904 100644 ---- a/dlls/ntdll/unixlib.h -+++ b/dlls/ntdll/unixlib.h -@@ -43,6 +43,7 @@ struct unix_funcs - - /* steamclient HACK */ - void (CDECL *steamclient_setup_trampolines)( HMODULE src_mod, HMODULE tgt_mod ); -+ void (CDECL *set_unix_env)( const char *var, const char *val ); - }; - - #endif /* __NTDLL_UNIXLIB_H */ -diff --git a/include/wine/debug.h b/include/wine/debug.h -index 6aac7fe82e8..bc2b1ec0c40 100644 ---- a/include/wine/debug.h -+++ b/include/wine/debug.h -@@ -149,6 +149,7 @@ extern const char * __cdecl __wine_dbg_strdup( const char *str ); - extern int __cdecl __wine_dbg_output( const char *str ); - extern int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_channel *channel, - const char *function ); -+extern void __cdecl __wine_set_unix_env( const char *var, const char *val ); - - /* - * Exported definitions and macros - -From a1dde27690950aeb4728f0f3783b4d04d608b5c0 Mon Sep 17 00:00:00 2001 -From: Vincent Povirk -Date: Wed, 1 Apr 2020 11:47:05 -0500 -Subject: [PATCH] winebrowser: Restore original LD_LIBRARY_PATH before calling - to system - ---- - dlls/ntdll/unix/env.c | 3 ++- - programs/winebrowser/main.c | 16 ++++++++++++++++ - 2 files changed, 18 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c -index 45e18dbccaf..6130ad23c15 100644 ---- a/dlls/ntdll/unix/env.c -+++ b/dlls/ntdll/unix/env.c -@@ -2620,5 +2620,6 @@ ULONG WINAPI RtlNtStatusToDosError( NTSTATUS status ) - - void CDECL set_unix_env( const char *var, const char *val ) - { -- setenv(var, val, 1); -+ if (!val) unsetenv(var); -+ else setenv(var, val, 1); - } -diff --git a/programs/winebrowser/main.c b/programs/winebrowser/main.c -index 913c0a8d672..df3f7425d65 100644 ---- a/programs/winebrowser/main.c -+++ b/programs/winebrowser/main.c -@@ -63,6 +63,17 @@ static char *strdup_unixcp( const WCHAR *str ) - return ret; - } - -+static void restore_system_environment(void) -+{ -+ const char* orig_ld_path = getenv("ORIG_LD_LIBRARY_PATH"); -+ -+ if (orig_ld_path) -+ { -+ __wine_set_unix_env("LD_LIBRARY_PATH", orig_ld_path); -+ __wine_set_unix_env("ORIG_LD_LIBRARY_PATH", NULL); -+ } -+} -+ - /* try to launch a unix app from a comma separated string of app names */ - static int launch_app( const WCHAR *candidates, const WCHAR *argv1 ) - { -@@ -72,6 +83,11 @@ static int launch_app( const WCHAR *candidates, const WCHAR *argv1 ) - - if (!(cmdline = strdup_unixcp( argv1 ))) return 1; - -+ /* PROTON HACK: Restore ORIG_LD_LIBRARY_PATH to LD_LIBRARY_PATH. -+ * System programs may not work correctly with our libraries, in -+ * particular gio on Ubuntu 19.04 is broken by our libgio. */ -+ restore_system_environment(); -+ - while (*candidates) - { - WCHAR **args = CommandLineToArgvW( candidates, &count ); -From a4048df6a5fec29d849bc2b11627d31f4cb01f3e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 11 Oct 2021 10:58:33 +0200 -Subject: [PATCH] ntdll: Use RTLD_NOLOAD to find already mapped modules. - -This makes it possible to detect modules that weren't unmapped from -dlclose, and that we should not fixup again. ---- - dlls/ntdll/unix/loader.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index de2270fb678..3790baa9fae 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -1303,9 +1303,11 @@ static NTSTATUS dlopen_dll( const char *so_name, UNICODE_STRING *nt_name, void * - { - void *module, *handle; - const IMAGE_NT_HEADERS *nt; -+ BOOL mapped = FALSE; - - callback_module = (void *)1; -- handle = dlopen( so_name, RTLD_NOW ); -+ if ((handle = dlopen( so_name, RTLD_NOW | RTLD_NOLOAD ))) mapped = TRUE; -+ else handle = dlopen( so_name, RTLD_NOW ); - if (!handle) - { - WARN( "failed to load .so lib %s: %s\n", debugstr_a(so_name), dlerror() ); -@@ -1322,7 +1324,7 @@ static NTSTATUS dlopen_dll( const char *so_name, UNICODE_STRING *nt_name, void * - { - module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff); - if (get_builtin_so_handle( module )) goto already_loaded; -- if (map_so_dll( nt, module )) -+ if (!mapped && map_so_dll( nt, module )) - { - dlclose( handle ); - return STATUS_NO_MEMORY; diff --git a/patches/proton/10-proton-protonify_staging.patch b/patches/proton/10-proton-protonify_staging.patch deleted file mode 100644 index 6b1880121..000000000 --- a/patches/proton/10-proton-protonify_staging.patch +++ /dev/null @@ -1,4175 +0,0 @@ -From 1091eaf13692b16ed66328ceeebfc587075fec6c Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 25 Oct 2018 12:50:45 -0500 -Subject: [PATCH] HACK: wined3d: Fake an AMD card in place of Nvidia cards - -Some games assume they can load the nvapi library if the hardware is an -nvidia card. This obviously fails in Wine. So fake that all nvidia -hardware is actually an AMD card, so they don't try to load nvapi. ---- - dlls/wined3d/adapter_gl.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/dlls/wined3d/adapter_gl.c b/dlls/wined3d/adapter_gl.c -index b8a2060cf46..8259d92ebac 100644 ---- a/dlls/wined3d/adapter_gl.c -+++ b/dlls/wined3d/adapter_gl.c -@@ -1009,6 +1009,14 @@ static const struct wined3d_gpu_description *query_gpu_description(const struct - vendor = wined3d_settings.pci_vendor_id; - TRACE("Overriding vendor PCI ID with 0x%04x.\n", vendor); - } -+ else if(vendor == HW_VENDOR_NVIDIA) -+ { -+ /* XXX: Fake having an AMD card in order to avoid games trying to load -+ * the Windows-only nvapi library. */ -+ WARN("Nvidia card detected. Faking an AMD RX 480!\n"); -+ vendor = HW_VENDOR_AMD; -+ device = CARD_AMD_RADEON_RX_480; -+ } - - if (wined3d_settings.pci_device_id != PCI_DEVICE_NONE) - { - -From aa7fa7ce94bd4e49e3843a8ea398d29882518e43 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 6 Aug 2018 08:06:03 -0500 -Subject: [PATCH] server: Set default timeout to 0 - -The Steam client will be waiting for the wineserver to exit to set up -some environment variables, so make it wait as short as possible. ---- - server/main.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/server/main.c b/server/main.c -index 20d3c48c4d9..aca8738c4c0 100644 ---- a/server/main.c -+++ b/server/main.c -@@ -42,7 +42,7 @@ - /* command-line options */ - int debug_level = 0; - int foreground = 0; --timeout_t master_socket_timeout = 3 * -TICKS_PER_SEC; /* master socket timeout, default is 3 seconds */ -+timeout_t master_socket_timeout = 0; /* master socket timeout, default is 3 seconds */ - const char *server_argv0; - - /* parse-line args */ - -From ba15ba1c9b8ee40e13ef1bd7f018924259f36c1b Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 18 Jun 2018 07:56:35 -0500 -Subject: [PATCH] ntdll: Notice THREADNAME_INFO exceptions and set thread name - on Linux - -Patch by Zeb. ---- - dlls/ntdll/unix/thread.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index 3b451a22577..ca5dac43bb0 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -43,6 +43,9 @@ - #ifdef HAVE_SYS_SYSCALL_H - #include - #endif -+#ifdef HAVE_PRCTL -+#include -+#endif - - #define NONAMELESSUNION - #include "ntstatus.h" -@@ -344,6 +347,16 @@ void wait_suspend( CONTEXT *context ) - } - - -+/* "How to: Set a Thread Name in Native Code" -+ * https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ -+typedef struct tagTHREADNAME_INFO -+{ -+ DWORD dwType; /* Must be 0x1000 */ -+ LPCSTR szName; /* Pointer to name - limited to 9 bytes (8 characters + terminator) */ -+ DWORD dwThreadID; /* Thread ID (-1 = caller thread) */ -+ DWORD dwFlags; /* Reserved for future use. Must be zero. */ -+} THREADNAME_INFO; -+ - /********************************************************************** - * send_debug_event - * -@@ -366,6 +379,21 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c - for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++) - params[i] = rec->ExceptionInformation[i]; - -+ if (rec->ExceptionCode == 0x406d1388) -+ { -+ const THREADNAME_INFO *threadname = (const THREADNAME_INFO *)rec->ExceptionInformation; -+ -+ if (threadname->dwThreadID == -1) -+ { -+#ifdef HAVE_PRCTL -+#ifndef PR_SET_NAME -+# define PR_SET_NAME 15 -+#endif -+ prctl( PR_SET_NAME, threadname->szName ); -+#endif -+ } -+ } -+ - SERVER_START_REQ( queue_exception_event ) - { - req->first = first_chance; -From 90e3616c89ef7ed38763a3e3af3e9f0cd59697da Mon Sep 17 00:00:00 2001 -From: Nikolay Sivov -Date: Wed, 8 Mar 2017 20:15:40 +0300 -Subject: [PATCH] HACK: dwrite: Don't recommend outline rendering mode - ---- - dlls/dwrite/font.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c -index e22559912c3..41ec809b727 100644 ---- a/dlls/dwrite/font.c -+++ b/dlls/dwrite/font.c -@@ -740,7 +740,8 @@ static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace - - ppem = emSize * ppdip; - -- if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) { -+ /* HACK: disable outline rendering mode to workaround d2d issue */ -+ if (0 && ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) { - *mode = DWRITE_RENDERING_MODE_OUTLINE; - return S_OK; - } -From 5c59517008697ce74becddb59a3e6702a963bb49 Mon Sep 17 00:00:00 2001 -From: Zhiyi Zhang -Date: Fri, 16 Aug 2019 09:46:25 +0000 -Subject: [PATCH] msctf: Use list to keep thread managers. - -Thread managers were stored in thread local storage, -which have a major flaw that they can't not be released -by another thread. - -Signed-off-by: Zhiyi Zhang ---- - dlls/msctf/msctf.c | 46 +++++++---------------- - dlls/msctf/msctf_internal.h | 1 - - dlls/msctf/threadmgr.c | 73 ++++++++++++++++++++++++++++++++----- - 3 files changed, 76 insertions(+), 44 deletions(-) - -diff --git a/dlls/msctf/msctf.c b/dlls/msctf/msctf.c -index c6e3a2ca597..fd919295c5a 100644 ---- a/dlls/msctf/msctf.c -+++ b/dlls/msctf/msctf.c -@@ -69,7 +69,6 @@ static UINT array_size; - static struct list AtsList = LIST_INIT(AtsList); - static UINT activated = 0; - --DWORD tlsIndex = 0; - TfClientId processId = 0; - ITfCompartmentMgr *globalCompartmentMgr = NULL; - -@@ -397,23 +396,19 @@ HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) - ActivatedTextService *actsvr; - ITfCategoryMgr *catmgr; - AtsEntry *entry; -- ITfThreadMgrEx *tm = TlsGetValue(tlsIndex); -+ ITfThreadMgr *tm; - ITfClientId *clientid; - -- if (!tm) return E_UNEXPECTED; -+ if (FAILED(TF_GetThreadMgr(&tm))) return E_UNEXPECTED; - - actsvr = HeapAlloc(GetProcessHeap(),0,sizeof(ActivatedTextService)); -- if (!actsvr) return E_OUTOFMEMORY; -+ if (!actsvr) goto fail; - -- ITfThreadMgrEx_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); -+ ITfThreadMgr_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); - ITfClientId_GetClientId(clientid, &lp->clsid, &actsvr->tid); - ITfClientId_Release(clientid); - -- if (!actsvr->tid) -- { -- HeapFree(GetProcessHeap(),0,actsvr); -- return E_OUTOFMEMORY; -- } -+ if (!actsvr->tid) goto fail; - - actsvr->pITfTextInputProcessor = NULL; - actsvr->LanguageProfile = *lp; -@@ -440,20 +435,21 @@ HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) - deactivate_remove_conflicting_ts(&actsvr->LanguageProfile.catid); - - if (activated > 0) -- activate_given_ts(actsvr, tm); -+ activate_given_ts(actsvr, (ITfThreadMgrEx *)tm); - - entry = HeapAlloc(GetProcessHeap(),0,sizeof(AtsEntry)); -- -- if (!entry) -- { -- HeapFree(GetProcessHeap(),0,actsvr); -- return E_OUTOFMEMORY; -- } -+ if (!entry) goto fail; - - entry->ats = actsvr; - list_add_head(&AtsList, &entry->entry); - -+ ITfThreadMgr_Release(tm); - return S_OK; -+ -+fail: -+ ITfThreadMgr_Release(tm); -+ HeapFree(GetProcessHeap(), 0, actsvr); -+ return E_OUTOFMEMORY; - } - - BOOL get_active_textservice(REFCLSID rclsid, TF_LANGUAGEPROFILE *profile) -@@ -560,11 +556,9 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: -- tlsIndex = TlsAlloc(); - break; - case DLL_PROCESS_DETACH: - if (fImpLoad) break; -- TlsFree(tlsIndex); - break; - } - return TRUE; -@@ -622,20 +616,6 @@ HRESULT WINAPI TF_CreateThreadMgr(ITfThreadMgr **pptim) - return ThreadMgr_Constructor(NULL,(IUnknown**)pptim); - } - --/*********************************************************************** -- * TF_GetThreadMgr (MSCTF.@) -- */ --HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) --{ -- TRACE("\n"); -- *pptim = TlsGetValue(tlsIndex); -- -- if (*pptim) -- ITfThreadMgr_AddRef(*pptim); -- -- return S_OK; --} -- - /*********************************************************************** - * SetInputScope(MSCTF.@) - */ -diff --git a/dlls/msctf/msctf_internal.h b/dlls/msctf/msctf_internal.h -index 584bb1044ed..ace2bee23d9 100644 ---- a/dlls/msctf/msctf_internal.h -+++ b/dlls/msctf/msctf_internal.h -@@ -35,7 +35,6 @@ - #define COOKIE_MAGIC_UIELEMENTSINK 0x00a0 - #define COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK 0x00b0 - --extern DWORD tlsIndex DECLSPEC_HIDDEN; - extern TfClientId processId DECLSPEC_HIDDEN; - extern ITfCompartmentMgr *globalCompartmentMgr DECLSPEC_HIDDEN; - -diff --git a/dlls/msctf/threadmgr.c b/dlls/msctf/threadmgr.c -index 2c208fbc04f..2119ea2193b 100644 ---- a/dlls/msctf/threadmgr.c -+++ b/dlls/msctf/threadmgr.c -@@ -37,6 +37,17 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(msctf); - -+static CRITICAL_SECTION ThreadMgrCs; -+static CRITICAL_SECTION_DEBUG ThreadMgrCsDebug = -+{ -+ 0, 0, &ThreadMgrCs, -+ {&ThreadMgrCsDebug.ProcessLocksList, -+ &ThreadMgrCsDebug.ProcessLocksList }, -+ 0, 0, {(DWORD_PTR)(__FILE__ ": ThreadMgrCs")} -+}; -+static CRITICAL_SECTION ThreadMgrCs = {&ThreadMgrCsDebug, -1, 0, 0, 0, 0}; -+struct list ThreadMgrList = LIST_INIT(ThreadMgrList); -+ - typedef struct tagPreservedKey - { - struct list entry; -@@ -98,6 +109,9 @@ typedef struct tagACLMulti { - struct list ThreadMgrEventSink; - struct list UIElementSink; - struct list InputProcessorProfileActivationSink; -+ -+ DWORD threadId; -+ struct list entry; - } ThreadMgr; - - typedef struct tagEnumTfDocumentMgr { -@@ -110,6 +124,11 @@ typedef struct tagEnumTfDocumentMgr { - - static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut); - -+static inline ThreadMgr *impl_from_ITfThreadMgr(ITfThreadMgr *iface) -+{ -+ return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); -+} -+ - static inline ThreadMgr *impl_from_ITfThreadMgrEx(ITfThreadMgrEx *iface) - { - return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); -@@ -155,6 +174,35 @@ static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMg - return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface); - } - -+/*********************************************************************** -+ * TF_GetThreadMgr (MSCTF.@) -+ */ -+HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) -+{ -+ DWORD id = GetCurrentThreadId(); -+ ThreadMgr *cursor; -+ -+ TRACE("%p\n", pptim); -+ -+ if (!pptim) -+ return E_INVALIDARG; -+ -+ EnterCriticalSection(&ThreadMgrCs); -+ LIST_FOR_EACH_ENTRY(cursor, &ThreadMgrList, ThreadMgr, entry) -+ { -+ if (cursor->threadId == id) -+ { -+ ITfThreadMgrEx_AddRef(&cursor->ITfThreadMgrEx_iface); -+ *pptim = (ITfThreadMgr *)&cursor->ITfThreadMgrEx_iface; -+ LeaveCriticalSection(&ThreadMgrCs); -+ return S_OK; -+ } -+ } -+ LeaveCriticalSection(&ThreadMgrCs); -+ *pptim = NULL; -+ return E_FAIL; -+} -+ - static void ThreadMgr_Destructor(ThreadMgr *This) - { - struct list *cursor, *cursor2; -@@ -163,7 +211,9 @@ static void ThreadMgr_Destructor(ThreadMgr *This) - if (This->focusHook) - UnhookWindowsHookEx(This->focusHook); - -- TlsSetValue(tlsIndex,NULL); -+ EnterCriticalSection(&ThreadMgrCs); -+ list_remove(&This->entry); -+ LeaveCriticalSection(&ThreadMgrCs); - TRACE("destroying %p\n", This); - if (This->focus) - ITfDocumentMgr_Release(This->focus); -@@ -386,17 +436,20 @@ static HRESULT WINAPI ThreadMgr_SetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr * - - static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam) - { -+ ITfThreadMgr *ThreadMgr_iface; - ThreadMgr *This; - -- This = TlsGetValue(tlsIndex); -- if (!This) -+ if (FAILED(TF_GetThreadMgr(&ThreadMgr_iface))) - { - ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n"); - return 0; - } -+ -+ This = impl_from_ITfThreadMgr(ThreadMgr_iface); - if (!This->focusHook) - { - ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n"); -+ ITfThreadMgr_Release(ThreadMgr_iface); - return 0; - } - -@@ -417,6 +470,7 @@ static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lPa - } - } - -+ ITfThreadMgr_Release(ThreadMgr_iface); - return CallNextHookEx(This->focusHook, nCode, wParam, lParam); - } - -@@ -1338,13 +1392,8 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) - return CLASS_E_NOAGGREGATION; - - /* Only 1 ThreadMgr is created per thread */ -- This = TlsGetValue(tlsIndex); -- if (This) -- { -- ThreadMgr_AddRef(&This->ITfThreadMgrEx_iface); -- *ppOut = (IUnknown*)&This->ITfThreadMgrEx_iface; -+ if (SUCCEEDED(TF_GetThreadMgr((ITfThreadMgr **)ppOut))) - return S_OK; -- } - - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr)); - if (This == NULL) -@@ -1359,7 +1408,6 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) - This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl; - This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl; - This->refCount = 1; -- TlsSetValue(tlsIndex,This); - - CompartmentMgr_Constructor((IUnknown*)&This->ITfThreadMgrEx_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); - -@@ -1376,6 +1424,11 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) - list_init(&This->UIElementSink); - list_init(&This->InputProcessorProfileActivationSink); - -+ This->threadId = GetCurrentThreadId(); -+ EnterCriticalSection(&ThreadMgrCs); -+ list_add_tail(&ThreadMgrList, &This->entry); -+ LeaveCriticalSection(&ThreadMgrCs); -+ - TRACE("returning %p\n", This); - *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface; - return S_OK; -From ed04e35d3f7af02267fb4e21578b3ccb27703836 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 23 Sep 2019 13:29:16 -0500 -Subject: [PATCH] dxdiag: Dump to stdout if no filename is given - ---- - programs/dxdiag/main.c | 8 +++++++- - programs/dxdiag/output.c | 10 +++++++--- - 2 files changed, 14 insertions(+), 4 deletions(-) - -diff --git a/programs/dxdiag/main.c b/programs/dxdiag/main.c -index 4533236f0f5..353e9f50fb9 100644 ---- a/programs/dxdiag/main.c -+++ b/programs/dxdiag/main.c -@@ -71,7 +71,13 @@ static BOOL process_file_name(const WCHAR *cmdline, enum output_type output_type - endptr = cmdline + lstrlenW(cmdline); - - len = endptr - cmdline; -- if (len == 0 || len >= filename_len) -+ if (len == 0) -+ { -+ *filename = 0; -+ return TRUE; -+ } -+ -+ if (len >= filename_len) - return FALSE; - - memcpy(filename, cmdline, len * sizeof(WCHAR)); -diff --git a/programs/dxdiag/output.c b/programs/dxdiag/output.c -index 50240fb2860..f0f6a6da0c3 100644 ---- a/programs/dxdiag/output.c -+++ b/programs/dxdiag/output.c -@@ -169,8 +169,12 @@ static BOOL output_text_information(struct dxdiag_information *dxdiag_info, cons - - fill_system_text_output_table(dxdiag_info, output_table[0].fields); - -- hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, -- NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); -+ if (filename && *filename) -+ hFile = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, -+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); -+ else -+ hFile = GetStdHandle(STD_OUTPUT_HANDLE); -+ - if (hFile == INVALID_HANDLE_VALUE) - { - WINE_ERR("File creation failed, last error %u\n", GetLastError()); -@@ -227,7 +231,7 @@ static HRESULT save_xml_document(IXMLDOMDocument *xmldoc, const WCHAR *filename) - VARIANT destVar; - HRESULT hr; - -- if (!bstr) -+ if (!bstr || !filename || !*filename) - return E_OUTOFMEMORY; - - V_VT(&destVar) = VT_BSTR; -From e485252dfad51a7e463643d56fe138129597e4b6 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Mon, 23 Sep 2019 08:56:04 -0500 -Subject: [PATCH] ntdll: Always add a tail to heap allocations. - -Fixes the Rockstar Games Launcher installer (and possibly other -NSIS-based installers) from crashing due to passing a too-small buffer -to GetWindowInfo(). ---- - dlls/ntdll/heap.c | 11 +++++------ - 1 file changed, 5 insertions(+), 6 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index 6344157f384..6fefe5d6d80 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -118,9 +118,8 @@ C_ASSERT( sizeof(ARENA_LARGE) % LARGE_ALIGNMENT == 0 ); - #define HEAP_MIN_SHRINK_SIZE (HEAP_MIN_DATA_SIZE+sizeof(ARENA_FREE)) - /* minimum size to start allocating large blocks */ - #define HEAP_MIN_LARGE_BLOCK_SIZE 0x7f000 --/* extra size to add at the end of block for tail checking */ --#define HEAP_TAIL_EXTRA_SIZE(flags) \ -- ((flags & HEAP_TAIL_CHECKING_ENABLED) || RUNNING_ON_VALGRIND ? ALIGNMENT : 0) -+/* extra size to add at the end of block to mitigate overruns and allow tail checking */ -+#define HEAP_TAIL_EXTRA_SIZE ALIGNMENT - - /* size of the blocks on the free lists */ - #define HEAP_FREELIST_SIZE(index) \ -@@ -800,7 +799,7 @@ static void HEAP_ShrinkBlock(SUBHEAP *subheap, ARENA_INUSE *pArena, SIZE_T size) - static void *allocate_large_block( HEAP *heap, DWORD flags, SIZE_T size ) - { - ARENA_LARGE *arena; -- SIZE_T block_size = sizeof(*arena) + ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE(flags); -+ SIZE_T block_size = sizeof(*arena) + ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE; - LPVOID address = NULL; - - if (block_size < size) return NULL; /* overflow */ -@@ -1814,7 +1813,7 @@ void * WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE heap, ULONG flags, SIZE_ - if (!heapPtr) return NULL; - flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY; - flags |= heapPtr->flags; -- rounded_size = ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE( flags ); -+ rounded_size = ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE; - if (rounded_size < size) /* overflow */ - { - if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY ); -@@ -1968,7 +1967,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - flags |= heapPtr->flags; - if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); - -- rounded_size = ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE(flags); -+ rounded_size = ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE; - if (rounded_size < size) goto oom; /* overflow */ - if (rounded_size < HEAP_MIN_DATA_SIZE) rounded_size = HEAP_MIN_DATA_SIZE; - -From 5cd65deffffad9073538acf4fd8e794ac07824a5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 9 Oct 2019 09:47:12 +0200 -Subject: [PATCH] makedep: Align PE sections so they can be directly mmaped. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This should help linux perf tool match the binary files on disk with the -code regions in memory. - -Signed-off-by: Rémi Bernon ---- - tools/makedep.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/tools/makedep.c b/tools/makedep.c -index 6079d1fe28b..18e7b8a913e 100644 ---- a/tools/makedep.c -+++ b/tools/makedep.c -@@ -3245,6 +3245,7 @@ static void output_module( struct makefile *make ) - output_filenames_obj_dir( make, make->res_files ); - output_filenames( all_libs ); - output_filename( make->is_cross ? "$(CROSSLDFLAGS)" : "$(LDFLAGS)" ); -+ output_filename( make->is_cross ? "-Wl,--file-alignment,4096" : "" ); - output( "\n" ); - - if (spec_file && make->importlib) -From 213905a322620eb326b655ab89fbca07316e6357 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 19 Nov 2019 09:59:17 -0600 -Subject: [PATCH] HACK: dxgi: Return empty GPU string for Crazy Machines 3 - -If the GPU string is long enough, the game will crash trying to -dereference part of it. Probably this is due to missing Media Foundation -support. Try to remove this hack after the game's videos successfully -play back. ---- - dlls/dxgi/adapter.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/dlls/dxgi/adapter.c b/dlls/dxgi/adapter.c -index d2fc629c843..5a97590dbce 100644 ---- a/dlls/dxgi/adapter.c -+++ b/dlls/dxgi/adapter.c -@@ -161,12 +161,32 @@ static HRESULT dxgi_adapter_get_desc(struct dxgi_adapter *adapter, DXGI_ADAPTER_ - if (FAILED(hr = wined3d_get_adapter_identifier(adapter->factory->wined3d, adapter->ordinal, 0, &adapter_id))) - return hr; - -+ { -+ /* HACK for Proton issue #3204 -+ * -+ * Due to reading uninitialized memory, the game tries to dereference -+ * part of the GPU Description string if it is long enough. So return -+ * an empty string instead. -+ * -+ * See the bug report for the full description, but we may be able to -+ * remove this hack after implementing enough of Media Foundation for -+ * this game's videos to play back. -+ */ -+ const char *sgi = getenv("SteamGameId"); -+ if(sgi && !strcmp(sgi, "351920")) -+ { -+ desc->Description[0] = 0; -+ goto skip_description; -+ } -+ } -+ - if (!MultiByteToWideChar(CP_ACP, 0, description, -1, desc->Description, ARRAY_SIZE(description))) - { - DWORD err = GetLastError(); - ERR("Failed to translate description %s (%#x).\n", debugstr_a(description), err); - hr = E_FAIL; - } -+skip_description: - - desc->VendorId = adapter_id.vendor_id; - desc->DeviceId = adapter_id.device_id; -From 749bf5fcd5f41a39301428a7fccd1e4febcd6f90 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= -Date: Fri, 13 Dec 2019 15:54:28 +0200 -Subject: [PATCH] dwmapi: Improve DwmGetWindowAttribute stub. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Gabriel Ivăncescu ---- - dlls/dwmapi/dwmapi_main.c | 26 ++++++++++++++++++++++++-- - 1 file changed, 24 insertions(+), 2 deletions(-) - -diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c -index 6378a091f0b..e976fda77f2 100644 ---- a/dlls/dwmapi/dwmapi_main.c -+++ b/dlls/dwmapi/dwmapi_main.c -@@ -205,9 +205,31 @@ BOOL WINAPI DwmDefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, - */ - HRESULT WINAPI DwmGetWindowAttribute(HWND hwnd, DWORD attribute, PVOID pv_attribute, DWORD size) - { -- FIXME("(%p %ld %p %ld) stub\n", hwnd, attribute, pv_attribute, size); -+ if (!hwnd) return E_HANDLE; -+ if (!pv_attribute) return E_INVALIDARG; - -- return E_NOTIMPL; -+ switch (attribute) -+ { -+ case DWMWA_NCRENDERING_ENABLED: -+ if (size < sizeof(BOOL)) return E_INVALIDARG; -+ -+ WARN("DWMWA_NCRENDERING_ENABLED: always returning FALSE.\n"); -+ *(BOOL*)(pv_attribute) = FALSE; -+ break; -+ -+ case DWMWA_CLOAKED: -+ if (size < sizeof(DWORD)) return E_INVALIDARG; -+ -+ WARN("DWMWA_CLOAKED: always returning 0.\n"); -+ *(DWORD*)(pv_attribute) = 0; -+ break; -+ -+ default: -+ FIXME("unimplemented attribute %ld, size %u, for hwnd %p.\n", attribute, size, hwnd); -+ return E_INVALIDARG; -+ } -+ -+ return S_OK; - } - - /********************************************************************** -From 1a2e600a9c35a9558b32e7986668d7dc81c8b5ae Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= -Date: Fri, 13 Dec 2019 15:54:30 +0200 -Subject: [PATCH] dwmapi: Add partial implementation of - DWMWA_EXTENDED_FRAME_BOUNDS. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Gabriel Ivăncescu ---- - dlls/dwmapi/Makefile.in | 1 + - dlls/dwmapi/dwmapi_main.c | 7 +++++++ - dlls/dwmapi/tests/dwmapi.c | 14 ++++++++++++++ - 3 files changed, 22 insertions(+) - -diff --git a/dlls/dwmapi/Makefile.in b/dlls/dwmapi/Makefile.in -index 3a3691326f8..d273a22c8f3 100644 ---- a/dlls/dwmapi/Makefile.in -+++ b/dlls/dwmapi/Makefile.in -@@ -1,5 +1,6 @@ - MODULE = dwmapi.dll - IMPORTLIB = dwmapi -+IMPORTS = user32 - - EXTRADLLFLAGS = -mno-cygwin - -diff --git a/dlls/dwmapi/dwmapi_main.c b/dlls/dwmapi/dwmapi_main.c -index e976fda77f2..212c88c5a02 100644 ---- a/dlls/dwmapi/dwmapi_main.c -+++ b/dlls/dwmapi/dwmapi_main.c -@@ -217,6 +217,13 @@ HRESULT WINAPI DwmGetWindowAttribute(HWND hwnd, DWORD attribute, PVOID pv_attrib - *(BOOL*)(pv_attribute) = FALSE; - break; - -+ case DWMWA_EXTENDED_FRAME_BOUNDS: -+ if (size < sizeof(RECT)) return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); -+ -+ WARN("DWMWA_EXTENDED_FRAME_BOUNDS: returning window rect.\n"); -+ GetWindowRect(hwnd, pv_attribute); -+ break; -+ - case DWMWA_CLOAKED: - if (size < sizeof(DWORD)) return E_INVALIDARG; - -From b739d48093cce805b7b4f48fdbd9d0bb62bc8013 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Mon, 13 Apr 2020 16:25:47 -0700 -Subject: [PATCH] HACK: dxgi: Swap around memory sizes for GTA IV - -GTA IV ends up using its "Intel integrated" codepath for determining -VRAM size (since nvapi/atiadlxx fail), but this requires that -DedicatedVideoMemory is a very small dummy value, and SharedSystemMemory -is the actual VRAM size. -Swap the memory values around so this works. ---- - dlls/dxgi/adapter.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/dlls/dxgi/adapter.c b/dlls/dxgi/adapter.c -index 5a97590dbce..a5563498cdd 100644 ---- a/dlls/dxgi/adapter.c -+++ b/dlls/dxgi/adapter.c -@@ -200,6 +200,25 @@ static HRESULT dxgi_adapter_get_desc(struct dxgi_adapter *adapter, DXGI_ADAPTER_ - desc->GraphicsPreemptionGranularity = 0; /* FIXME */ - desc->ComputePreemptionGranularity = 0; /* FIXME */ - -+ { -+ /* HACK -+ * -+ * Grand Theft Auto IV first tries to get VRAM size using nvapi/atiadlxx, -+ * after that fails it falls back to the Intel integrated codepath which -+ * uses DXGI. -+ * -+ * DedicatedVideoMemory must be a dummy value less than 200 MB, then -+ * SharedSystemMemory will be used as the VRAM size. -+ * In case of failure, the game will just use 512 MB as VRAM size. -+ */ -+ const char *sgi = getenv("SteamGameId"); -+ if(sgi && !strcmp(sgi, "12210")) -+ { -+ desc->SharedSystemMemory = adapter_id.video_memory; -+ desc->DedicatedVideoMemory = 32 * 1024 * 1024; -+ } -+ } -+ - return hr; - } - -From c619409f235cf660cdd4fd3295d5e04ec628daa1 Mon Sep 17 00:00:00 2001 -From: Alexey Prokhin -Date: Thu, 23 Apr 2020 12:29:55 +0300 -Subject: [PATCH] kernelbase: Set the proper error code in - GetQueuedCompletionStatus{Ex} when the handle is closed. - -Planet Zoo relies on it being ERROR_ABANDONED_WAIT_0. ---- - dlls/kernelbase/sync.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c -index 0ae3aadde92..e95ede8aed5 100644 ---- a/dlls/kernelbase/sync.c -+++ b/dlls/kernelbase/sync.c -@@ -960,6 +960,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatus( HANDLE port, LPDWORD co - } - - if (status == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); -+ else if (status == ERROR_WAIT_NO_CHILDREN) SetLastError( ERROR_ABANDONED_WAIT_0 ); - else SetLastError( RtlNtStatusToDosError(status) ); - return FALSE; - } -@@ -981,6 +982,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatusEx( HANDLE port, OVERLAPP - if (ret == STATUS_SUCCESS) return TRUE; - else if (ret == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); - else if (ret == STATUS_USER_APC) SetLastError( WAIT_IO_COMPLETION ); -+ else if (ret == ERROR_WAIT_NO_CHILDREN) SetLastError( ERROR_ABANDONED_WAIT_0 ); - else SetLastError( RtlNtStatusToDosError(ret) ); - return FALSE; - } - -From 0255dbc3afd3ff673fa701e7802474483252fcb2 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 13 Jul 2020 10:21:49 -0500 -Subject: [PATCH] ntdll: Handle NULL object name buffer in - nt_to_unix_file_name_attr(). - ---- - dlls/ntdll/tests/file.c | 22 +++++++++++++++++++++- - dlls/ntdll/unix/file.c | 8 ++++++++ - 2 files changed, 29 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 20eb6a05922..d99c6b462b2 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -3593,12 +3593,20 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, - const WCHAR *name; - char *unix_name; - int name_len, unix_len; - NTSTATUS status; - -+ if (!attr->ObjectName->Buffer && attr->ObjectName->Length) -+ return STATUS_ACCESS_VIOLATION; -+ - if (!attr->RootDirectory) /* without root dir fall back to normal lookup */ -+ { -+ if (!attr->ObjectName->Buffer) -+ return STATUS_OBJECT_PATH_SYNTAX_BAD; -+ - return nt_to_unix_file_name_no_root( attr->ObjectName, name_ret, disposition ); -+ } - - name = attr->ObjectName->Buffer; - name_len = attr->ObjectName->Length / sizeof(WCHAR); - - if (name_len && name[0] == '\\') return STATUS_INVALID_PARAMETER; -From 514d3e11c999b11a95ab35df5b4ab454d34fe791 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 13 May 2020 13:55:55 +0300 -Subject: [PATCH] ntdll: Add WINE_DISABLE_WRITE_WATCH env var to disable write - watch support. - -Massively improves performance for corert games (Streets of Rage 4). -Could be fixed properly with Linux kernel changes. ---- - dlls/ntdll/unix/virtual.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index 7ea80852090..272e1c5b176 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -3425,6 +3425,22 @@ NTSTATUS WINAPI NtAllocateVirtualMemory( HANDLE process, PVOID *ret, ULONG_PTR z - if (zero_bits > 21 && zero_bits < 32) return STATUS_INVALID_PARAMETER_3; - if (!is_win64 && !is_wow64 && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3; - -+ if (type & MEM_WRITE_WATCH) -+ { -+ static int disable = -1; -+ -+ if (disable == -1) -+ { -+ const char *env_var; -+ -+ if ((disable = (env_var = getenv("WINE_DISABLE_WRITE_WATCH")) && atoi(env_var))) -+ FIXME("Disabling write watch support.\n"); -+ } -+ -+ if (disable) -+ return STATUS_NOT_SUPPORTED; -+ } -+ - if (process != NtCurrentProcess()) - { - apc_call_t call; -From 912701cb515acdc8e0ff263552f656cd49f60714 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 15 May 2020 13:01:26 +0200 -Subject: [PATCH] d3d10core: Implement D3D10CoreRegisterLayers. - ---- - dlls/d3d10core/d3d10core_main.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/dlls/d3d10core/d3d10core_main.c b/dlls/d3d10core/d3d10core_main.c -index d364be90d6d..5a9a4a211c1 100644 ---- a/dlls/d3d10core/d3d10core_main.c -+++ b/dlls/d3d10core/d3d10core_main.c -@@ -29,11 +29,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d10core); - HRESULT WINAPI D3D11CoreCreateDevice(IDXGIFactory *factory, IDXGIAdapter *adapter, unsigned int flags, - const D3D_FEATURE_LEVEL *feature_levels, unsigned int level_count, ID3D11Device **device); - -+HRESULT WINAPI D3D11CoreRegisterLayers(void); -+ - HRESULT WINAPI D3D10CoreRegisterLayers(void) - { - TRACE("\n"); - -- return E_NOTIMPL; -+ return D3D11CoreRegisterLayers(); - } - - HRESULT WINAPI D3D10CoreCreateDevice(IDXGIFactory *factory, IDXGIAdapter *adapter, - -From 376a037ce1391e071835a0bf30ebf1fcec43c367 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 15 May 2020 12:59:44 +0200 -Subject: [PATCH] dxgi: Add fallback to D3D10CoreRegisterLayers. - -If D3D11CoreRegisterLayers is not found in module. ---- - dlls/dxgi/dxgi_main.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/dlls/dxgi/dxgi_main.c b/dlls/dxgi/dxgi_main.c -index 83c3f3734a7..006ab370844 100644 ---- a/dlls/dxgi/dxgi_main.c -+++ b/dlls/dxgi/dxgi_main.c -@@ -106,8 +106,8 @@ static HRESULT register_d3d10core_layers(HMODULE d3d10core) - - if (!dxgi_main.d3d10core) - { -- HRESULT hr; -- HRESULT (WINAPI *d3d11core_register_layers)(void); -+ HRESULT hr = E_FAIL; -+ HRESULT (WINAPI *register_layers)(void); - HMODULE mod; - BOOL ret; - -@@ -117,8 +117,10 @@ static HRESULT register_d3d10core_layers(HMODULE d3d10core) - return E_FAIL; - } - -- d3d11core_register_layers = (void *)GetProcAddress(mod, "D3D11CoreRegisterLayers"); -- hr = d3d11core_register_layers(); -+ if ((register_layers = (void *)GetProcAddress(mod, "D3D11CoreRegisterLayers")) || -+ (register_layers = (void *)GetProcAddress(mod, "D3D10CoreRegisterLayers"))) -+ hr = register_layers(); -+ - if (FAILED(hr)) - { - ERR("Failed to register d3d11 layers, returning %#x.\n", hr); - -From 5b00ca69a1927e1d0df4cf26160228e460568c51 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 9 Jun 2020 14:16:22 +0300 -Subject: [PATCH] kernelbase: HACK Add an option to blacklist files. - ---- - dlls/kernelbase/file.c | 76 +++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 75 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c -index eb2ef57c7d6..c7881fe4516 100644 ---- a/dlls/kernelbase/file.c -+++ b/dlls/kernelbase/file.c -@@ -41,6 +41,8 @@ - #include "wine/exception.h" - #include "wine/debug.h" - -+#include "wine/heap.h" -+ - WINE_DEFAULT_DEBUG_CHANNEL(file); - - /* info structure for FindFirstFile handle */ -@@ -432,6 +434,72 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileA( LPCSTR name, DWORD access, DWORD sh - return CreateFileW( nameW, access, sharing, sa, creation, attributes, template ); - } - -+#define MAX_BLACKLISTED_FILENAMES 32 -+ -+static struct -+{ -+ const WCHAR *name; -+ size_t name_len; -+} -+blacklist_filenames[MAX_BLACKLISTED_FILENAMES]; -+ -+static unsigned int blacklist_filename_count; -+ -+static BOOL CALLBACK init_file_blacklist(PINIT_ONCE init_once, PVOID parameter, PVOID *context) -+{ -+ const WCHAR separators[] = L",; "; -+ WCHAR *buffer, *token; -+ DWORD size; -+ -+ if (!(size = GetEnvironmentVariableW(L"WINE_BLACKLIST_FILES", NULL, 0))) -+ return TRUE; -+ -+ if (!(buffer = heap_alloc(sizeof(*buffer) * size))) -+ { -+ ERR("No memory.\n"); -+ return FALSE; -+ } -+ -+ if (GetEnvironmentVariableW(L"WINE_BLACKLIST_FILES", buffer, size) != size - 1) -+ { -+ ERR("Error getting WINE_BLACKLIST_FILES env variable.\n"); -+ return FALSE; -+ } -+ -+ blacklist_filename_count = 0; -+ token = wcstok(buffer, separators); -+ while (token && blacklist_filename_count < MAX_BLACKLISTED_FILENAMES) -+ { -+ FIXME("Blacklisting %s file.\n", debugstr_w(token)); -+ blacklist_filenames[blacklist_filename_count].name = token; -+ blacklist_filenames[blacklist_filename_count++].name_len = wcslen(token); -+ token = wcstok(NULL, separators); -+ } -+ -+ if (token && blacklist_filename_count == MAX_BLACKLISTED_FILENAMES) -+ ERR("File black list is too long.\n"); -+ -+ return TRUE; -+} -+ -+static BOOL is_file_blacklisted(LPCWSTR filename) -+{ -+ static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; -+ unsigned int i; -+ size_t len; -+ -+ if (!InitOnceExecuteOnce(&init_once, init_file_blacklist, NULL, NULL)) -+ return FALSE; -+ -+ len = wcslen(filename); -+ -+ for (i = 0; i < blacklist_filename_count; ++i) -+ if (blacklist_filenames[i].name_len <= len -+ && !wcsicmp(blacklist_filenames[i].name, filename + len - blacklist_filenames[i].name_len)) -+ return TRUE; -+ -+ return FALSE; -+} - - /************************************************************************* - * CreateFileW (kernelbase.@) -@@ -460,7 +528,6 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileW( LPCWSTR filename, DWORD access, DWO - FILE_OVERWRITE /* TRUNCATE_EXISTING */ - }; - -- - /* sanity checks */ - - if (!filename || !filename[0]) -@@ -479,6 +546,13 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileW( LPCWSTR filename, DWORD access, DWO - (sharing & FILE_SHARE_DELETE) ? "FILE_SHARE_DELETE " : "", - creation, attributes); - -+ if (is_file_blacklisted(filename)) -+ { -+ FIXME("\"%s\" is blacklisted.\n", debugstr_w(filename)); -+ SetLastError( ERROR_FILE_NOT_FOUND ); -+ return INVALID_HANDLE_VALUE; -+ } -+ - if ((GetVersion() & 0x80000000) && !wcsncmp( filename, L"\\\\.\\", 4 ) && - !RtlIsDosDeviceName_U( filename + 4 ) && - wcsnicmp( filename + 4, L"PIPE\\", 5 ) && - -From 2409bd1f74be116172688a25df725290637c255a Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Wed, 10 Jun 2020 16:18:29 -0500 -Subject: [PATCH] kernelbase: Apply blacklist automatically to Origin - executables - ---- - dlls/kernelbase/file.c | 54 ++++++++++++++++++++++++++++++++++-------- - 1 file changed, 44 insertions(+), 10 deletions(-) - -diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c -index c7881fe4516..bb4be45da5d 100644 ---- a/dlls/kernelbase/file.c -+++ b/dlls/kernelbase/file.c -@@ -447,23 +447,57 @@ static unsigned int blacklist_filename_count; - - static BOOL CALLBACK init_file_blacklist(PINIT_ONCE init_once, PVOID parameter, PVOID *context) - { -+ static WCHAR origin_blacklist[] = L"kernel32.dll;user32.dll"; -+ - const WCHAR separators[] = L",; "; - WCHAR *buffer, *token; - DWORD size; - -- if (!(size = GetEnvironmentVariableW(L"WINE_BLACKLIST_FILES", NULL, 0))) -- return TRUE; -- -- if (!(buffer = heap_alloc(sizeof(*buffer) * size))) -+ if ((size = GetEnvironmentVariableW(L"WINE_BLACKLIST_FILES", NULL, 0))) - { -- ERR("No memory.\n"); -- return FALSE; -- } -+ if (!(buffer = heap_alloc(sizeof(*buffer) * size))) -+ { -+ ERR("No memory.\n"); -+ return FALSE; -+ } - -- if (GetEnvironmentVariableW(L"WINE_BLACKLIST_FILES", buffer, size) != size - 1) -+ if (GetEnvironmentVariableW(L"WINE_BLACKLIST_FILES", buffer, size) != size - 1) -+ { -+ ERR("Error getting WINE_BLACKLIST_FILES env variable.\n"); -+ return FALSE; -+ } -+ } -+ else - { -- ERR("Error getting WINE_BLACKLIST_FILES env variable.\n"); -- return FALSE; -+ static const WCHAR *origin_names[] = { -+ L"igoproxy64.exe", -+ L"igoproxy.exe", -+ L"origin.exe", -+ L"easteamproxy.exe" -+ }; -+ -+ WCHAR cur_exe[MAX_PATH]; -+ DWORD cur_exe_len, i; -+ -+ if (!(cur_exe_len = GetModuleFileNameW(NULL, cur_exe, ARRAY_SIZE(cur_exe)))) -+ return TRUE; -+ -+ buffer = NULL; -+ -+ for (i = 0; i < ARRAY_SIZE(origin_names); ++i) -+ { -+ DWORD origin_name_len = wcslen(origin_names[i]); -+ if (cur_exe_len >= origin_name_len && -+ wcsicmp(cur_exe + cur_exe_len - origin_name_len, origin_names[i]) == 0) -+ { -+ FIXME("using origin file blacklist for %s\n", debugstr_w(cur_exe)); -+ buffer = origin_blacklist; -+ break; -+ } -+ } -+ -+ if (!buffer) -+ return TRUE; - } - - blacklist_filename_count = 0; -From ff790e8d99f2026af9b8569355fc1df5e6f0c639 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Sat, 5 Sep 2020 01:09:37 +0300 -Subject: [PATCH] wbemprox: HACK: Make Bloons TD6 happy so it does not exit - after getting string Wine from bios info. - ---- - dlls/wbemprox/builtin.c | 22 +++++++++++----------- - 1 file changed, 11 insertions(+), 11 deletions(-) - -diff --git a/dlls/wbemprox/builtin.c b/dlls/wbemprox/builtin.c -index 43268221936..f39d6f0cd7b 100644 ---- a/dlls/wbemprox/builtin.c -+++ b/dlls/wbemprox/builtin.c -@@ -1181,7 +1181,7 @@ static WCHAR *get_bios_string( BYTE id, const char *buf, UINT len ) - static WCHAR *get_bios_manufacturer( const char *buf, UINT len ) - { - WCHAR *ret = get_bios_string( 1, buf, len ); -- if (!ret) return heap_strdupW( L"The Wine Project" ); -+ if (!ret) return heap_strdupW( L"The Proton Project" ); - return ret; - } - -@@ -1227,7 +1227,7 @@ static WCHAR *get_bios_releasedate( const char *buf, UINT len ) - static WCHAR *get_bios_smbiosbiosversion( const char *buf, UINT len ) - { - WCHAR *ret = get_bios_string( 2, buf, len ); -- if (!ret) return heap_strdupW( L"Wine" ); -+ if (!ret) return heap_strdupW( L"Proton" ); - return ret; - } - -@@ -1307,7 +1307,7 @@ static enum fill_status fill_bios( struct table *table, const struct expr *cond - rec->smbiosminorversion = get_bios_smbiosminorversion( buf, len ); - rec->systembiosmajorversion = get_bios_system_bios_major_release( buf, len ); - rec->systembiosminorversion = get_bios_system_bios_minor_release( buf, len ); -- rec->version = L"WINE - 1"; -+ rec->version = L"PROTON - 1"; - if (!match_row( table, row, cond, &status )) free_row_values( table, row ); - else row++; - -@@ -1468,8 +1468,8 @@ static enum fill_status fill_compsys( struct table *table, const struct expr *co - rec->description = L"AT/AT COMPATIBLE"; - rec->domain = L"WORKGROUP"; - rec->domainrole = 0; /* standalone workstation */ -- rec->manufacturer = L"The Wine Project"; -- rec->model = L"Wine"; -+ rec->manufacturer = L"The Proton Project"; -+ rec->model = L"Proton"; - rec->name = get_computername(); - rec->num_logical_processors = get_logical_processor_count( NULL, &rec->num_processors ); - rec->total_physical_memory = get_total_physical_memory(); -@@ -1505,7 +1505,7 @@ static WCHAR *get_compsysproduct_identifyingnumber( const char *buf, UINT len ) - static WCHAR *get_compsysproduct_name( const char *buf, UINT len ) - { - WCHAR *ret = get_compsysproduct_string( 2, buf, len ); -- if (!ret) return heap_strdupW( L"Wine" ); -+ if (!ret) return heap_strdupW( L"Proton" ); - return ret; - } - -@@ -1533,7 +1533,7 @@ done: - static WCHAR *get_compsysproduct_vendor( const char *buf, UINT len ) - { - WCHAR *ret = get_compsysproduct_string( 1, buf, len ); -- if (!ret) return heap_strdupW( L"The Wine Project" ); -+ if (!ret) return heap_strdupW( L"The Proton Project" ); - return ret; - } - -@@ -2652,7 +2652,7 @@ static enum fill_status fill_networkadapter( struct table *table, const struct e - rec->index = aa->u.s.IfIndex; - rec->interface_index = aa->u.s.IfIndex; - rec->mac_address = get_mac_address( aa->PhysicalAddress, aa->PhysicalAddressLength ); -- rec->manufacturer = L"The Wine Project"; -+ rec->manufacturer = L"The Proton Project"; - rec->name = heap_strdupW( aa->FriendlyName ); - rec->netconnection_status = get_connection_status( aa->OperStatus ); - rec->physicaladapter = physical; -@@ -3475,7 +3475,7 @@ static enum fill_status fill_operatingsystem( struct table *table, const struct - rec->lastbootuptime = get_lastbootuptime(); - rec->localdatetime = get_localdatetime(); - rec->locale = get_locale(); -- rec->manufacturer = L"The Wine Project"; -+ rec->manufacturer = L"The Proton Project"; - rec->name = get_osname( rec->caption ); - rec->operatingsystemsku = get_operatingsystemsku(); - rec->osarchitecture = get_osarchitecture(); -@@ -3740,7 +3740,7 @@ static WCHAR *get_systemenclosure_string( BYTE id, const char *buf, UINT len ) - static WCHAR *get_systemenclosure_manufacturer( const char *buf, UINT len ) - { - WCHAR *ret = get_systemenclosure_string( 1, buf, len ); -- if (!ret) return heap_strdupW( L"Wine" ); -+ if (!ret) return heap_strdupW( L"Proton" ); - return ret; - } - -@@ -3955,7 +3955,7 @@ static enum fill_status fill_sounddevice( struct table *table, const struct expr - - rec = (struct record_sounddevice *)table->data; - rec->deviceid = get_sounddevice_pnpdeviceid( &desc ); -- rec->manufacturer = L"The Wine Project"; -+ rec->manufacturer = L"The Proton Project"; - rec->name = L"Wine Audio Device"; - rec->pnpdeviceid = get_sounddevice_pnpdeviceid( &desc ); - rec->productname = L"Wine Audio Device"; --- -2.26.2 - -From c9a5fcb0966ab0ca0722c8c07476c131844f98e1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 16 Oct 2020 23:37:09 +0200 -Subject: [PATCH] dotnetfx35.exe: Add stub program. - -This makes it possible to override native dotnetfx35 installer, which -is broken in an unfixable way. Recent Windows versions also bypass its -execution somehow. ---- - configure | 2 ++ - configure.ac | 1 + - programs/dotnetfx35/Makefile.in | 7 +++++++ - programs/dotnetfx35/main.c | 32 ++++++++++++++++++++++++++++++++ - 4 files changed, 42 insertions(+) - create mode 100644 programs/dotnetfx35/Makefile.in - create mode 100644 programs/dotnetfx35/main.c - -diff --git a/configure b/configure -index 848323bb057..d676b1c82ee 100755 ---- a/configure -+++ b/configure -@@ -1766,6 +1766,7 @@ enable_conhost - enable_control - enable_cscript - enable_dism -+enable_dotnetfx35 - enable_dplaysvr - enable_dpnsvr - enable_dpvsetup -@@ -21579,6 +21580,7 @@ wine_fn_config_makefile programs/conhost enable_conhost - wine_fn_config_makefile programs/control enable_control - wine_fn_config_makefile programs/cscript enable_cscript - wine_fn_config_makefile programs/dism enable_dism -+wine_fn_config_makefile programs/dotnetfx35 enable_dotnetfx35 - wine_fn_config_makefile programs/dplaysvr enable_dplaysvr - wine_fn_config_makefile programs/dpnsvr enable_dpnsvr - wine_fn_config_makefile programs/dpvsetup enable_dpvsetup -diff --git a/configure.ac b/configure.ac -index 130dbeb8530..63d26ff123c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3997,6 +3997,7 @@ WINE_CONFIG_MAKEFILE(programs/conhost) - WINE_CONFIG_MAKEFILE(programs/control) - WINE_CONFIG_MAKEFILE(programs/cscript) - WINE_CONFIG_MAKEFILE(programs/dism) -+WINE_CONFIG_MAKEFILE(programs/dotnetfx35) - WINE_CONFIG_MAKEFILE(programs/dplaysvr) - WINE_CONFIG_MAKEFILE(programs/dpnsvr) - WINE_CONFIG_MAKEFILE(programs/dpvsetup) -diff --git a/programs/dotnetfx35/Makefile.in b/programs/dotnetfx35/Makefile.in -new file mode 100644 -index 00000000000..e50ed37f700 ---- /dev/null -+++ b/programs/dotnetfx35/Makefile.in -@@ -0,0 +1,7 @@ -+MODULE = dotnetfx35.exe -+IMPORTS = -+ -+EXTRADLLFLAGS = -mwindows -mno-cygwin -+ -+C_SRCS = \ -+ main.c -diff --git a/programs/dotnetfx35/main.c b/programs/dotnetfx35/main.c -new file mode 100644 -index 00000000000..cd6df5bcf41 ---- /dev/null -+++ b/programs/dotnetfx35/main.c -@@ -0,0 +1,32 @@ -+/* -+ * Fake dotnetfx35.exe installer -+ * -+ * Copyright 2020 Rémi Bernon -+ * -+ * 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 -+#include -+ -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(dotnetfx); -+ -+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) -+{ -+ FIXME("stub!"); -+ return 0; -+} -From 2452b57e7fed9ac5036df9bcace5c28366a8eb41 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 8 Jan 2021 13:47:39 -0600 -Subject: [PATCH] HACK: kernelbase: Add NFS EXE to Origin file blacklist hack - ---- - dlls/kernelbase/file.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c -index a33440107b6..397aa64dce2 100644 ---- a/dlls/kernelbase/file.c -+++ b/dlls/kernelbase/file.c -@@ -741,7 +741,8 @@ static BOOL CALLBACK init_file_blacklist(PINIT_ONCE init_once, PVOID parameter, - L"igoproxy64.exe", - L"igoproxy.exe", - L"origin.exe", -- L"easteamproxy.exe" -+ L"easteamproxy.exe", -+ L"NFS11Remastered.exe" - }; - - WCHAR cur_exe[MAX_PATH]; -From e6c7aa8bc42fea042c3d504009ad8a0fb70a6c0c Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 21 Jan 2021 11:54:10 -0600 -Subject: [PATCH] vulkan-1: Prefer builtin - -Games that ship their own vulkan-1 will be broken with your VR wrappers. ---- - dlls/vulkan-1/Makefile.in | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/dlls/vulkan-1/Makefile.in b/dlls/vulkan-1/Makefile.in -index a4a10bc8e93..551ef146cd7 100644 ---- a/dlls/vulkan-1/Makefile.in -+++ b/dlls/vulkan-1/Makefile.in -@@ -2,6 +2,4 @@ MODULE = vulkan-1.dll - IMPORTS = winevulkan - IMPORTLIB = vulkan-1 - --EXTRADLLFLAGS = -Wb,--prefer-native -- - RC_SRCS = version.rc -From 07461415f4399934a3c03c8dd6e146167bd67dfd Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 25 Mar 2021 17:53:37 +0300 -Subject: [PATCH 07/16] wine.inf: Create package repository for VCLibs.140. - ---- - loader/wine.inf.in | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 4df88d1f386..1506a73573b 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -67,6 +67,7 @@ AddReg=\ - Misc,\ - Nls,\ - OLE,\ -+ Packages,\ - Printing,\ - Services, \ - SessionMgr,\ -@@ -95,6 +96,7 @@ AddReg=\ - Misc,\ - Nls,\ - OLE,\ -+ Packages.ntamd64,\ - Printing,\ - Services, \ - SessionMgr,\ -@@ -123,6 +125,7 @@ AddReg=\ - Misc,\ - Nls,\ - OLE,\ -+ Packages.ntarm64,\ - Printing,\ - Services, \ - SessionMgr,\ -@@ -142,6 +145,7 @@ AddReg=\ - DirectX,\ - MCI,\ - Misc,\ -+ Packages.wow64,\ - Tapi,\ - VersionInfo.ntamd64,\ - LicenseInformation, \ -@@ -234,6 +238,7 @@ CurrentVersionNT="Software\Microsoft\Windows NT\CurrentVersion" - CurrentVersionNT="Software\Microsoft\Windows NT\CurrentVersion" - FontSubStr="Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" - Control="System\CurrentControlSet\Control" -+Packages="Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages" - - [Classes] - HKCR,.chm,,2,"chm.file" -@@ -1129,6 +1134,18 @@ HKLM,System\CurrentControlSet\Control\Nls\Locale\Alternate Sorts,"00030404",,"9" - HKLM,"Software\Microsoft\OLE","EnableDCOM",,"Y" - HKLM,"Software\Microsoft\OLE","EnableRemoteConnect",,"N" - -+[Packages] -+HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x86__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" -+ -+[Packages.ntamd64] -+HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x64__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" -+ -+[Packages.wow64] -+HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_x86__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\syswow64" -+ -+[Packages.arm64] -+HKLM,"%Packages%\Microsoft.VCLibs.140.00_14.0.29231.0_arm64__8wekyb3d8bbwe","Path",0x00020002,"%SystemRoot%\system32" -+ - [Printing] - HKLM,%Control%\Print\Monitors\Local Port,"Driver",2,"localspl.dll" - HKLM,%Control%\Print\Printers,"DefaultSpoolDirectory",2,"%11%\spool\printers" --- -2.30.2 - -From 4a2ca2d4e87c84a57dde064296822860701fc877 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 15 Mar 2021 21:59:00 +0300 -Subject: [PATCH 08/16] kernel32: Implement GetPackagesByPackageFamily(). - ---- - .../api-ms-win-appmodel-runtime-l1-1-1.spec | 2 +- - .../ext-ms-win-kernel32-package-l1-1-1.spec | 2 +- - dlls/kernel32/kernel32.spec | 1 + - dlls/kernel32/tests/version.c | 131 ++++++++++++++++++ - dlls/kernelbase/kernelbase.spec | 2 +- - dlls/kernelbase/version.c | 115 +++++++++++++++ - include/appmodel.h | 2 + - 7 files changed, 252 insertions(+), 3 deletions(-) - -diff --git a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -index 99d1d9f3835..696bb75be30 100644 ---- a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -+++ b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -@@ -15,7 +15,7 @@ - @ stub GetPackageInfo - @ stub GetPackagePath - @ stub GetPackagePathByFullName --@ stub GetPackagesByPackageFamily -+@ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernel32.GetPackagesByPackageFamily - @ stub GetStagedPackageOrigin - @ stub GetStagedPackagePathByFullName - @ stub OpenPackageInfoByFullName -diff --git a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -index 61fd115cca7..ff5118049e2 100644 ---- a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -+++ b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -@@ -12,7 +12,7 @@ - @ stub GetPackageId - @ stub GetPackageInfo - @ stub GetPackagePath --@ stub GetPackagesByPackageFamily -+@ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernel32.GetPackagesByPackageFamily - @ stub GetStagedPackageOrigin - @ stub OpenPackageInfoByFullName - @ stub PackageFamilyNameFromFullName -diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec -index bcaf2512990..59785a6de24 100644 ---- a/dlls/kernel32/kernel32.spec -+++ b/dlls/kernel32/kernel32.spec -@@ -765,6 +765,7 @@ - @ stdcall -import GetOverlappedResultEx(long ptr ptr long long) - @ stdcall -import GetUserDefaultGeoName(ptr long) - @ stdcall -import GetUserPreferredUILanguages(long ptr ptr ptr) -+@ stdcall -import GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) - @ stdcall GetPackageFamilyName(long ptr ptr) kernelbase.GetPackageFamilyName - @ stdcall GetPackageFullName(long ptr ptr) kernelbase.GetPackageFullName - @ stdcall -import GetPhysicallyInstalledSystemMemory(ptr) -diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c -index 835c5398685..9a35d679323 100644 ---- a/dlls/kernel32/tests/version.c -+++ b/dlls/kernel32/tests/version.c -@@ -23,6 +23,7 @@ - #include "winternl.h" - #include "appmodel.h" - -+static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); - static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); - static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); - static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); -@@ -43,6 +44,7 @@ static void init_function_pointers(void) - - hmod = GetModuleHandleA("kernel32.dll"); - -+ GET_PROC(GetPackagesByPackageFamily); - GET_PROC(GetProductInfo); - GET_PROC(GetSystemFirmwareTable); - GET_PROC(PackageIdFromFullName); -@@ -918,6 +920,134 @@ static void test_PackageIdFromFullName(void) - ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); - } - -+static void test_package_info(void) -+{ -+ static const WCHAR package_family_msvc140[] = L"Microsoft.VCLibs.140.00_8wekyb3d8bbwe"; -+ UINT32 count, length, curr_length, size; -+ WCHAR *full_names[32]; -+ BYTE id_buffer[512]; -+ WCHAR buffer[2048]; -+ BOOL arch_found; -+ SYSTEM_INFO si; -+ unsigned int i; -+ PACKAGE_ID *id; -+ DWORD arch; -+ LONG ret; -+ -+ if (!pGetPackagesByPackageFamily) -+ { -+ win_skip("GetPackagesByPackageFamily not available.\n"); -+ return; -+ } -+ -+ GetSystemInfo(&si); -+ arch = si.wProcessorArchitecture; -+ -+ count = 0; -+ length = 0; -+ ret = pGetPackagesByPackageFamily(L"Unknown_8wekyb3d8bbwe", &count, NULL, &length, NULL); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ ok(!count, "Got unexpected count %u.\n", count); -+ ok(!length, "Got unexpected length %u.\n", length); -+ -+ count = 0; -+ length = 0; -+ ret = pGetPackagesByPackageFamily(L"Unknown_iekyb3d8bbwe", &count, NULL, &length, NULL); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ ok(!count, "Got unexpected count %u.\n", count); -+ ok(!length, "Got unexpected length %u.\n", length); -+ -+ count = 0xdeadbeef; -+ length = 0xdeadbeef; -+ ret = pGetPackagesByPackageFamily(L"Unknown", &count, NULL, &length, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ ok(count == 0xdeadbeef, "Got unexpected count %u.\n", count); -+ ok(length == 0xdeadbeef, "Got unexpected length %u.\n", length); -+ -+ count = 0; -+ length = 0; -+ ret = pGetPackagesByPackageFamily(L"Unknown", &count, NULL, &length, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ ok(!count, "Got unexpected count %u.\n", count); -+ ok(!length, "Got unexpected length %u.\n", length); -+ -+ count = 0; -+ length = 0; -+ ret = pGetPackagesByPackageFamily(L"Unknown_8wekyb3d8bbwe_b", &count, NULL, &length, NULL); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ ok(!count, "Got unexpected count %u.\n", count); -+ ok(!length, "Got unexpected length %u.\n", length); -+ -+ count = 0; -+ length = 0; -+ ret = pGetPackagesByPackageFamily(L"Unknown_", &count, NULL, &length, NULL); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ ok(!count, "Got unexpected count %u.\n", count); -+ ok(!length, "Got unexpected length %u.\n", length); -+ -+ length = 0; -+ ret = pGetPackagesByPackageFamily(package_family_msvc140, NULL, NULL, &length, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ ok(!length, "Got unexpected length %u.\n", length); -+ -+ count = 0; -+ ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, NULL, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ ok(!count, "Got unexpected count %u.\n", count); -+ -+ count = ARRAY_SIZE(full_names); -+ length = ARRAY_SIZE(buffer); -+ ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); -+ ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); -+ -+ ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, full_names, &length, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); -+ ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); -+ -+ ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, buffer); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); -+ ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); -+ -+ count = 0; -+ length = 0; -+ ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); -+ if (!ret && !count && !length) -+ { -+ win_skip("Package VCLibs.140.00 is not installed.\n"); -+ return; -+ } -+ -+ ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); -+ ok(count >= 1, "Got unexpected count %u.\n", count); -+ ok(length > 1, "Got unexpected length %u.\n", length); -+ -+ ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, full_names, &length, buffer); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ ok(count >= 1, "Got unexpected count %u.\n", count); -+ ok(length > 1, "Got unexpected length %u.\n", length); -+ -+ id = (PACKAGE_ID *)id_buffer; -+ curr_length = 0; -+ arch_found = FALSE; -+ for (i = 0; i < count; ++i) -+ { -+ curr_length += lstrlenW(full_names[i]) + 1; -+ -+ size = sizeof(id_buffer); -+ ret = pPackageIdFromFullName(full_names[i], 0, &size, id_buffer); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ -+ if (id->processorArchitecture == arch) -+ arch_found = TRUE; -+ } -+ ok(curr_length == length, "Got unexpected length %u.\n", length); -+ ok(arch_found, "Did not find package for current arch.\n"); -+} -+ - START_TEST(version) - { - init_function_pointers(); -@@ -927,4 +1057,5 @@ START_TEST(version) - test_VerifyVersionInfo(); - test_GetSystemFirmwareTable(); - test_PackageIdFromFullName(); -+ test_package_info(); - } -diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec -index b42a9af8b8e..5d21680f512 100644 ---- a/dlls/kernelbase/kernelbase.spec -+++ b/dlls/kernelbase/kernelbase.spec -@@ -614,7 +614,7 @@ - # @ stub GetPackageStatusForUser - # @ stub GetPackageTargetPlatformProperty - # @ stub GetPackageVolumeSisPath --# @ stub GetPackagesByPackageFamily -+@ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) - @ stdcall GetPerformanceInfo(ptr long) - @ stdcall GetPhysicallyInstalledSystemMemory(ptr) - # @ stub GetPreviousFgPolicyRefreshInfoInternal -diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c -index 66bd619e394..dca4ffb8647 100644 ---- a/dlls/kernelbase/version.c -+++ b/dlls/kernelbase/version.c -@@ -39,10 +39,12 @@ - #include "winnls.h" - #include "winternl.h" - #include "winerror.h" -+#include "winreg.h" - #include "appmodel.h" - - #include "kernelbase.h" - #include "wine/debug.h" -+#include "wine/heap.h" - - WINE_DEFAULT_DEBUG_CHANNEL(ver); - -@@ -154,6 +156,8 @@ static const struct - } - }; - -+static const WCHAR packages_key_name[] = L"Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows" -+ L"\\CurrentVersion\\AppModel\\PackageRepository\\Packages"; - - /****************************************************************************** - * init_current_version -@@ -1681,3 +1685,114 @@ LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 * - - return ERROR_SUCCESS; - } -+ -+ -+/*********************************************************************** -+ * GetPackagesByPackageFamily (kernelbase.@) -+ */ -+LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, -+ UINT32 *buffer_length, WCHAR *buffer) -+{ -+ UINT32 curr_count, curr_length, package_id_buf_size, size; -+ unsigned int i, name_len, publisher_id_len; -+ DWORD subkey_count, max_key_len, length; -+ const WCHAR *publisher_id; -+ WCHAR *package_name; -+ BOOL short_buffer; -+ PACKAGE_ID *id; -+ HKEY key; -+ -+ TRACE("family_name %s, count %p, full_names %p, buffer_length %p, buffer %p.\n", -+ debugstr_w(family_name), count, full_names, buffer_length, buffer); -+ -+ if (!buffer_length || !count || !family_name) -+ return ERROR_INVALID_PARAMETER; -+ -+ if ((*buffer_length || *count) && (!full_names || !buffer)) -+ return ERROR_INVALID_PARAMETER; -+ -+ if (!(publisher_id = wcschr(family_name, L'_'))) -+ return ERROR_INVALID_PARAMETER; -+ -+ name_len = publisher_id - family_name; -+ ++publisher_id; -+ publisher_id_len = lstrlenW(publisher_id); -+ -+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, packages_key_name, 0, KEY_READ, &key)) -+ { -+ ERR("Key open failed.\n"); -+ *count = 0; -+ *buffer_length = 0; -+ return ERROR_SUCCESS; -+ } -+ if (RegQueryInfoKeyW(key, NULL, NULL, NULL, &subkey_count, &max_key_len, NULL, NULL, NULL, NULL, NULL, NULL)) -+ { -+ ERR("Query key info failed.\n"); -+ RegCloseKey(key); -+ *count = 0; -+ *buffer_length = 0; -+ return ERROR_SUCCESS; -+ } -+ -+ if (!(package_name = heap_alloc((max_key_len + 1) * sizeof(*package_name)))) -+ { -+ ERR("No memory.\n"); -+ RegCloseKey(key); -+ return ERROR_OUTOFMEMORY; -+ } -+ -+ package_id_buf_size = sizeof(*id) + (max_key_len + 1) * sizeof(WCHAR); -+ if (!(id = heap_alloc(package_id_buf_size))) -+ { -+ ERR("No memory.\n"); -+ heap_free(package_name); -+ RegCloseKey(key); -+ return ERROR_OUTOFMEMORY; -+ } -+ -+ curr_count = curr_length = 0; -+ for (i = 0; i < subkey_count; ++i) -+ { -+ length = max_key_len + 1; -+ if (RegEnumKeyExW(key, i, package_name, &length, NULL, NULL, NULL, NULL)) -+ { -+ ERR("Error enumerating key %u.\n", i); -+ continue; -+ } -+ -+ size = package_id_buf_size; -+ if (PackageIdFromFullName(package_name, 0, &size, (BYTE *)id)) -+ { -+ ERR("Error getting package id from full name.\n"); -+ continue; -+ } -+ -+ if (lstrlenW(id->name) != name_len) -+ continue; -+ if (wcsnicmp(family_name, id->name, name_len)) -+ continue; -+ -+ if (lstrlenW(id->publisherId) != publisher_id_len) -+ continue; -+ if (wcsnicmp(publisher_id, id->publisherId, publisher_id_len)) -+ continue; -+ if (curr_length + length < *buffer_length) -+ { -+ memcpy(buffer + curr_length, package_name, (length + 1) * sizeof(*package_name)); -+ if (curr_count < *count) -+ full_names[curr_count] = buffer + curr_length; -+ } -+ curr_length += length + 1; -+ ++curr_count; -+ } -+ -+ heap_free(id); -+ heap_free(package_name); -+ RegCloseKey(key); -+ -+ short_buffer = curr_length > *buffer_length || curr_count > *count; -+ *count = curr_count; -+ *buffer_length = curr_length; -+ -+ return short_buffer ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS; -+} -diff --git a/include/appmodel.h b/include/appmodel.h -index e4288bbfbb0..27a0d0a8646 100644 ---- a/include/appmodel.h -+++ b/include/appmodel.h -@@ -82,6 +82,8 @@ LONG WINAPI AppPolicyGetProcessTerminationMethod(HANDLE token, AppPolicyProcessT - LONG WINAPI AppPolicyGetShowDeveloperDiagnostic(HANDLE token, AppPolicyShowDeveloperDiagnostic *policy); - LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadInitializationType *policy); - LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); -+LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, -+ UINT32 *buffer_length, WCHAR *buffer); - LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *buffer_length, BYTE *buffer); - - #if defined(__cplusplus) --- -2.30.2 - -From 1bf233880b472769e5b560a3d50adbbecfeb5736 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 26 Mar 2021 01:10:08 +0300 -Subject: [PATCH 09/16] kernel32: Implement PackageFullNameFromId(). - ---- - .../api-ms-win-appmodel-runtime-l1-1-1.spec | 2 +- - .../ext-ms-win-kernel32-package-l1-1-1.spec | 2 +- - dlls/kernel32/kernel32.spec | 1 + - dlls/kernel32/tests/version.c | 22 +++++++++- - dlls/kernelbase/kernelbase.spec | 2 +- - dlls/kernelbase/version.c | 43 +++++++++++++++++++ - include/appmodel.h | 1 + - 7 files changed, 69 insertions(+), 4 deletions(-) - -diff --git a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -index 696bb75be30..72a0a33baf5 100644 ---- a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -+++ b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -@@ -17,5 +17,5 @@ - @ stub OpenPackageInfoByFullName - @ stub PackageFamilyNameFromFullName - @ stub PackageFamilyNameFromId --@ stub PackageFullNameFromId -+@ stdcall PackageFullNameFromId(ptr ptr ptr) kernel32.PackageFullNameFromId - @ stdcall PackageIdFromFullName(wstr long ptr ptr) kernelbase.PackageIdFromFullName -diff --git a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -index ff5118049e2..42566176b56 100644 ---- a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -+++ b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -@@ -17,5 +17,5 @@ - @ stub OpenPackageInfoByFullName - @ stub PackageFamilyNameFromFullName - @ stub PackageFamilyNameFromId --@ stub PackageFullNameFromId -+@ stdcall PackageFullNameFromId(ptr ptr ptr) kernel32.PackageFullNameFromId - @ stdcall PackageIdFromFullName(wstr long ptr ptr) kernelbase.PackageIdFromFullName -diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec -index 59785a6de24..491f5ca0402 100644 ---- a/dlls/kernel32/kernel32.spec -+++ b/dlls/kernel32/kernel32.spec -@@ -1152,6 +1152,7 @@ - @ stdcall -import PeekConsoleInputW(ptr ptr long ptr) - @ stdcall -import PeekNamedPipe(long ptr long ptr ptr ptr) - @ stdcall -import PostQueuedCompletionStatus(long long ptr ptr) -+@ stdcall -import PackageFullNameFromId(ptr ptr ptr) - @ stdcall -import PackageIdFromFullName(wstr long ptr ptr) - @ stdcall PowerClearRequest(long long) - @ stdcall PowerCreateRequest(ptr) -diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c -index 9a35d679323..ed1ef3e3bf7 100644 ---- a/dlls/kernel32/tests/version.c -+++ b/dlls/kernel32/tests/version.c -@@ -26,6 +26,7 @@ - static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); - static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); - static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); -+static LONG (WINAPI * pPackageFullNameFromId)(const PACKAGE_ID *, UINT32 *, WCHAR *); - static LONG (WINAPI * pPackageIdFromFullName)(const WCHAR *, UINT32, UINT32 *, BYTE *); - static NTSTATUS (WINAPI * pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, void *, ULONG, ULONG *); - static NTSTATUS (WINAPI * pRtlGetVersion)(RTL_OSVERSIONINFOEXW *); -@@ -47,6 +48,7 @@ static void init_function_pointers(void) - GET_PROC(GetPackagesByPackageFamily); - GET_PROC(GetProductInfo); - GET_PROC(GetSystemFirmwareTable); -+ GET_PROC(PackageFullNameFromId); - GET_PROC(PackageIdFromFullName); - - hmod = GetModuleHandleA("ntdll.dll"); -@@ -803,9 +805,11 @@ static void test_PackageIdFromFullName(void) - { - 0, PROCESSOR_ARCHITECTURE_INTEL, - {{.Major = 1, .Minor = 2, .Build = 3, .Revision = 4}}, -- (WCHAR *)L"TestPackage", NULL, -+ (WCHAR *)L"TestPackage", (WCHAR *)L"TestResource", - (WCHAR *)L"TestResourceId", (WCHAR *)L"0abcdefghjkme" - }; -+ static const WCHAR test_package_fullname[] = -+ L"TestPackage_1.2.3.4_x86_TestResourceId_0abcdefghjkme"; - UINT32 size, expected_size; - PACKAGE_ID test_id; - WCHAR fullname[512]; -@@ -918,6 +922,22 @@ static void test_PackageIdFromFullName(void) - size = sizeof(id_buffer); - ret = pPackageIdFromFullName(L"TestPackage_1.2.3.4_X86_0abcdefghjkme", 0, &size, id_buffer); - ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ -+ ret = pPackageFullNameFromId(&test_package_id, NULL, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ -+ size = sizeof(fullname); -+ ret = pPackageFullNameFromId(&test_package_id, &size, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ -+ size = 0; -+ ret = pPackageFullNameFromId(&test_package_id, &size, NULL); -+ ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); -+ ok(size == lstrlenW(test_package_fullname) + 1, "Got unexpected size %u.\n", size); -+ -+ ret = pPackageFullNameFromId(&test_package_id, &size, fullname); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ ok(!lstrcmpW(fullname, test_package_fullname), "Got unexpected fullname %s.\n", debugstr_w(fullname)); - } - - static void test_package_info(void) -diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec -index 5d21680f512..81d88b1a33a 100644 ---- a/dlls/kernelbase/kernelbase.spec -+++ b/dlls/kernelbase/kernelbase.spec -@@ -1012,7 +1012,7 @@ - # @ stub PackageFamilyNameFromFullName - # @ stub PackageFamilyNameFromId - # @ stub PackageFamilyNameFromProductId --# @ stub PackageFullNameFromId -+@ stdcall PackageFullNameFromId(ptr ptr ptr) - # @ stub PackageFullNameFromProductId - @ stdcall PackageIdFromFullName(wstr long ptr ptr) - # @ stub PackageIdFromProductId -diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c -index dca4ffb8647..560e45e965a 100644 ---- a/dlls/kernelbase/version.c -+++ b/dlls/kernelbase/version.c -@@ -1597,6 +1597,16 @@ static UINT32 processor_arch_from_string(const WCHAR *str, unsigned int len) - return ~0u; - } - -+const WCHAR *string_from_processor_arch(UINT32 code) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(arch_names); ++i) -+ if (code == arch_names[i].code) -+ return arch_names[i].name; -+ return NULL; -+} -+ - /*********************************************************************** - * PackageIdFromFullName (kernelbase.@) - */ -@@ -1687,6 +1697,39 @@ LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 * - } - - -+/*********************************************************************** -+ * PackageFullNameFromId (kernelbase.@) -+ */ -+LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name) -+{ -+ WCHAR ver_str[5 * 4 + 3 + 1]; -+ const WCHAR *arch_str; -+ UINT32 have_length; -+ -+ TRACE("package_id %p, length %p, full_name %p.\n", package_id, length, full_name); -+ -+ if (!package_id || !length) -+ return ERROR_INVALID_PARAMETER; -+ if (!full_name && *length) -+ return ERROR_INVALID_PARAMETER; -+ if (!package_id->name || !package_id->resourceId || !package_id->publisherId -+ || !(arch_str = string_from_processor_arch(package_id->processorArchitecture))) -+ return ERROR_INVALID_PARAMETER; -+ -+ swprintf(ver_str, ARRAY_SIZE(ver_str), L"%u.%u.%u.%u", package_id->version.u.s.Major, -+ package_id->version.u.s.Minor, package_id->version.u.s.Build, package_id->version.u.s.Revision); -+ have_length = *length; -+ *length = lstrlenW(package_id->name) + 1 + lstrlenW(ver_str) + 1 + lstrlenW(arch_str) + 1 -+ + lstrlenW(package_id->resourceId) + 1 + lstrlenW(package_id->publisherId) + 1; -+ -+ if (have_length < *length) -+ return ERROR_INSUFFICIENT_BUFFER; -+ -+ swprintf(full_name, *length, L"%s_%s_%s_%s_%s", package_id->name, ver_str, arch_str, package_id->resourceId, package_id->publisherId); -+ return ERROR_SUCCESS; -+} -+ -+ - /*********************************************************************** - * GetPackagesByPackageFamily (kernelbase.@) - */ -diff --git a/include/appmodel.h b/include/appmodel.h -index 27a0d0a8646..be59bc70f5f 100644 ---- a/include/appmodel.h -+++ b/include/appmodel.h -@@ -84,6 +84,7 @@ LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadIn - LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); - LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, - UINT32 *buffer_length, WCHAR *buffer); -+LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name); - LONG WINAPI PackageIdFromFullName(const WCHAR *full_name, UINT32 flags, UINT32 *buffer_length, BYTE *buffer); - - #if defined(__cplusplus) --- -2.30.2 - -From fb64ea93325eb2d4aa9be77c3e2b07ca20052c3d Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 15 Mar 2021 22:05:19 +0300 -Subject: [PATCH 10/16] kernel32: Implement GetPackagePath(). - ---- - .../api-ms-win-appmodel-runtime-l1-1-1.spec | 2 +- - .../ext-ms-win-kernel32-package-l1-1-1.spec | 2 +- - dlls/kernel32/kernel32.spec | 1 + - dlls/kernel32/tests/version.c | 64 +++++++++++++-- - dlls/kernelbase/kernelbase.spec | 2 +- - dlls/kernelbase/version.c | 82 +++++++++++++++++++ - include/appmodel.h | 1 + - 7 files changed, 146 insertions(+), 8 deletions(-) - -diff --git a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -index 72a0a33baf5..e77ac397b03 100644 ---- a/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -+++ b/dlls/api-ms-win-appmodel-runtime-l1-1-1/api-ms-win-appmodel-runtime-l1-1-1.spec -@@ -13,7 +13,7 @@ - @ stdcall GetPackageFullName(long ptr ptr) kernel32.GetPackageFullName - @ stub GetPackageId - @ stub GetPackageInfo --@ stub GetPackagePath -+@ stdcall GetPackagePath(ptr long ptr ptr) kernel32.GetPackagePath - @ stub GetPackagePathByFullName - @ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernel32.GetPackagesByPackageFamily - @ stub GetStagedPackageOrigin -diff --git a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -index 42566176b56..58bf807b4be 100644 ---- a/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -+++ b/dlls/ext-ms-win-kernel32-package-l1-1-1/ext-ms-win-kernel32-package-l1-1-1.spec -@@ -11,7 +11,7 @@ - @ stdcall GetPackageFullName(long ptr ptr) kernel32.GetPackageFullName - @ stub GetPackageId - @ stub GetPackageInfo --@ stub GetPackagePath -+@ stdcall GetPackagePath(ptr long ptr ptr) kernel32.GetPackagePath - @ stdcall GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) kernel32.GetPackagesByPackageFamily - @ stub GetStagedPackageOrigin - @ stub OpenPackageInfoByFullName -diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec -index 491f5ca0402..6b1030b00df 100644 ---- a/dlls/kernel32/kernel32.spec -+++ b/dlls/kernel32/kernel32.spec -@@ -768,6 +768,7 @@ - @ stdcall -import GetPackagesByPackageFamily(wstr ptr ptr ptr ptr) - @ stdcall GetPackageFamilyName(long ptr ptr) kernelbase.GetPackageFamilyName - @ stdcall GetPackageFullName(long ptr ptr) kernelbase.GetPackageFullName -+@ stdcall -import GetPackagePath(ptr long ptr ptr) - @ stdcall -import GetPhysicallyInstalledSystemMemory(ptr) - @ stdcall -import GetPriorityClass(long) - @ stdcall GetPrivateProfileIntA(str str long str) -diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c -index ed1ef3e3bf7..1d5dc550d46 100644 ---- a/dlls/kernel32/tests/version.c -+++ b/dlls/kernel32/tests/version.c -@@ -23,6 +23,7 @@ - #include "winternl.h" - #include "appmodel.h" - -+static LONG (WINAPI * pGetPackagePath)(const PACKAGE_ID *, const UINT32, UINT32 *, WCHAR *); - static LONG (WINAPI * pGetPackagesByPackageFamily)(const WCHAR *, UINT32 *, WCHAR **, UINT32 *, WCHAR *); - static BOOL (WINAPI * pGetProductInfo)(DWORD, DWORD, DWORD, DWORD, DWORD *); - static UINT (WINAPI * pGetSystemFirmwareTable)(DWORD, DWORD, void *, DWORD); -@@ -45,6 +46,7 @@ static void init_function_pointers(void) - - hmod = GetModuleHandleA("kernel32.dll"); - -+ GET_PROC(GetPackagePath); - GET_PROC(GetPackagesByPackageFamily); - GET_PROC(GetProductInfo); - GET_PROC(GetSystemFirmwareTable); -@@ -943,15 +945,15 @@ static void test_PackageIdFromFullName(void) - static void test_package_info(void) - { - static const WCHAR package_family_msvc140[] = L"Microsoft.VCLibs.140.00_8wekyb3d8bbwe"; -- UINT32 count, length, curr_length, size; -+ UINT32 count, length, curr_length, size, path_length, total_length; -+ WCHAR buffer[2048], path[MAX_PATH]; -+ PACKAGE_ID *id, saved_id; - WCHAR *full_names[32]; - BYTE id_buffer[512]; -- WCHAR buffer[2048]; -+ DWORD arch, attrib; - BOOL arch_found; - SYSTEM_INFO si; - unsigned int i; -- PACKAGE_ID *id; -- DWORD arch; - LONG ret; - - if (!pGetPackagesByPackageFamily) -@@ -1032,6 +1034,10 @@ static void test_package_info(void) - ok(count == ARRAY_SIZE(full_names), "Got unexpected count %u.\n", count); - ok(length == ARRAY_SIZE(buffer), "Got unexpected length %u.\n", length); - -+ length = 0; -+ ret = pGetPackagePath(NULL, 0, &length, NULL); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ - count = 0; - length = 0; - ret = pGetPackagesByPackageFamily(package_family_msvc140, &count, NULL, &length, NULL); -@@ -1050,6 +1056,7 @@ static void test_package_info(void) - ok(count >= 1, "Got unexpected count %u.\n", count); - ok(length > 1, "Got unexpected length %u.\n", length); - -+ total_length = length; - id = (PACKAGE_ID *)id_buffer; - curr_length = 0; - arch_found = FALSE; -@@ -1063,9 +1070,56 @@ static void test_package_info(void) - - if (id->processorArchitecture == arch) - arch_found = TRUE; -+ -+ path_length = 0; -+ ret = pGetPackagePath(id, 0, &path_length, NULL); -+ ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got unexpected ret %u.\n", ret); -+ ok(path_length > 1, "Got unexpected path_length %u.\n", path_length); -+ -+ length = path_length; -+ ret = pGetPackagePath(id, 0, &length, path); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ ok(length == path_length, "Got unexpected length %u.\n", length); -+ attrib = GetFileAttributesW(path); -+ ok(attrib != INVALID_FILE_ATTRIBUTES && attrib & FILE_ATTRIBUTE_DIRECTORY, -+ "Got unexpected attrib %#x, GetLastError() %u.\n", attrib, GetLastError()); - } -- ok(curr_length == length, "Got unexpected length %u.\n", length); -+ ok(curr_length == total_length, "Got unexpected length %u.\n", length); - ok(arch_found, "Did not find package for current arch.\n"); -+ -+ size = sizeof(id_buffer); -+ ret = pPackageIdFromFullName(full_names[0], 0, &size, id_buffer); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ saved_id = *id; -+ -+ id->publisherId = NULL; -+ length = ARRAY_SIZE(path); -+ ret = pGetPackagePath(id, 0, &length, path); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ -+ *id = saved_id; -+ id->name = NULL; -+ length = ARRAY_SIZE(path); -+ ret = pGetPackagePath(id, 0, &length, path); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ -+ *id = saved_id; -+ id->publisher = NULL; -+ length = ARRAY_SIZE(path); -+ ret = pGetPackagePath(id, 0, &length, path); -+ ok(ret == ERROR_SUCCESS, "Got unexpected ret %u.\n", ret); -+ -+ *id = saved_id; -+ id->processorArchitecture = ~0u; -+ length = ARRAY_SIZE(path); -+ ret = pGetPackagePath(id, 0, &length, path); -+ ok(ret == ERROR_INVALID_PARAMETER, "Got unexpected ret %u.\n", ret); -+ -+ *id = saved_id; -+ id->name[0] = L'X'; -+ length = ARRAY_SIZE(path); -+ ret = pGetPackagePath(id, 0, &length, path); -+ ok(ret == ERROR_NOT_FOUND, "Got unexpected ret %u.\n", ret); - } - - START_TEST(version) -diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec -index 81d88b1a33a..0b374a53b60 100644 ---- a/dlls/kernelbase/kernelbase.spec -+++ b/dlls/kernelbase/kernelbase.spec -@@ -601,7 +601,7 @@ - # @ stub GetPackageInfo - # @ stub GetPackageInstallTime - # @ stub GetPackageOSMaxVersionTested --# @ stub GetPackagePath -+@ stdcall GetPackagePath(ptr long ptr ptr) - # @ stub GetPackagePathByFullName - # @ stub GetPackagePathOnVolume - # @ stub GetPackageProperty -diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c -index 560e45e965a..1f16194a565 100644 ---- a/dlls/kernelbase/version.c -+++ b/dlls/kernelbase/version.c -@@ -1839,3 +1839,85 @@ LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, - - return short_buffer ? ERROR_INSUFFICIENT_BUFFER : ERROR_SUCCESS; - } -+ -+ -+/*********************************************************************** -+ * GetPackagePath (kernelbase.@) -+ */ -+LONG WINAPI GetPackagePath(const PACKAGE_ID *package_id, const UINT32 reserved, UINT32 *length, WCHAR *path) -+{ -+ WCHAR *key_name = NULL, *expanded_path = NULL; -+ UINT32 required_length, have_length; -+ unsigned int offset; -+ HKEY key = NULL; -+ DWORD size; -+ LONG ret; -+ -+ TRACE("package_id %p, reserved %u, length %p, path %p.\n", package_id, reserved, length, path); -+ -+ if (!length) -+ return ERROR_INVALID_PARAMETER; -+ if (!path && *length) -+ return ERROR_INVALID_PARAMETER; -+ -+ required_length = 0; -+ if ((ret = PackageFullNameFromId(package_id, &required_length, NULL)) != ERROR_INSUFFICIENT_BUFFER) -+ return ret; -+ -+ offset = lstrlenW(packages_key_name) + 1; -+ if (!(key_name = heap_alloc((offset + required_length) * sizeof(WCHAR)))) -+ { -+ ERR("No memory."); -+ return ERROR_OUTOFMEMORY; -+ } -+ -+ if ((ret = PackageFullNameFromId(package_id, &required_length, key_name + offset))) -+ goto done; -+ -+ memcpy(key_name, packages_key_name, (offset - 1) * sizeof(WCHAR)); -+ key_name[offset - 1] = L'\\'; -+ -+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &key)) -+ { -+ WARN("Key %s not found.\n", debugstr_w(key_name)); -+ ret = ERROR_NOT_FOUND; -+ goto done; -+ } -+ if (RegGetValueW(key, NULL, L"Path", RRF_RT_REG_SZ, NULL, NULL, &size)) -+ { -+ WARN("Path value not found in %s.\n", debugstr_w(key_name)); -+ ret = ERROR_NOT_FOUND; -+ goto done; -+ } -+ if (!(expanded_path = heap_alloc(size))) -+ { -+ ERR("No memory."); -+ ret = ERROR_OUTOFMEMORY; -+ goto done; -+ } -+ if (RegGetValueW(key, NULL, L"Path", RRF_RT_REG_SZ, NULL, expanded_path, &size)) -+ { -+ WARN("Could not get Path value from %s.\n", debugstr_w(key_name)); -+ ret = ERROR_NOT_FOUND; -+ goto done; -+ } -+ -+ have_length = *length; -+ *length = lstrlenW(expanded_path) + 1; -+ if (have_length >= *length) -+ { -+ memcpy(path, expanded_path, *length * sizeof(*path)); -+ ret = ERROR_SUCCESS; -+ } -+ else -+ { -+ ret = ERROR_INSUFFICIENT_BUFFER; -+ } -+ -+done: -+ if (key) -+ RegCloseKey(key); -+ heap_free(expanded_path); -+ heap_free(key_name); -+ return ret; -+} -diff --git a/include/appmodel.h b/include/appmodel.h -index be59bc70f5f..c73cb8d26ef 100644 ---- a/include/appmodel.h -+++ b/include/appmodel.h -@@ -82,6 +82,7 @@ LONG WINAPI AppPolicyGetProcessTerminationMethod(HANDLE token, AppPolicyProcessT - LONG WINAPI AppPolicyGetShowDeveloperDiagnostic(HANDLE token, AppPolicyShowDeveloperDiagnostic *policy); - LONG WINAPI AppPolicyGetThreadInitializationType(HANDLE token, AppPolicyThreadInitializationType *policy); - LONG WINAPI AppPolicyGetWindowingModel(HANDLE processToken, AppPolicyWindowingModel *policy); -+LONG WINAPI GetPackagePath(const PACKAGE_ID *package_id, const UINT32 reserved, UINT32 *length, WCHAR *path); - LONG WINAPI GetPackagesByPackageFamily(const WCHAR *family_name, UINT32 *count, WCHAR **full_names, - UINT32 *buffer_length, WCHAR *buffer); - LONG WINAPI PackageFullNameFromId(const PACKAGE_ID *package_id, UINT32 *length, WCHAR *full_name); --- -2.30.2 - -From 995fdfb8cdb0a8eed82e16640034dc9673ded681 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 12 Mar 2021 23:58:39 +0300 -Subject: [PATCH 14/16] esync: Fix restoring the objects state on wait all - objects retry. - ---- - dlls/ntdll/unix/esync.c | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c -index 9a615fb277c..810477d02a0 100644 ---- a/dlls/ntdll/unix/esync.c -+++ b/dlls/ntdll/unix/esync.c -@@ -1168,10 +1168,22 @@ tryagain: - { - /* We were too slow. Put everything back. */ - value = 1; -- for (j = i; j >= 0; j--) -+ for (j = i - 1; j >= 0; j--) - { -- if (write( obj->fd, &value, sizeof(value) ) == -1) -+ struct esync *obj = objs[j]; -+ -+ if (obj->type == ESYNC_MUTEX) -+ { -+ struct mutex *mutex = obj->shm; -+ -+ if (mutex->tid == GetCurrentThreadId()) -+ continue; -+ } -+ if (write( fds[j].fd, &value, sizeof(value) ) == -1) -+ { -+ ERR("write failed.\n"); - return errno_to_status( errno ); -+ } - } - - goto tryagain; /* break out of two loops and a switch */ --- -2.30.2 - -From 47be204baf902d876fc5e5b0240b6167500ec0dd Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 29 Mar 2021 21:54:30 +0300 -Subject: [PATCH] dxgi: Use proxy IDXGISwapChain interface when importing that - from d3d implementation. - -For Origin overlay. - -Required for Origin overlay to work (which expects IDXGISwapChain -implementation methods to reside in dxgi.dll). ---- - dlls/dxgi/factory.c | 511 +++++++++++++++++++++++++++++++++++++++++- - dlls/dxgi/swapchain.c | 6 +- - 2 files changed, 509 insertions(+), 8 deletions(-) - -diff --git a/dlls/dxgi/factory.c b/dlls/dxgi/factory.c -index af18bdd2c32..020faa26a11 100644 ---- a/dlls/dxgi/factory.c -+++ b/dlls/dxgi/factory.c -@@ -29,7 +29,7 @@ static inline struct dxgi_factory *impl_from_IWineDXGIFactory(IWineDXGIFactory * - return CONTAINING_RECORD(iface, struct dxgi_factory, IWineDXGIFactory_iface); - } - --static HRESULT STDMETHODCALLTYPE dxgi_factory_QueryInterface(IWineDXGIFactory *iface, REFIID iid, void **out) -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH dxgi_factory_QueryInterface(IWineDXGIFactory *iface, REFIID iid, void **out) - { - struct dxgi_factory *factory = impl_from_IWineDXGIFactory(iface); - -@@ -58,7 +58,7 @@ static HRESULT STDMETHODCALLTYPE dxgi_factory_QueryInterface(IWineDXGIFactory *i - return E_NOINTERFACE; - } - --static ULONG STDMETHODCALLTYPE dxgi_factory_AddRef(IWineDXGIFactory *iface) -+static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH dxgi_factory_AddRef(IWineDXGIFactory *iface) - { - struct dxgi_factory *factory = impl_from_IWineDXGIFactory(iface); - ULONG refcount = InterlockedIncrement(&factory->refcount); -@@ -68,7 +68,7 @@ static ULONG STDMETHODCALLTYPE dxgi_factory_AddRef(IWineDXGIFactory *iface) - return refcount; - } - --static ULONG STDMETHODCALLTYPE dxgi_factory_Release(IWineDXGIFactory *iface) -+static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH dxgi_factory_Release(IWineDXGIFactory *iface) - { - struct dxgi_factory *factory = impl_from_IWineDXGIFactory(iface); - ULONG refcount = InterlockedDecrement(&factory->refcount); -@@ -267,7 +267,494 @@ static BOOL STDMETHODCALLTYPE dxgi_factory_IsWindowedStereoEnabled(IWineDXGIFact - return FALSE; - } - --static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSwapChainForHwnd(IWineDXGIFactory *iface, -+struct proxy_swapchain -+{ -+ IDXGISwapChain4 IDXGISwapChain4_iface; -+ IDXGISwapChain4 *swapchain; -+}; -+ -+static inline struct proxy_swapchain *proxy_swapchain_from_IDXGISwapChain4(IDXGISwapChain4 *iface) -+{ -+ return CONTAINING_RECORD(iface, struct proxy_swapchain, IDXGISwapChain4_iface); -+} -+ -+/* IUnknown methods */ -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_QueryInterface(IDXGISwapChain4 *iface, REFIID riid, void **object) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ TRACE("iface %p, riid %s, object %p\n", iface, debugstr_guid(riid), object); -+ -+ if (IsEqualGUID(riid, &IID_IUnknown) -+ || IsEqualGUID(riid, &IID_IDXGIObject) -+ || IsEqualGUID(riid, &IID_IDXGIDeviceSubObject) -+ || IsEqualGUID(riid, &IID_IDXGISwapChain) -+ || IsEqualGUID(riid, &IID_IDXGISwapChain1) -+ || IsEqualGUID(riid, &IID_IDXGISwapChain2) -+ || IsEqualGUID(riid, &IID_IDXGISwapChain3) -+ || IsEqualGUID(riid, &IID_IDXGISwapChain4)) -+ { -+ IDXGISwapChain4_AddRef(swapchain->swapchain); -+ *object = iface; -+ return S_OK; -+ } -+ -+ WARN("%s not implemented, returning E_NOINTERFACE\n", debugstr_guid(riid)); -+ -+ *object = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_AddRef(IDXGISwapChain4 *iface) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE("swapchain %p.\n", swapchain); -+ -+ return IDXGISwapChain4_AddRef(swapchain->swapchain); -+} -+ -+static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_Release(IDXGISwapChain4 *iface) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ ULONG refcount = IDXGISwapChain4_Release(swapchain->swapchain); -+ -+ TRACE("%p decreasing refcount to %u.\n", swapchain, refcount); -+ -+ if (!refcount) -+ heap_free(swapchain); -+ -+ return refcount; -+} -+ -+/* IDXGIObject methods */ -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetPrivateData(IDXGISwapChain4 *iface, -+ REFGUID guid, UINT data_size, const void *data) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface, debugstr_guid(guid), data_size, data); -+ -+ return IDXGISwapChain4_SetPrivateData(swapchain->swapchain, guid, data_size, data); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetPrivateDataInterface(IDXGISwapChain4 *iface, -+ REFGUID guid, const IUnknown *object) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE("iface %p, guid %s, object %p.\n", iface, debugstr_guid(guid), object); -+ -+ return IDXGISwapChain4_SetPrivateDataInterface(swapchain->swapchain, guid, object); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetPrivateData(IDXGISwapChain4 *iface, -+ REFGUID guid, UINT *data_size, void *data) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface, debugstr_guid(guid), data_size, data); -+ -+ return IDXGISwapChain4_GetPrivateData(swapchain->swapchain, guid, data_size, data); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetParent(IDXGISwapChain4 *iface, REFIID riid, void **parent) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE("iface %p, riid %s, parent %p.\n", iface, debugstr_guid(riid), parent); -+ -+ return IDXGISwapChain4_GetParent(swapchain->swapchain, riid, parent); -+} -+ -+/* IDXGIDeviceSubObject methods */ -+ -+static HRESULT STDMETHODCALLTYPE proxy_swapchain_GetDevice(IDXGISwapChain4 *iface, REFIID riid, void **device) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE("iface %p, riid %s, device %p.\n", iface, debugstr_guid(riid), device); -+ -+ return IDXGISwapChain4_GetDevice(swapchain->swapchain, riid, device); -+} -+ -+/* IDXGISwapChain methods */ -+ -+HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_Present(IDXGISwapChain4 *iface, UINT sync_interval, UINT flags) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE("iface %p, sync_interval %u, flags %#x.\n", iface, sync_interval, flags); -+ -+ return IDXGISwapChain4_Present(swapchain->swapchain, sync_interval, flags); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetBuffer(IDXGISwapChain4 *iface, -+ UINT buffer_idx, REFIID riid, void **surface) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetBuffer(swapchain->swapchain, buffer_idx, riid, surface); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetFullscreenState(IDXGISwapChain4 *iface, -+ BOOL fullscreen, IDXGIOutput *target) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_SetFullscreenState(swapchain->swapchain, fullscreen, target); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetFullscreenState(IDXGISwapChain4 *iface, -+ BOOL *fullscreen, IDXGIOutput **target) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetFullscreenState(swapchain->swapchain, fullscreen, target); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetDesc(IDXGISwapChain4 *iface, DXGI_SWAP_CHAIN_DESC *desc) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetDesc(swapchain->swapchain, desc); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_ResizeBuffers(IDXGISwapChain4 *iface, -+ UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_ResizeBuffers(swapchain->swapchain, buffer_count, width, height, format, flags); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_ResizeTarget(IDXGISwapChain4 *iface, -+ const DXGI_MODE_DESC *target_mode_desc) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_ResizeTarget(swapchain->swapchain, target_mode_desc); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetContainingOutput(IDXGISwapChain4 *iface, IDXGIOutput **output) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetContainingOutput(swapchain->swapchain, output); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetFrameStatistics(IDXGISwapChain4 *iface, -+ DXGI_FRAME_STATISTICS *stats) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetFrameStatistics(swapchain->swapchain, stats); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetLastPresentCount(IDXGISwapChain4 *iface, -+ UINT *last_present_count) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetLastPresentCount(swapchain->swapchain, last_present_count); -+} -+ -+/* IDXGISwapChain1 methods */ -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetDesc1(IDXGISwapChain4 *iface, DXGI_SWAP_CHAIN_DESC1 *desc) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetDesc1(swapchain->swapchain, desc); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetFullscreenDesc(IDXGISwapChain4 *iface, -+ DXGI_SWAP_CHAIN_FULLSCREEN_DESC *desc) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetFullscreenDesc(swapchain->swapchain, desc); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetHwnd(IDXGISwapChain4 *iface, HWND *hwnd) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetHwnd(swapchain->swapchain, hwnd); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetCoreWindow(IDXGISwapChain4 *iface, -+ REFIID iid, void **core_window) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetCoreWindow(swapchain->swapchain, iid, core_window); -+} -+ -+HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_Present1(IDXGISwapChain4 *iface, -+ UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_Present1(swapchain->swapchain, sync_interval, flags, present_parameters); -+} -+ -+static BOOL STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_IsTemporaryMonoSupported(IDXGISwapChain4 *iface) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_IsTemporaryMonoSupported(swapchain->swapchain); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetRestrictToOutput(IDXGISwapChain4 *iface, IDXGIOutput **output) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetRestrictToOutput(swapchain->swapchain, output); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetBackgroundColor(IDXGISwapChain4 *iface, const DXGI_RGBA *color) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_SetBackgroundColor(swapchain->swapchain, color); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetBackgroundColor(IDXGISwapChain4 *iface, DXGI_RGBA *color) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetBackgroundColor(swapchain->swapchain, color); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetRotation(IDXGISwapChain4 *iface, DXGI_MODE_ROTATION rotation) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_SetRotation(swapchain->swapchain, rotation); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetRotation(IDXGISwapChain4 *iface, DXGI_MODE_ROTATION *rotation) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetRotation(swapchain->swapchain, rotation); -+} -+ -+/* IDXGISwapChain2 methods */ -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetSourceSize(IDXGISwapChain4 *iface, UINT width, UINT height) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_SetSourceSize(swapchain->swapchain, width, height); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetSourceSize(IDXGISwapChain4 *iface, UINT *width, UINT *height) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetSourceSize(swapchain->swapchain, width, height); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetMaximumFrameLatency(IDXGISwapChain4 *iface, UINT max_latency) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_SetMaximumFrameLatency(swapchain->swapchain, max_latency); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetMaximumFrameLatency(IDXGISwapChain4 *iface, UINT *max_latency) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetMaximumFrameLatency(swapchain->swapchain, max_latency); -+} -+ -+static HANDLE STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetFrameLatencyWaitableObject(IDXGISwapChain4 *iface) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetFrameLatencyWaitableObject(swapchain->swapchain); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetMatrixTransform(IDXGISwapChain4 *iface, -+ const DXGI_MATRIX_3X2_F *matrix) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_SetMatrixTransform(swapchain->swapchain, matrix); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetMatrixTransform(IDXGISwapChain4 *iface, -+ DXGI_MATRIX_3X2_F *matrix) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetMatrixTransform(swapchain->swapchain, matrix); -+} -+ -+/* IDXGISwapChain3 methods */ -+ -+static UINT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_GetCurrentBackBufferIndex(IDXGISwapChain4 *iface) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_GetCurrentBackBufferIndex(swapchain->swapchain); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_CheckColorSpaceSupport(IDXGISwapChain4 *iface, -+ DXGI_COLOR_SPACE_TYPE colour_space, UINT *colour_space_support) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_CheckColorSpaceSupport(swapchain->swapchain, colour_space, colour_space_support); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetColorSpace1(IDXGISwapChain4 *iface, -+ DXGI_COLOR_SPACE_TYPE colour_space) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_SetColorSpace1(swapchain->swapchain, colour_space); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_ResizeBuffers1(IDXGISwapChain4 *iface, -+ UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags, -+ const UINT *node_mask, IUnknown * const *present_queue) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_ResizeBuffers1(swapchain->swapchain, buffer_count, width, height, format, flags, node_mask, present_queue); -+} -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH proxy_swapchain_SetHDRMetaData(IDXGISwapChain4 *iface, -+ DXGI_HDR_METADATA_TYPE type, UINT size, void *metadata) -+{ -+ struct proxy_swapchain *swapchain = proxy_swapchain_from_IDXGISwapChain4(iface); -+ -+ TRACE(".\n"); -+ -+ return IDXGISwapChain4_SetHDRMetaData(swapchain->swapchain, type, size, metadata); -+} -+ -+static const struct IDXGISwapChain4Vtbl proxy_swapchain_vtbl = -+{ -+ /* IUnknown methods */ -+ proxy_swapchain_QueryInterface, -+ proxy_swapchain_AddRef, -+ proxy_swapchain_Release, -+ /* IDXGIObject methods */ -+ proxy_swapchain_SetPrivateData, -+ proxy_swapchain_SetPrivateDataInterface, -+ proxy_swapchain_GetPrivateData, -+ proxy_swapchain_GetParent, -+ /* IDXGIDeviceSubObject methods */ -+ proxy_swapchain_GetDevice, -+ /* IDXGISwapChain methods */ -+ proxy_swapchain_Present, -+ proxy_swapchain_GetBuffer, -+ proxy_swapchain_SetFullscreenState, -+ proxy_swapchain_GetFullscreenState, -+ proxy_swapchain_GetDesc, -+ proxy_swapchain_ResizeBuffers, -+ proxy_swapchain_ResizeTarget, -+ proxy_swapchain_GetContainingOutput, -+ proxy_swapchain_GetFrameStatistics, -+ proxy_swapchain_GetLastPresentCount, -+ /* IDXGISwapChain1 methods */ -+ proxy_swapchain_GetDesc1, -+ proxy_swapchain_GetFullscreenDesc, -+ proxy_swapchain_GetHwnd, -+ proxy_swapchain_GetCoreWindow, -+ proxy_swapchain_Present1, -+ proxy_swapchain_IsTemporaryMonoSupported, -+ proxy_swapchain_GetRestrictToOutput, -+ proxy_swapchain_SetBackgroundColor, -+ proxy_swapchain_GetBackgroundColor, -+ proxy_swapchain_SetRotation, -+ proxy_swapchain_GetRotation, -+ /* IDXGISwapChain2 methods */ -+ proxy_swapchain_SetSourceSize, -+ proxy_swapchain_GetSourceSize, -+ proxy_swapchain_SetMaximumFrameLatency, -+ proxy_swapchain_GetMaximumFrameLatency, -+ proxy_swapchain_GetFrameLatencyWaitableObject, -+ proxy_swapchain_SetMatrixTransform, -+ proxy_swapchain_GetMatrixTransform, -+ /* IDXGISwapChain3 methods */ -+ proxy_swapchain_GetCurrentBackBufferIndex, -+ proxy_swapchain_CheckColorSpaceSupport, -+ proxy_swapchain_SetColorSpace1, -+ proxy_swapchain_ResizeBuffers1, -+ /* IDXGISwapChain4 methods */ -+ proxy_swapchain_SetHDRMetaData, -+}; -+ -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH dxgi_factory_CreateSwapChainForHwnd(IWineDXGIFactory *iface, - IUnknown *device, HWND window, const DXGI_SWAP_CHAIN_DESC1 *desc, - const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *fullscreen_desc, - IDXGIOutput *output, IDXGISwapChain1 **swapchain) -@@ -299,9 +786,23 @@ static HRESULT STDMETHODCALLTYPE dxgi_factory_CreateSwapChainForHwnd(IWineDXGIFa - - if (SUCCEEDED(IUnknown_QueryInterface(device, &IID_IWineDXGISwapChainFactory, (void **)&swapchain_factory))) - { -+ IDXGISwapChain4 *swapchain_impl; - hr = IWineDXGISwapChainFactory_create_swapchain(swapchain_factory, -- (IDXGIFactory *)iface, window, desc, fullscreen_desc, output, swapchain); -+ (IDXGIFactory *)iface, window, desc, fullscreen_desc, output, (IDXGISwapChain1 **)&swapchain_impl); - IWineDXGISwapChainFactory_Release(swapchain_factory); -+ if (SUCCEEDED(hr)) -+ { -+ struct proxy_swapchain *obj; -+ -+ obj = heap_alloc_zero(sizeof(*obj)); -+ obj->IDXGISwapChain4_iface.lpVtbl = &proxy_swapchain_vtbl; -+ obj->swapchain = swapchain_impl; -+ *swapchain = (IDXGISwapChain1 *)&obj->IDXGISwapChain4_iface; -+ } -+ else -+ { -+ *swapchain = NULL; -+ } - return hr; - } - -diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c -index 82e5fbf811d..b1153ac4927 100644 ---- a/dlls/dxgi/swapchain.c -+++ b/dlls/dxgi/swapchain.c -@@ -232,7 +232,7 @@ static ULONG STDMETHODCALLTYPE d3d11_swapchain_AddRef(IDXGISwapChain1 *iface) - return refcount; - } - --static ULONG STDMETHODCALLTYPE d3d11_swapchain_Release(IDXGISwapChain1 *iface) -+static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_Release(IDXGISwapChain1 *iface) - { - struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface); - ULONG refcount = InterlockedDecrement(&swapchain->refcount); -@@ -325,7 +325,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDevice(IDXGISwapChain1 *ifac - - /* IDXGISwapChain1 methods */ - --static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain, -+static HRESULT DECLSPEC_HOTPATCH d3d11_swapchain_present(struct d3d11_swapchain *swapchain, - unsigned int sync_interval, unsigned int flags) - { - if (sync_interval > 4) -@@ -697,7 +697,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetCoreWindow(IDXGISwapChain1 * - return DXGI_ERROR_INVALID_CALL; - } - --static HRESULT STDMETHODCALLTYPE d3d11_swapchain_Present1(IDXGISwapChain1 *iface, -+static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_Present1(IDXGISwapChain1 *iface, - UINT sync_interval, UINT flags, const DXGI_PRESENT_PARAMETERS *present_parameters) - { - struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain1(iface); -From 2fb560afba703185617bef6e277aa0cad3fcf681 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 30 Mar 2021 00:38:36 +0300 -Subject: [PATCH] dxgi: Specify an image base. - -For Origin overlay. ---- - dlls/dxgi/Makefile.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/dxgi/Makefile.in b/dlls/dxgi/Makefile.in -index c21cb18d8ff..1c626be213b 100644 ---- a/dlls/dxgi/Makefile.in -+++ b/dlls/dxgi/Makefile.in -@@ -3,7 +3,7 @@ IMPORTLIB = dxgi - IMPORTS = gdi32 dxguid uuid wined3d user32 - EXTRAINCL = $(VKD3D_CFLAGS) - --EXTRADLLFLAGS = -mcygwin -+EXTRADLLFLAGS = -Wl,--image-base,0x7bb00000 -mcygwin - - C_SRCS = \ - adapter.c \ -From fec2ecbd2dfd3c357f63c8f7bd9383b7a10d4553 Mon Sep 17 00:00:00 2001 -From: Esme Povirk -Date: Thu, 22 Apr 2021 14:35:40 -0500 -Subject: [PATCH] HACK: mscoree: For M&B2:Bannerlord, redirect ManagedStarter - loads to Bannerlord.exe - -For M&B2:Bannerlord. ---- - dlls/mscoree/metahost.c | 26 ++++++++++++++++++++++++++ - 1 file changed, 26 insertions(+) - -diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c -index d9b599fadc7..25acdced21e 100644 ---- a/dlls/mscoree/metahost.c -+++ b/dlls/mscoree/metahost.c -@@ -1742,6 +1742,32 @@ static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname - } - } - -+ if (!strcmp(assemblyname, "ManagedStarter")) -+ { -+ /* HACK for Mount & Blade II: Bannerlord -+ * -+ * The launcher executable uses an AssemblyResolve event handler -+ * to redirect loads of the "ManagedStarter" assembly to -+ * Bannerlord.exe. Due to Mono issue #11319, the runtime attempts -+ * to load ManagedStarter before executing the static constructor -+ * that adds this event handler. We work around this by doing the -+ * same thing in our own assembly load hook. */ -+ const char* sgi = getenv("SteamGameId"); -+ if (sgi && !strcmp(sgi, "261550")) -+ { -+ FIXME("hack, using Bannerlord.exe\n"); -+ -+ result = mono_assembly_open("Bannerlord.exe", &stat); -+ -+ if (result) -+ goto done; -+ else -+ { -+ ERR("Bannerlord.exe failed to load\n"); -+ } -+ } -+ } -+ - /* FIXME: We should search the given paths before the GAC. */ - - if ((search_flags & ASSEMBLY_SEARCH_GAC) != 0) -From 003223a6816f3121a8e60d8ef3ec79e1768878ce Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 7 May 2021 13:44:00 -0500 -Subject: [PATCH] HACK: dxgi: Return a static factory for RE8: Village - -CW-Bug-Id: 18923 ---- - dlls/dxgi/dxgi_main.c | 15 ++++++ - dlls/dxgi/dxgi_private.h | 2 + - dlls/dxgi/factory.c | 99 +++++++++++++++++++++++++++++++++++++++- - 3 files changed, 115 insertions(+), 1 deletion(-) - -diff --git a/dlls/dxgi/dxgi_main.c b/dlls/dxgi/dxgi_main.c -index 83c3f3734a7..941e23b3394 100644 ---- a/dlls/dxgi/dxgi_main.c -+++ b/dlls/dxgi/dxgi_main.c -@@ -56,6 +56,18 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, void *reserved) - return TRUE; - } - -+static BOOL is_re8(void) -+{ -+ static int status = -1; -+ -+ if(status < 0){ -+ const char *sgi = getenv("SteamGameId"); -+ status = sgi && !strcmp(sgi, "1196590"); -+ } -+ -+ return status != 0; -+} -+ - HRESULT WINAPI CreateDXGIFactory2(UINT flags, REFIID iid, void **factory) - { - TRACE("flags %#x, iid %s, factory %p.\n", flags, debugstr_guid(iid), factory); -@@ -70,6 +82,9 @@ HRESULT WINAPI CreateDXGIFactory1(REFIID iid, void **factory) - { - TRACE("iid %s, factory %p.\n", debugstr_guid(iid), factory); - -+ if(is_re8()) -+ return get_re8_dxgi_factory(iid, factory); -+ - return dxgi_factory_create(iid, factory, TRUE); - } - -diff --git a/dlls/dxgi/dxgi_private.h b/dlls/dxgi/dxgi_private.h -index acba3544e39..9d1b1cde342 100644 ---- a/dlls/dxgi/dxgi_private.h -+++ b/dlls/dxgi/dxgi_private.h -@@ -209,4 +209,6 @@ struct dxgi_surface - HRESULT dxgi_surface_init(struct dxgi_surface *surface, IDXGIDevice *device, - IUnknown *outer, struct wined3d_texture *wined3d_texture) DECLSPEC_HIDDEN; - -+HRESULT get_re8_dxgi_factory(REFIID riid, void **factory) DECLSPEC_HIDDEN; -+ - #endif /* __WINE_DXGI_PRIVATE_H */ -diff --git a/dlls/dxgi/factory.c b/dlls/dxgi/factory.c -index 020faa26a11..ba7d3e78905 100644 ---- a/dlls/dxgi/factory.c -+++ b/dlls/dxgi/factory.c -@@ -1044,6 +1044,8 @@ static const struct IWineDXGIFactoryVtbl dxgi_factory_vtbl = - dxgi_factory_UnregisterAdaptersChangedEvent, - }; - -+static const struct IWineDXGIFactoryVtbl re8_factory_vtbl; -+ - struct dxgi_factory *unsafe_impl_from_IDXGIFactory(IDXGIFactory *iface) - { - IWineDXGIFactory *wine_factory; -@@ -1057,7 +1059,8 @@ struct dxgi_factory *unsafe_impl_from_IDXGIFactory(IDXGIFactory *iface) - ERR("Failed to get IWineDXGIFactory interface, hr %#x.\n", hr); - return NULL; - } -- assert(wine_factory->lpVtbl == &dxgi_factory_vtbl); -+ assert(wine_factory->lpVtbl == &dxgi_factory_vtbl || -+ wine_factory->lpVtbl == &re8_factory_vtbl); - factory = CONTAINING_RECORD(wine_factory, struct dxgi_factory, IWineDXGIFactory_iface); - IWineDXGIFactory_Release(wine_factory); - return factory; -@@ -1125,3 +1128,97 @@ HWND dxgi_factory_get_device_window(struct dxgi_factory *factory) - - return factory->device_window; - } -+ -+/* re8 calls DXGICreateFactory1 over and over again, which is very expensive in -+ * Wine. instead just cache the first one we create and return that. */ -+static struct dxgi_factory re8_factory; -+ -+static CRITICAL_SECTION re8_factory_lock; -+static CRITICAL_SECTION_DEBUG re8_factory_lock_debug = -+{ -+ 0, 0, &re8_factory_lock, -+ { &re8_factory_lock_debug.ProcessLocksList, &re8_factory_lock_debug.ProcessLocksList }, -+ 0, 0, { (DWORD_PTR)(__FILE__ ": re8_factory_lock") } -+}; -+static CRITICAL_SECTION re8_factory_lock = { &re8_factory_lock_debug, -1, 0, 0, 0, 0 }; -+ -+static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH re8_factory_AddRef(IWineDXGIFactory *iface) -+{ -+ TRACE("%p static.\n", iface); -+ return re8_factory.refcount; -+} -+ -+static ULONG STDMETHODCALLTYPE DECLSPEC_HOTPATCH re8_factory_Release(IWineDXGIFactory *iface) -+{ -+ TRACE("%p static.\n", iface); -+ return re8_factory.refcount; -+} -+ -+static const struct IWineDXGIFactoryVtbl re8_factory_vtbl = -+{ -+ dxgi_factory_QueryInterface, -+ re8_factory_AddRef, -+ re8_factory_Release, -+ dxgi_factory_SetPrivateData, -+ dxgi_factory_SetPrivateDataInterface, -+ dxgi_factory_GetPrivateData, -+ dxgi_factory_GetParent, -+ dxgi_factory_EnumAdapters, -+ dxgi_factory_MakeWindowAssociation, -+ dxgi_factory_GetWindowAssociation, -+ dxgi_factory_CreateSwapChain, -+ dxgi_factory_CreateSoftwareAdapter, -+ /* IDXGIFactory1 methods */ -+ dxgi_factory_EnumAdapters1, -+ dxgi_factory_IsCurrent, -+ /* IDXGIFactory2 methods */ -+ dxgi_factory_IsWindowedStereoEnabled, -+ dxgi_factory_CreateSwapChainForHwnd, -+ dxgi_factory_CreateSwapChainForCoreWindow, -+ dxgi_factory_GetSharedResourceAdapterLuid, -+ dxgi_factory_RegisterStereoStatusWindow, -+ dxgi_factory_RegisterStereoStatusEvent, -+ dxgi_factory_UnregisterStereoStatus, -+ dxgi_factory_RegisterOcclusionStatusWindow, -+ dxgi_factory_RegisterOcclusionStatusEvent, -+ dxgi_factory_UnregisterOcclusionStatus, -+ dxgi_factory_CreateSwapChainForComposition, -+ /* IDXGIFactory3 methods */ -+ dxgi_factory_GetCreationFlags, -+ /* IDXGIFactory4 methods */ -+ dxgi_factory_EnumAdapterByLuid, -+ dxgi_factory_EnumWarpAdapter, -+ /* IDXIGFactory5 methods */ -+ dxgi_factory_CheckFeatureSupport, -+ /* IDXGIFactory6 methods */ -+ dxgi_factory_EnumAdapterByGpuPreference, -+ /* IDXGIFactory7 methods */ -+ dxgi_factory_RegisterAdaptersChangedEvent, -+ dxgi_factory_UnregisterAdaptersChangedEvent, -+}; -+ -+HRESULT get_re8_dxgi_factory(REFIID riid, void **factory) -+{ -+ HRESULT hr; -+ -+ EnterCriticalSection(&re8_factory_lock); -+ -+ if(re8_factory.refcount == 0){ -+ if (FAILED(hr = dxgi_factory_init(&re8_factory, TRUE))) -+ { -+ WARN("Failed to initialize factory, hr %#x.\n", hr); -+ LeaveCriticalSection(&re8_factory_lock); -+ return hr; -+ } -+ -+ re8_factory.IWineDXGIFactory_iface.lpVtbl = &re8_factory_vtbl; -+ -+ TRACE("Created factory %p.\n", &re8_factory); -+ } -+ -+ LeaveCriticalSection(&re8_factory_lock); -+ -+ hr = IWineDXGIFactory_QueryInterface(&re8_factory.IWineDXGIFactory_iface, riid, factory); -+ -+ return hr; -+} -From ce0c255a1fd40bfa9a1de6f6765b83a4dcf9d0dd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 May 2021 14:57:46 +0200 -Subject: [PATCH] user32: Implement rudimentary EnableMouseInPointer support. - -CW-Bug-Id: 18943 ---- - dlls/user32/input.c | 9 +++++---- - dlls/user32/message.c | 32 ++++++++++++++++++++++++++++++++ - dlls/user32/user_private.h | 1 + - include/winuser.h | 26 ++++++++++++++++++++++++++ - 4 files changed, 64 insertions(+), 4 deletions(-) - -diff --git a/dlls/user32/input.c b/dlls/user32/input.c -index 455f857d9d0..dbfc9f36819 100644 ---- a/dlls/user32/input.c -+++ b/dlls/user32/input.c -@@ -1324,15 +1324,16 @@ int WINAPI GetMouseMovePointsEx( UINT size, LPMOUSEMOVEPOINT ptin, LPMOUSEMOVEPO - return copied; - } - -+BOOL enable_mouse_in_pointer = FALSE; -+ - /*********************************************************************** - * EnableMouseInPointer (USER32.@) - */ - BOOL WINAPI EnableMouseInPointer(BOOL enable) - { -- FIXME("(%#x) stub\n", enable); -- -- SetLastError(ERROR_CALL_NOT_IMPLEMENTED); -- return FALSE; -+ FIXME("(%#x) semi-stub\n", enable); -+ enable_mouse_in_pointer = TRUE; -+ return TRUE; - } - - static DWORD CALLBACK devnotify_window_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) -diff --git a/dlls/user32/message.c b/dlls/user32/message.c -index a54ecccc7cd..57baea203e5 100644 ---- a/dlls/user32/message.c -+++ b/dlls/user32/message.c -@@ -2590,6 +2590,38 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H - in the WM_SETCURSOR message even if it's non-client mouse message */ - SendMessageW( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message )); - -+ if (enable_mouse_in_pointer) switch (msg->message) -+ { -+ case WM_MOUSEMOVE: -+ case WM_LBUTTONDOWN: -+ case WM_LBUTTONUP: -+ case WM_RBUTTONDOWN: -+ case WM_RBUTTONUP: -+ case WM_MBUTTONDOWN: -+ case WM_MBUTTONUP: -+ case WM_XBUTTONDOWN: -+ case WM_XBUTTONUP: -+ { -+ WORD flags = POINTER_MESSAGE_FLAG_INRANGE|POINTER_MESSAGE_FLAG_INCONTACT|POINTER_MESSAGE_FLAG_PRIMARY; -+ if (msg->message == WM_LBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; -+ if (msg->message == WM_RBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; -+ if (msg->message == WM_MBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_LBUTTON) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_RBUTTON) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_MBUTTON) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON1) flags |= POINTER_MESSAGE_FLAG_FOURTHBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON2) flags |= POINTER_MESSAGE_FLAG_FIFTHBUTTON; -+ SendMessageW( msg->hwnd, WM_POINTERUPDATE, MAKELONG( 1, flags ), MAKELONG( msg->pt.x, msg->pt.y ) ); -+ break; -+ } -+ case WM_MOUSEWHEEL: -+ SendMessageW( msg->hwnd, WM_POINTERWHEEL, MAKELONG( 1, HIWORD( msg->wParam ) ), MAKELONG( msg->pt.x, msg->pt.y ) ); -+ break; -+ case WM_MOUSEHWHEEL: -+ SendMessageW( msg->hwnd, WM_POINTERHWHEEL, MAKELONG( 1, HIWORD( msg->wParam ) ), MAKELONG( msg->pt.x, msg->pt.y ) ); -+ break; -+ } -+ - msg->message = message; - return !eatMsg; - } -diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h -index 5a36f9bb7aa..0910e453f13 100644 ---- a/dlls/user32/user_private.h -+++ b/dlls/user32/user_private.h -@@ -236,6 +236,7 @@ static inline BOOL is_broadcast( HWND hwnd ) - } - - extern HMODULE user32_module DECLSPEC_HIDDEN; -+extern BOOL enable_mouse_in_pointer DECLSPEC_HIDDEN; - - struct dce; - struct tagWND; -diff --git a/include/winuser.h b/include/winuser.h -index fe82613e590..402fbee9dc4 100644 ---- a/include/winuser.h -+++ b/include/winuser.h -@@ -3474,6 +3474,32 @@ typedef struct tagMENUGETOBJECTINFO - void *pvObj; - } MENUGETOBJECTINFO, *PMENUGETOBJECTINFO; - -+#define POINTER_MESSAGE_FLAG_NEW 0x00000001 -+#define POINTER_MESSAGE_FLAG_INRANGE 0x00000002 -+#define POINTER_MESSAGE_FLAG_INCONTACT 0x00000004 -+#define POINTER_MESSAGE_FLAG_FIRSTBUTTON 0x00000010 -+#define POINTER_MESSAGE_FLAG_SECONDBUTTON 0x00000020 -+#define POINTER_MESSAGE_FLAG_THIRDBUTTON 0x00000040 -+#define POINTER_MESSAGE_FLAG_FOURTHBUTTON 0x00000080 -+#define POINTER_MESSAGE_FLAG_FIFTHBUTTON 0x00000100 -+#define POINTER_MESSAGE_FLAG_PRIMARY 0x00002000 -+#define POINTER_MESSAGE_FLAG_CONFIDENCE 0x00004000 -+#define POINTER_MESSAGE_FLAG_CANCELED 0x00008000 -+ -+#define GET_POINTERID_WPARAM(wparam) (LOWORD(wparam)) -+#define IS_POINTER_FLAG_SET_WPARAM(wparam, flags) ((HIWORD(wparam) & (flags)) == (flags)) -+#define IS_POINTER_NEW_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_NEW) -+#define IS_POINTER_INRANGE_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_INRANGE) -+#define IS_POINTER_INCONTACT_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_INCONTACT) -+#define IS_POINTER_FIRSTBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_FIRSTBUTTON) -+#define IS_POINTER_SECONDBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_SECONDBUTTON) -+#define IS_POINTER_THIRDBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_THIRDBUTTON) -+#define IS_POINTER_FOURTHBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_FOURTHBUTTON) -+#define IS_POINTER_FIFTHBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_FIFTHBUTTON) -+#define IS_POINTER_PRIMARY_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_PRIMARY) -+#define HAS_POINTER_CONFIDENCE_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_CONFIDENCE) -+#define IS_POINTER_CANCELED_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_CANCELED) -+ - #if defined(_WINGDI_) && !defined(NOGDI) - WINUSERAPI LONG WINAPI ChangeDisplaySettingsA(LPDEVMODEA,DWORD); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsW(LPDEVMODEW,DWORD); - -From 43c3113aa696898ec5758118b92f8c2a5fb61714 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 30 Jul 2021 21:01:13 +0300 -Subject: [PATCH] kernelbase: HACK: Force CEF software rendering for - UplayWebCore. - -(To be revisited once builtin d3dcompiler is added). ---- - dlls/kernelbase/process.c | 27 ++++++++++++++++++++++++++- - 1 file changed, 26 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c -index 33197563cd8..9bcb377a62e 100644 ---- a/dlls/kernelbase/process.c -+++ b/dlls/kernelbase/process.c -@@ -33,6 +33,7 @@ - - #include "kernelbase.h" - #include "wine/debug.h" -+#include "wine/heap.h" - #include "wine/condrv.h" - - WINE_DEFAULT_DEBUG_CHANNEL(process); -@@ -517,7 +518,31 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - } - else - { -- if (!(tidy_cmdline = get_file_name( cmd_line, name, ARRAY_SIZE(name) ))) return FALSE; -+ static const WCHAR *opt = L" --use-gl=swiftshader"; -+ WCHAR *cmdline_new = NULL; -+ -+ if (cmd_line && wcsstr( cmd_line, L"UplayWebCore.exe" )) -+ { -+ FIXME( "HACK: appending %s to command line %s.\n", debugstr_w(opt), debugstr_w(cmd_line) ); -+ -+ cmdline_new = heap_alloc( sizeof(WCHAR) * (lstrlenW(cmd_line) + lstrlenW(opt) + 1) ); -+ lstrcpyW(cmdline_new, cmd_line); -+ lstrcatW(cmdline_new, opt); -+ } -+ -+ tidy_cmdline = get_file_name( cmdline_new ? cmdline_new : cmd_line, name, ARRAY_SIZE(name) ); -+ -+ if (!tidy_cmdline) -+ { -+ heap_free( cmdline_new ); -+ return FALSE; -+ } -+ -+ if (cmdline_new) -+ { -+ if (cmdline_new == tidy_cmdline) cmd_line = NULL; -+ else heap_free( cmdline_new ); -+ } - app_name = name; - } - -From 0597fa1ef89f5c4840c9b5762d74d7ce2e0abb56 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Wed, 23 Jun 2021 13:37:04 +0300 -Subject: [PATCH] winex11.drv: Add a GPU for each Vulkan device that was not - tied to an XRandR provider. - -This assures that each Vulkan device has a LUID assigned (see X11DRV_InitGpu -and VkPhysicalDeviceIDProperties). - -LUIDs are important for DirectX <-> Vulkan interop. VKD3D-Proton and -DXVK's DXGI use that to identify which underlaying Vulkan device to use -for the selected adapter. - -This change fixes GPU selection in Hitman 2 in DX12 mode. Without it -VKD3D-Proton resorts to a heuristic (vid/pid matching, and if that fails -use the first device in enumeration order) which can select the wrong -one on some multi-GPU Nvidia setups due to nvapihack. - -This also fixes Forza Horizon 4 on Wayland as XWayland doesn't expose -providers which results in missing LUIDs even for the GPU driving the -outputs. - -CW-Bug-Id: #18737 -CW-Bug-Id: #18925 ---- - dlls/winex11.drv/xrandr.c | 149 +++++++++++++++++++++++++++++++++++--- - 1 file changed, 139 insertions(+), 10 deletions(-) - -diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c -index 7edaaf07dc2..a17b8f47fbf 100644 ---- a/dlls/winex11.drv/xrandr.c -+++ b/dlls/winex11.drv/xrandr.c -@@ -602,6 +602,113 @@ static BOOL is_crtc_primary( RECT primary, const XRRCrtcInfo *crtc ) - crtc->y + crtc->height == primary.bottom; - } - -+static void add_remaining_gpus_via_vulkan( struct gdi_gpu **gpus, int *count ) -+{ -+ static const char *extensions[] = -+ { -+ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, -+ }; -+ const struct vulkan_funcs *vulkan_funcs = get_vulkan_driver( WINE_VULKAN_DRIVER_VERSION ); -+ PFN_vkGetPhysicalDeviceProperties2KHR pvkGetPhysicalDeviceProperties2KHR; -+ PFN_vkEnumeratePhysicalDevices pvkEnumeratePhysicalDevices; -+ uint32_t device_count; -+ VkPhysicalDevice *vk_physical_devices = NULL; -+ VkPhysicalDeviceProperties2 properties2; -+ VkInstanceCreateInfo create_info; -+ VkPhysicalDeviceIDProperties id; -+ VkInstance vk_instance = NULL; -+ INT gpu_idx, device_idx; -+ INT original_gpu_count = *count; -+ struct gdi_gpu *new_gpu; -+ BOOL new; -+ VkResult vr; -+ -+ memset( &create_info, 0, sizeof(create_info) ); -+ create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; -+ create_info.enabledExtensionCount = ARRAY_SIZE(extensions); -+ create_info.ppEnabledExtensionNames = extensions; -+ vr = vulkan_funcs->p_vkCreateInstance( &create_info, NULL, &vk_instance ); -+ -+ if (vr != VK_SUCCESS) -+ { -+ WARN("Failed to create a Vulkan instance, vr %d.\n", vr); -+ goto done; -+ } -+ -+#define LOAD_VK_FUNC(f) \ -+ if (!(p##f = (void *)vulkan_funcs->p_vkGetInstanceProcAddr( vk_instance, #f ))) \ -+ { \ -+ WARN("Failed to load " #f ".\n"); \ -+ goto done; \ -+ } -+ -+ LOAD_VK_FUNC(vkEnumeratePhysicalDevices) -+ LOAD_VK_FUNC(vkGetPhysicalDeviceProperties2KHR) -+#undef LOAD_VK_FUNC -+ -+ vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, NULL ); -+ if (vr != VK_SUCCESS || !device_count) -+ { -+ WARN("No Vulkan device found, vr %d, device_count %d.\n", vr, device_count); -+ goto done; -+ } -+ -+ if (!(vk_physical_devices = heap_calloc( device_count, sizeof(*vk_physical_devices) ))) -+ goto done; -+ -+ vr = pvkEnumeratePhysicalDevices( vk_instance, &device_count, vk_physical_devices ); -+ if (vr != VK_SUCCESS) -+ { -+ WARN("vkEnumeratePhysicalDevices failed, vr %d.\n", vr); -+ goto done; -+ } -+ -+ for (device_idx = 0; device_idx < device_count; ++device_idx) -+ { -+ memset( &id, 0, sizeof(id) ); -+ id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; -+ properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; -+ properties2.pNext = &id; -+ -+ pvkGetPhysicalDeviceProperties2KHR( vk_physical_devices[device_idx], &properties2 ); -+ -+ /* Ignore Khronos vendor IDs */ -+ if (properties2.properties.vendorID >= 0x10000) -+ continue; -+ -+ new = TRUE; -+ for (gpu_idx = 0; gpu_idx < original_gpu_count; ++gpu_idx) -+ { -+ if (!memcmp( &(*gpus)[gpu_idx].vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) )) -+ { -+ new = FALSE; -+ break; -+ } -+ } -+ -+ if (!new) -+ continue; -+ -+ *gpus = heap_realloc( *gpus, (*count + 1) * sizeof(**gpus) ); -+ if (!gpus) goto done; -+ new_gpu = &(*gpus)[(*count)++]; -+ memset( new_gpu, 0, sizeof(*new_gpu) ); -+ new_gpu->id = -1; -+ -+ memcpy( &new_gpu->vulkan_uuid, id.deviceUUID, sizeof(id.deviceUUID) ); -+ new_gpu->vendor_id = properties2.properties.vendorID; -+ new_gpu->device_id = properties2.properties.deviceID; -+ MultiByteToWideChar( CP_UTF8, 0, properties2.properties.deviceName, -1, new_gpu->name, ARRAY_SIZE(new_gpu->name) ); -+ -+ TRACE("Added a new GPU via Vulkan: %04x:%04x %s\n", new_gpu->vendor_id, new_gpu->device_id, debugstr_w(new_gpu->name)); -+ } -+ -+done: -+ heap_free( vk_physical_devices ); -+ if (vk_instance) -+ vulkan_funcs->p_vkDestroyInstance( vk_instance, NULL ); -+} -+ - VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDisplayKHR) - - static BOOL get_gpu_properties_from_vulkan( struct gdi_gpu *gpu, const XRRProviderInfo *provider_info ) -@@ -718,6 +825,7 @@ static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL g - XRRProviderInfo *provider_info = NULL; - XRRCrtcInfo *crtc_info = NULL; - INT primary_provider = -1; -+ INT gpu_count = 0; - RECT primary_rect; - BOOL ret = FALSE; - INT i, j; -@@ -730,22 +838,17 @@ static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL g - if (!provider_resources) - goto done; - -- gpus = heap_calloc( provider_resources->nproviders ? provider_resources->nproviders : 1, sizeof(*gpus) ); -- if (!gpus) -- goto done; -- - /* Some XRandR implementations don't support providers. - * In this case, report a fake one to try searching adapters in screen resources */ - if (!provider_resources->nproviders) - { - WARN("XRandR implementation doesn't report any providers, faking one.\n"); -- lstrcpyW( gpus[0].name, wine_adapterW ); -- *new_gpus = gpus; -- *count = 1; -- ret = TRUE; -- goto done; -+ goto fallback; - } - -+ gpus = heap_calloc( provider_resources->nproviders, sizeof(*gpus) ); -+ if (!gpus) goto done; -+ - primary_rect = get_primary_rect( screen_resources ); - for (i = 0; i < provider_resources->nproviders; ++i) - { -@@ -778,6 +881,7 @@ static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL g - /* FIXME: Add an alternate method of getting PCI IDs, for systems that don't support Vulkan */ - } - pXRRFreeProviderInfo( provider_info ); -+ gpu_count++; - } - - /* Make primary GPU the first */ -@@ -788,8 +892,29 @@ static BOOL xrandr14_get_gpus2( struct gdi_gpu **new_gpus, int *count, BOOL g - gpus[primary_provider] = tmp; - } - -+fallback: -+ /* Add the Vulkan only GPUs only if we need all the detailed properties */ -+ if (get_properties) -+ add_remaining_gpus_via_vulkan( &gpus, &gpu_count ); -+ -+ if (gpu_count == 0) -+ { -+ /* we need at least one for get_adapters() / get_id() */ -+ gpus = heap_calloc( 1, sizeof(*gpus) ); -+ if (!gpus) goto done; -+ lstrcpyW( gpus[0].name, wine_adapterW ); -+ gpu_count = 1; -+ } -+ else if (gpus[0].id == -1) -+ { -+ /* the only GPUs we have are from Vulkan, mark the first one -+ * as main so that we can use screen resources for adapters, -+ * see xrandr14_get_adapters() */ -+ gpus[0].id = 0; -+ } -+ - *new_gpus = gpus; -- *count = provider_resources->nproviders; -+ *count = gpu_count; - ret = TRUE; - done: - if (provider_resources) -@@ -834,6 +959,10 @@ static BOOL xrandr14_get_adapters( ULONG_PTR gpu_id, struct x11drv_adapter **new - if (!screen_resources) - goto done; - -+ /* Vulkan-only, adapter-less GPU */ -+ if (gpu_id == -1) -+ goto done; -+ - if (gpu_id) - { - provider_info = pXRRGetProviderInfo( gdi_display, screen_resources, gpu_id ); - -From 498ecc1a9e25a63aa0b082b28896647bbc063cb3 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 25 Jun 2021 23:17:43 +0300 -Subject: [PATCH] esync, fsync: Use usleep(0) instead of NtYieldExecution() in - esync_pulse_event(). - ---- - dlls/ntdll/unix/esync.c | 2 +- - dlls/ntdll/unix/fsync.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c -index 810477d02a0..80f2ee88fc2 100644 ---- a/dlls/ntdll/unix/esync.c -+++ b/dlls/ntdll/unix/esync.c -@@ -626,7 +626,7 @@ NTSTATUS esync_pulse_event( HANDLE handle ) - - /* Try to give other threads a chance to wake up. Hopefully erring on this - * side is the better thing to do... */ -- NtYieldExecution(); -+ usleep(0); - - read( obj->fd, &value, sizeof(value) ); - -From 38a3e2ae80c6a80be73be9288d2d12bfcb6ccb8d Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 22 Jul 2021 16:11:18 -0500 -Subject: [PATCH] HACK: shell32: Update knownfolder paths in the registry - -Guilty Gear Strive requires that the path be in the new format. Since we -haven't yet found a game that has a problem with the new format, let's -just use that in all cases. - -For Steam cloud sync failures. - -CW-Bug-Id: #18905 ---- - dlls/shell32/shellpath.c | 21 ++++++++++++++++++--- - 1 file changed, 18 insertions(+), 3 deletions(-) - -diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c -index a2b71bfb701..7227e97d6b9 100644 ---- a/dlls/shell32/shellpath.c -+++ b/dlls/shell32/shellpath.c -@@ -4630,6 +4630,8 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, - LPCWSTR szUserShellFolderPath, LPCWSTR szShellFolderPath, const UINT folders[], - UINT foldersLen) - { -+ static const WCHAR WineVistaPathsW[] = {'_','_','W','i','n','e','V','i','s','t','a','P','a','t','h','s',0}; -+ - const WCHAR *szValueName; - WCHAR buffer[40]; - UINT i; -@@ -4638,6 +4640,7 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, - HKEY hUserKey = NULL, hKey = NULL; - DWORD dwType, dwPathLen; - LONG ret; -+ DWORD already_vista_paths = 0; - - TRACE("%p,%p,%s,%p,%u\n", hRootKey, hToken, - debugstr_w(szUserShellFolderPath), folders, foldersLen); -@@ -4651,6 +4654,12 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, - if (ret) - hr = HRESULT_FROM_WIN32(ret); - } -+ -+ /* check if the registry has already been updated to the vista+ style paths */ -+ dwPathLen = sizeof(already_vista_paths); -+ RegQueryValueExW(hUserKey, WineVistaPathsW, NULL, &dwType, -+ (LPBYTE)&already_vista_paths, &dwPathLen); -+ - for (i = 0; SUCCEEDED(hr) && i < foldersLen; i++) - { - dwPathLen = MAX_PATH * sizeof(WCHAR); -@@ -4663,9 +4672,10 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, - szValueName = &buffer[0]; - } - -- if (RegQueryValueExW(hUserKey, szValueName, NULL, -- &dwType, (LPBYTE)path, &dwPathLen) || (dwType != REG_SZ && -- dwType != REG_EXPAND_SZ)) -+ if (!already_vista_paths || -+ RegQueryValueExW(hUserKey, szValueName, NULL, &dwType, -+ (LPBYTE)path, &dwPathLen) || -+ (dwType != REG_SZ && dwType != REG_EXPAND_SZ)) - { - *path = '\0'; - if (CSIDL_Data[folders[i]].type == CSIDL_Type_User) -@@ -4706,6 +4716,11 @@ static HRESULT _SHRegisterFolders(HKEY hRootKey, HANDLE hToken, - hToken, SHGFP_TYPE_DEFAULT, path); - } - } -+ -+ already_vista_paths = 1; -+ RegSetValueExW(hUserKey, WineVistaPathsW, 0, REG_DWORD, -+ (LPBYTE)&already_vista_paths, sizeof(already_vista_paths)); -+ - if (hUserKey) - RegCloseKey(hUserKey); - if (hKey) -From a9ec37d83082b1623aea4bc5933f77f4c8a356cf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 14 Sep 2021 14:16:47 +0200 -Subject: [PATCH] msvcrt: Check for ERMS support and use rep stosb for large - memset calls. - ---- - dlls/msvcrt/math.c | 13 +++++++++ - dlls/msvcrt/msvcrt.h | 1 + - dlls/msvcrt/string.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 78 insertions(+) - -diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c -index d6b0d9422e7..ed763f02589 100644 ---- a/dlls/msvcrt/math.c -+++ b/dlls/msvcrt/math.c -@@ -42,6 +42,7 @@ - #include - #include - #include -+#include - - #include "msvcrt.h" - #include "winternl.h" -@@ -64,6 +65,7 @@ typedef int (CDECL *MSVCRT_matherr_func)(struct _exception *); - - static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL; - -+BOOL erms_supported; - BOOL sse2_supported; - static BOOL sse2_enabled; - -@@ -71,6 +73,17 @@ static const struct unix_funcs *unix_funcs; - - void msvcrt_init_math( void *module ) - { -+#if defined(__i386__) || defined(__x86_64__) -+ int regs[4]; -+ -+ __cpuid(regs, 0); -+ if (regs[0] >= 7) -+ { -+ __cpuidex(regs, 7, 0); -+ erms_supported = ((regs[1] >> 9) & 1); -+ } -+#endif -+ - sse2_supported = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE ); - #if _MSVCR_VER <=71 - sse2_enabled = FALSE; -diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h -index c84e0a0a638..69c52616e3f 100644 ---- a/dlls/msvcrt/msvcrt.h -+++ b/dlls/msvcrt/msvcrt.h -@@ -32,6 +32,7 @@ - #include "winbase.h" - #undef strncpy - -+extern BOOL erms_supported DECLSPEC_HIDDEN; - extern BOOL sse2_supported DECLSPEC_HIDDEN; - - #define DBL80_MAX_10_EXP 4932 -diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c -index 70cca8d18ee..3daa0d483d0 100644 ---- a/dlls/msvcrt/string.c -+++ b/dlls/msvcrt/string.c -@@ -2722,6 +2722,13 @@ __ASM_GLOBAL_FUNC( sse2_memmove, - MEMMOVE_CLEANUP - "ret" ) - -+#undef MEMMOVE_INIT -+#undef MEMMOVE_CLEANUP -+#undef DEST_REG -+#undef SRC_REG -+#undef LEN_REG -+#undef TMP_REG -+ - #endif - - /********************************************************************* -@@ -2845,6 +2852,56 @@ void * __cdecl memcpy(void *dst, const void *src, size_t n) - return memmove(dst, src, n); - } - -+#if defined(__i386__) || defined(__x86_64__) -+ -+#ifdef __i386__ -+#define DEST_REG "%edi" -+#define LEN_REG "%ecx" -+#define VAL_REG "%eax" -+ -+#define MEMSET_INIT \ -+ "movl " DEST_REG ", %edx\n\t" \ -+ "movl 4(%esp), " DEST_REG "\n\t" \ -+ "movl 8(%esp), " VAL_REG "\n\t" \ -+ "movl 12(%esp), " LEN_REG "\n\t" -+ -+#define MEMSET_RET \ -+ "movl %edx, " DEST_REG "\n\t" \ -+ "ret" -+ -+#else -+ -+#define DEST_REG "%rdi" -+#define LEN_REG "%rcx" -+#define VAL_REG "%eax" -+ -+#define MEMSET_INIT \ -+ "movq " DEST_REG ", %r9\n\t" \ -+ "movq %rcx, " DEST_REG "\n\t" \ -+ "movl %edx, " VAL_REG "\n\t" \ -+ "movq %r8, " LEN_REG "\n\t" -+ -+#define MEMSET_RET \ -+ "movq %r9, " DEST_REG "\n\t" \ -+ "ret" -+ -+#endif -+ -+void __cdecl erms_memset_aligned_32(unsigned char *d, unsigned int c, size_t n); -+__ASM_GLOBAL_FUNC( erms_memset_aligned_32, -+ MEMSET_INIT -+ "rep\n\t" -+ "stosb\n\t" -+ MEMSET_RET ) -+ -+#undef MEMSET_INIT -+#undef MEMSET_RET -+#undef DEST_REG -+#undef LEN_REG -+#undef VAL_REG -+ -+#endif -+ - static inline void memset_aligned_32(unsigned char *d, uint64_t v, size_t n) - { - while (n >= 32) -@@ -2880,6 +2937,13 @@ void *__cdecl memset(void *dst, int c, size_t n) - if (n <= 64) return dst; - - n = (n - a) & ~0x1f; -+#if defined(__i386__) || defined(__x86_64__) -+ if (n >= 2048 && erms_supported) -+ { -+ erms_memset_aligned_32(d + a, v, n); -+ return dst; -+ } -+#endif - memset_aligned_32(d + a, v, n); - return dst; - } -From 454d37da51ed35ce16d73ba162c4fad3de7f93b1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 14 Sep 2021 14:16:48 +0200 -Subject: [PATCH] msvcrt: Add an SSE2 memset_aligned_32 implementation. - ---- - dlls/msvcrt/string.c | 33 +++++++++++++++++++++++++++++++++ - 1 file changed, 33 insertions(+) - -diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c -index 3daa0d483d0..74409a6fb76 100644 ---- a/dlls/msvcrt/string.c -+++ b/dlls/msvcrt/string.c -@@ -2894,6 +2894,27 @@ __ASM_GLOBAL_FUNC( erms_memset_aligned_32, - "stosb\n\t" - MEMSET_RET ) - -+void __cdecl sse2_memset_aligned_32(unsigned char *d, unsigned int c, size_t n); -+__ASM_GLOBAL_FUNC( sse2_memset_aligned_32, -+ MEMSET_INIT -+ "movd " VAL_REG ", %xmm0\n\t" -+ "pshufd $0, %xmm0, %xmm0\n\t" -+ "test $0x20, " LEN_REG "\n\t" -+ "je 1f\n\t" -+ "sub $0x20, " LEN_REG "\n\t" -+ "movdqa %xmm0, 0x00(" DEST_REG ", " LEN_REG ")\n\t" -+ "movdqa %xmm0, 0x10(" DEST_REG ", " LEN_REG ")\n\t" -+ "je 2f\n\t" -+ "1:\n\t" -+ "sub $0x40, " LEN_REG "\n\t" -+ "movdqa %xmm0, 0x00(" DEST_REG ", " LEN_REG ")\n\t" -+ "movdqa %xmm0, 0x10(" DEST_REG ", " LEN_REG ")\n\t" -+ "movdqa %xmm0, 0x20(" DEST_REG ", " LEN_REG ")\n\t" -+ "movdqa %xmm0, 0x30(" DEST_REG ", " LEN_REG ")\n\t" -+ "ja 1b\n\t" -+ "2:\n\t" -+ MEMSET_RET ) -+ - #undef MEMSET_INIT - #undef MEMSET_RET - #undef DEST_REG -@@ -2943,9 +2964,21 @@ void *__cdecl memset(void *dst, int c, size_t n) - erms_memset_aligned_32(d + a, v, n); - return dst; - } -+#ifdef __x86_64__ -+ sse2_memset_aligned_32(d + a, v, n); -+ return dst; -+#else -+ if (sse2_supported) -+ { -+ sse2_memset_aligned_32(d + a, v, n); -+ return dst; -+ } -+#endif - #endif -+#ifndef __x86_64__ - memset_aligned_32(d + a, v, n); - return dst; -+#endif - } - if (n >= 8) - { -From 1ace788f817b0175e63d02732c0c11269d19ae0a Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 16 Sep 2021 18:01:42 +0300 -Subject: [PATCH] kernelbase: Return an error from - InitializeProcessForWsWatch() stub. - -CW-Bug-ID: #19445 - -For DeathLoop. ---- - dlls/kernelbase/debug.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c -index cbc53e22ac1..60b03c57137 100644 ---- a/dlls/kernelbase/debug.c -+++ b/dlls/kernelbase/debug.c -@@ -1525,7 +1525,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetWsChangesEx( HANDLE process, PSAPI_WS_WATCH_INF - BOOL WINAPI /* DECLSPEC_HOTPATCH */ InitializeProcessForWsWatch( HANDLE process ) - { - FIXME( "(process=%p): stub\n", process ); -- return TRUE; -+ SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); -+ return FALSE; - } - - -From c5012eb1b2613f053a331d9156046fe8b7245687 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 17 Sep 2021 21:49:11 +0300 -Subject: [PATCH] advapi32: HACK: Don't free provider library in - CryptReleaseContext() for DeathLoop. - -CW-Bug-Id: 19427 - -Avoids a lockup in DeathLoop. To be dropped once we have a -GetModuleHandle() not blocking on the loader lock. ---- - dlls/advapi32/crypt.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/dlls/advapi32/crypt.c b/dlls/advapi32/crypt.c -index 20c55558fa5..db6e16ae435 100644 ---- a/dlls/advapi32/crypt.c -+++ b/dlls/advapi32/crypt.c -@@ -645,9 +645,19 @@ BOOL WINAPI CryptReleaseContext (HCRYPTPROV hProv, DWORD dwFlags) - - if (InterlockedDecrement(&pProv->refcount) == 0) - { -+ static unsigned int once; -+ char sgi[64]; -+ - ret = pProv->pFuncs->pCPReleaseContext(pProv->hPrivate, dwFlags); - pProv->dwMagic = 0; -- FreeLibrary(pProv->hModule); -+ if(GetEnvironmentVariableA("SteamGameId", sgi, sizeof(sgi)) && !strcmp(sgi, "1252330")) -+ { -+ if (!once++) FIXME("HACK: not freeing provider library.\n"); -+ } -+ else -+ { -+ FreeLibrary(pProv->hModule); -+ } - #if 0 - CRYPT_Free(pProv->pVTable->pContextInfo); - #endif -From 04bb9112d2d540452068d1e22d4faf51fe11f351 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Mon, 8 Nov 2021 19:38:33 +0200 -Subject: [PATCH] msvcrt: Increase module's reference count before returning - from _beginthread[ex](). - -Increasing DLL's reference count from the trampoline function makes it -prone to race conditions. The thread can start executing after we have -already returned from _beginthread[ex]() and the DLL might have been -freed. - -Fixes rare crash on launch with Baldur's Gate 3. - -Signed-off-by: Arkadiusz Hiler -Signed-off-by: Piotr Caban -Signed-off-by: Alexandre Julliard ---- - dlls/msvcrt/thread.c | 50 +++++++++++++++++++++++++++----------------- - 1 file changed, 31 insertions(+), 19 deletions(-) - -diff --git a/dlls/msvcrt/thread.c b/dlls/msvcrt/thread.c -index 01500d93d91..173763d0eb1 100644 ---- a/dlls/msvcrt/thread.c -+++ b/dlls/msvcrt/thread.c -@@ -32,6 +32,9 @@ typedef struct { - _beginthreadex_start_routine_t start_address_ex; - }; - void *arglist; -+#if _MSVCR_VER >= 140 -+ HMODULE module; -+#endif - } _beginthread_trampoline_t; - - /********************************************************************* -@@ -113,16 +116,10 @@ static DWORD CALLBACK _beginthread_trampoline(LPVOID arg) - thread_data_t *data = msvcrt_get_thread_data(); - - memcpy(&local_trampoline,arg,sizeof(local_trampoline)); -- data->handle = local_trampoline.thread; - free(arg); -- -+ data->handle = local_trampoline.thread; - #if _MSVCR_VER >= 140 -- if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, -- (void*)local_trampoline.start_address, &data->module)) -- { -- data->module = NULL; -- WARN("failed to get module for the start_address: %d\n", GetLastError()); -- } -+ data->module = local_trampoline.module; - #endif - - local_trampoline.start_address(local_trampoline.arglist); -@@ -162,7 +159,19 @@ uintptr_t CDECL _beginthread( - trampoline->start_address = start_address; - trampoline->arglist = arglist; - -+#if _MSVCR_VER >= 140 -+ if(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, -+ (void*)start_address, &trampoline->module)) -+ { -+ trampoline->module = NULL; -+ WARN("failed to get module for the start_address: %d\n", GetLastError()); -+ } -+#endif -+ - if(ResumeThread(thread) == -1) { -+#if _MSVCR_VER >= 140 -+ FreeLibrary(trampoline->module); -+#endif - free(trampoline); - *_errno() = EAGAIN; - return -1; -@@ -181,19 +190,10 @@ static DWORD CALLBACK _beginthreadex_trampoline(LPVOID arg) - thread_data_t *data = msvcrt_get_thread_data(); - - memcpy(&local_trampoline, arg, sizeof(local_trampoline)); -- data->handle = local_trampoline.thread; - free(arg); -- -+ data->handle = local_trampoline.thread; - #if _MSVCR_VER >= 140 -- { -- thread_data_t *data = msvcrt_get_thread_data(); -- if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, -- (void*)local_trampoline.start_address_ex, &data->module)) -- { -- data->module = NULL; -- WARN("failed to get module for the start_address: %d\n", GetLastError()); -- } -- } -+ data->module = local_trampoline.module; - #endif - - retval = local_trampoline.start_address_ex(local_trampoline.arglist); -@@ -225,9 +225,21 @@ uintptr_t CDECL _beginthreadex( - trampoline->start_address_ex = start_address; - trampoline->arglist = arglist; - -+#if _MSVCR_VER >= 140 -+ if(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, -+ (void*)start_address, &trampoline->module)) -+ { -+ trampoline->module = NULL; -+ WARN("failed to get module for the start_address: %d\n", GetLastError()); -+ } -+#endif -+ - thread = CreateThread(security, stack_size, _beginthreadex_trampoline, - trampoline, initflag, thrdaddr); - if(!thread) { -+#if _MSVCR_VER >= 140 -+ FreeLibrary(trampoline->module); -+#endif - free(trampoline); - msvcrt_set_errno(GetLastError()); - return 0; -From 6d574d1275635d1fda1177707a8f3146249b52ce Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 13 Oct 2021 15:19:37 +0200 -Subject: [PATCH] msvcrt: Write memory forward in memset. - -Instead of going backward, which may break the Linux kernel page fault -optimizations. ---- - dlls/msvcrt/string.c | 23 +++++++++++++---------- - 1 file changed, 13 insertions(+), 10 deletions(-) - -diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c -index 74409a6fb76..63a11c27e03 100644 ---- a/dlls/msvcrt/string.c -+++ b/dlls/msvcrt/string.c -@@ -2901,16 +2901,18 @@ __ASM_GLOBAL_FUNC( sse2_memset_aligned_32, - "pshufd $0, %xmm0, %xmm0\n\t" - "test $0x20, " LEN_REG "\n\t" - "je 1f\n\t" -+ "add $0x20, " DEST_REG "\n\t" - "sub $0x20, " LEN_REG "\n\t" -- "movdqa %xmm0, 0x00(" DEST_REG ", " LEN_REG ")\n\t" -- "movdqa %xmm0, 0x10(" DEST_REG ", " LEN_REG ")\n\t" -+ "movdqa %xmm0, -0x20(" DEST_REG ")\n\t" -+ "movdqa %xmm0, -0x10(" DEST_REG ")\n\t" - "je 2f\n\t" - "1:\n\t" -+ "add $0x40, " DEST_REG "\n\t" - "sub $0x40, " LEN_REG "\n\t" -- "movdqa %xmm0, 0x00(" DEST_REG ", " LEN_REG ")\n\t" -- "movdqa %xmm0, 0x10(" DEST_REG ", " LEN_REG ")\n\t" -- "movdqa %xmm0, 0x20(" DEST_REG ", " LEN_REG ")\n\t" -- "movdqa %xmm0, 0x30(" DEST_REG ", " LEN_REG ")\n\t" -+ "movdqa %xmm0, -0x40(" DEST_REG ")\n\t" -+ "movdqa %xmm0, -0x30(" DEST_REG ")\n\t" -+ "movdqa %xmm0, -0x20(" DEST_REG ")\n\t" -+ "movdqa %xmm0, -0x10(" DEST_REG ")\n\t" - "ja 1b\n\t" - "2:\n\t" - MEMSET_RET ) diff --git a/patches/proton/11-proton-pa-staging.patch b/patches/proton/11-proton-pa-staging.patch deleted file mode 100644 index 94eaa74ab..000000000 --- a/patches/proton/11-proton-pa-staging.patch +++ /dev/null @@ -1,695 +0,0 @@ -From 75115b915982adcfe001475ff959e889119a65e4 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 17 Jul 2020 08:44:43 -0500 -Subject: [PATCH] include/xact3.h: Add missing legacy classes - ---- - include/xact3.h | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 50 insertions(+) - -diff --git a/include/xact3.h b/include/xact3.h -index a1df1a51330..684e6ee3019 100644 ---- a/include/xact3.h -+++ b/include/xact3.h -@@ -522,6 +522,56 @@ DECLARE_INTERFACE(IXACT3Cue) - #define IXACT3Cue_SetOutputVoiceMatrix(p,a,b,c,d) (p)->SetOutputVoiceMatrix(a,b,c,d) - #endif - -+/***************************************************************************** -+ * IXACT34Cue interface -+ */ -+#define INTERFACE IXACT34Cue -+DECLARE_INTERFACE(IXACT34Cue) -+{ -+ /*** IXACT34Cue methods ***/ -+ STDMETHOD(Play)(THIS) PURE; -+ STDMETHOD(Stop)(THIS_ DWORD pdwFlags) PURE; -+ STDMETHOD(GetState)(THIS_ DWORD *pdwState) PURE; -+ STDMETHOD(Destroy)(THIS) PURE; -+ STDMETHOD(SetMatrixCoefficients)(THIS_ UINT32 uSrcChannelCount, UINT32 uDstChannelCount, float *pMatrixCoefficients) PURE; -+ STDMETHOD_(XACTVARIABLEINDEX,GetVariableIndex)(THIS_ PCSTR szFriendlyName) PURE; -+ STDMETHOD(SetVariable)(THIS_ XACTVARIABLEINDEX nIndex, XACTVARIABLEVALUE nValue) PURE; -+ STDMETHOD(GetVariable)(THIS_ XACTVARIABLEINDEX nIndex, XACTVARIABLEVALUE *nValue) PURE; -+ STDMETHOD(Pause)(THIS_ BOOL fPause) PURE; -+ STDMETHOD(GetProperties)(THIS_ LPXACT_CUE_INSTANCE_PROPERTIES *ppProperties) PURE; -+}; -+#undef INTERFACE -+ -+#if !defined(__cplusplus) || defined(CINTERFACE) -+/*** IXACT34Cue methods ***/ -+#define IXACT34Cue_Play(p) (p)->lpVtbl->Destroy(p) -+#define IXACT34Cue_Stop(p,a) (p)->lpVtbl->Stop(p,a) -+#define IXACT34Cue_GetState(p,a) (p)->lpVtbl->GetState(p,a) -+#define IXACT34Cue_Destroy(p) (p)->lpVtbl->Destroy(p) -+#define IXACT34Cue_SetMatrixCoefficients(p,a,b,c) (p)->lpVtbl->SetMatrixCoefficients(p,a,b,c) -+#define IXACT34Cue_GetVariableIndex(p,a) (p)->lpVtbl->GetVariableIndex(p,a) -+#define IXACT34Cue_SetVariable(p,a,b) (p)->lpVtbl->SetVariable(p,a,b) -+#define IXACT34Cue_GetVariable(p,a,b) (p)->lpVtbl->GetVariable(p,a,b) -+#define IXACT34Cue_Pause(p,a) (p)->lpVtbl->Pause(p,a) -+#define IXACT34Cue_GetProperties(p,a) (p)->lpVtbl->GetProperties(p,a) -+#define IXACT34Cue_SetOutputVoices(p,a) (p)->lpVtbl->SetOutputVoices(p,a) -+#define IXACT34Cue_SetOutputVoiceMatrix(p,a,b,c,d) (p)->lpVtbl->SetOutputVoiceMatrix(p,a,b,c,d) -+#else -+/*** IXACT34Cue methods ***/ -+#define IXACT34Cue_Play(p) (p)->Destroy() -+#define IXACT34Cue_Stop(p,a) (p)->Stop(a) -+#define IXACT34Cue_GetState(p,a) (p)->Stop(a) -+#define IXACT34Cue_Destroy(p) (p)->Destroy() -+#define IXACT34Cue_SetMatrixCoefficients(p,a,b,c) (p)->SetMatrixCoefficients(a,b,c) -+#define IXACT34Cue_GetVariableIndex(p,a) (p)->GetVariableIndex(a) -+#define IXACT34Cue_SetVariable(p,a,b) (p)->SetVariable(a,b) -+#define IXACT34Cue_GetVariable(p,a,b) (p)->GetVariable(a,b) -+#define IXACT34Cue_Pause(p,a) (p)->Pause(a) -+#define IXACT34Cue_GetProperties(p,a) (p)->GetProperties(a) -+#define IXACT34Cue_SetOutputVoices(p,a) (p)->SetOutputVoices(a) -+#define IXACT34Cue_SetOutputVoiceMatrix(p,a,b,c,d) (p)->SetOutputVoiceMatrix(a,b,c,d) -+#endif -+ - /***************************************************************************** - * IXACT3Wave interface - */ -From 11607d48e3110898fe61d48b9d11b2ca98869462 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 15 Jan 2019 10:10:47 -0600 -Subject: [PATCH] HACK: ntdll: Don't pass SDL_AUDIODRIVER from Linux - environment. - ---- - dlls/ntdll/unix/env.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c -index c2c420100d1..45e18dbccaf 100644 ---- a/dlls/ntdll/unix/env.c -+++ b/dlls/ntdll/unix/env.c -@@ -534,6 +534,7 @@ static BOOL is_special_env_var( const char *var ) - STARTS_WITH( var, "TEMP=" ) || - STARTS_WITH( var, "TMP=" ) || - STARTS_WITH( var, "QT_" ) || -+ STARTS_WITH( var, "SDL_AUDIODRIVER=" ) || - STARTS_WITH( var, "VK_" )); - } - -From fd70d39797c088a8877dfd6d2563c9c5ab5a7f30 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Wed, 15 Jan 2020 10:17:23 -0600 -Subject: [PATCH] dsound: Initialize primary buffer with device's channel - layout - -Fixes surround sound in some games, like Borderlands GOTY and Dead -Space. ---- - dlls/dsound/dsound.c | 77 +----------------------------------- - dlls/dsound/dsound_private.h | 1 - - dlls/dsound/primary.c | 75 ++++++++++++++++++++++++++++++++++- - 3 files changed, 76 insertions(+), 77 deletions(-) - -diff --git a/dlls/dsound/dsound.c b/dlls/dsound/dsound.c -index bcff0d8642a..cb53f1058a5 100644 ---- a/dlls/dsound/dsound.c -+++ b/dlls/dsound/dsound.c -@@ -23,7 +23,6 @@ - #include - #include - #include --#include - - #define COBJMACROS - -@@ -137,9 +136,9 @@ static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice) - device->ref = 1; - device->priolevel = DSSCL_NORMAL; - device->stopped = 1; -- device->speaker_config = DSSPEAKER_COMBINED(DSSPEAKER_STEREO, DSSPEAKER_GEOMETRY_WIDE); - -- DSOUND_ParseSpeakerConfig(device); -+ device->speaker_config = 0; -+ device->num_speakers = 0; - - /* 3D listener initial parameters */ - device->ds3dl.dwSize = sizeof(DS3DLISTENER); -@@ -1128,74 +1128,3 @@ HRESULT WINAPI DirectSoundCreate8( - return hr; - } - --void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) --{ -- switch (DSSPEAKER_CONFIG(device->speaker_config)) { -- case DSSPEAKER_MONO: -- device->speaker_angles[0] = M_PI/180.0f * 0.0f; -- device->speaker_num[0] = 0; -- device->num_speakers = 1; -- device->lfe_channel = -1; -- break; -- -- case DSSPEAKER_STEREO: -- case DSSPEAKER_HEADPHONE: -- device->speaker_angles[0] = M_PI/180.0f * -90.0f; -- device->speaker_angles[1] = M_PI/180.0f * 90.0f; -- device->speaker_num[0] = 0; /* Left */ -- device->speaker_num[1] = 1; /* Right */ -- device->num_speakers = 2; -- device->lfe_channel = -1; -- break; -- -- case DSSPEAKER_QUAD: -- device->speaker_angles[0] = M_PI/180.0f * -135.0f; -- device->speaker_angles[1] = M_PI/180.0f * -45.0f; -- device->speaker_angles[2] = M_PI/180.0f * 45.0f; -- device->speaker_angles[3] = M_PI/180.0f * 135.0f; -- device->speaker_num[0] = 2; /* Rear left */ -- device->speaker_num[1] = 0; /* Front left */ -- device->speaker_num[2] = 1; /* Front right */ -- device->speaker_num[3] = 3; /* Rear right */ -- device->num_speakers = 4; -- device->lfe_channel = -1; -- break; -- -- case DSSPEAKER_5POINT1_BACK: -- device->speaker_angles[0] = M_PI/180.0f * -135.0f; -- device->speaker_angles[1] = M_PI/180.0f * -45.0f; -- device->speaker_angles[2] = M_PI/180.0f * 0.0f; -- device->speaker_angles[3] = M_PI/180.0f * 45.0f; -- device->speaker_angles[4] = M_PI/180.0f * 135.0f; -- device->speaker_angles[5] = 9999.0f; -- device->speaker_num[0] = 4; /* Rear left */ -- device->speaker_num[1] = 0; /* Front left */ -- device->speaker_num[2] = 2; /* Front centre */ -- device->speaker_num[3] = 1; /* Front right */ -- device->speaker_num[4] = 5; /* Rear right */ -- device->speaker_num[5] = 3; /* LFE */ -- device->num_speakers = 6; -- device->lfe_channel = 3; -- break; -- -- case DSSPEAKER_5POINT1_SURROUND: -- device->speaker_angles[0] = M_PI/180.0f * -90.0f; -- device->speaker_angles[1] = M_PI/180.0f * -30.0f; -- device->speaker_angles[2] = M_PI/180.0f * 0.0f; -- device->speaker_angles[3] = M_PI/180.0f * 30.0f; -- device->speaker_angles[4] = M_PI/180.0f * 90.0f; -- device->speaker_angles[5] = 9999.0f; -- device->speaker_num[0] = 4; /* Rear left */ -- device->speaker_num[1] = 0; /* Front left */ -- device->speaker_num[2] = 2; /* Front centre */ -- device->speaker_num[3] = 1; /* Front right */ -- device->speaker_num[4] = 5; /* Rear right */ -- device->speaker_num[5] = 3; /* LFE */ -- device->num_speakers = 6; -- device->lfe_channel = 3; -- break; -- -- default: -- WARN("unknown speaker_config %lu\n", device->speaker_config); -- } --} -diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h -index 18dc369db5c..c39d9ec40ea 100644 ---- a/dlls/dsound/dsound_private.h -+++ b/dlls/dsound/dsound_private.h -@@ -208,7 +208,6 @@ HRESULT IKsPrivatePropertySetImpl_Create(REFIID riid, void **ppv) DECLSPEC_HIDDE - HRESULT DSOUND_Create(REFIID riid, void **ppv) DECLSPEC_HIDDEN; - HRESULT DSOUND_Create8(REFIID riid, void **ppv) DECLSPEC_HIDDEN; - HRESULT IDirectSoundImpl_Create(IUnknown *outer_unk, REFIID riid, void **ppv, BOOL has_ds8) DECLSPEC_HIDDEN; --void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) DECLSPEC_HIDDEN; - - /* primary.c */ - -diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c -index e7da015a533..25a15466190 100644 ---- a/dlls/dsound/primary.c -+++ b/dlls/dsound/primary.c -@@ -24,6 +24,7 @@ - */ - - #include -+#include - - #define COBJMACROS - #define NONAMELESSUNION -@@ -109,6 +110,78 @@ static DWORD DSOUND_FindSpeakerConfig(IMMDevice *mmdevice, int channels) - return def; - } - -+static void DSOUND_ParseSpeakerConfig(DirectSoundDevice *device) -+{ -+ switch (DSSPEAKER_CONFIG(device->speaker_config)) { -+ case DSSPEAKER_MONO: -+ device->speaker_angles[0] = M_PI/180.0f * 0.0f; -+ device->speaker_num[0] = 0; -+ device->num_speakers = 1; -+ device->lfe_channel = -1; -+ break; -+ -+ case DSSPEAKER_STEREO: -+ case DSSPEAKER_HEADPHONE: -+ device->speaker_angles[0] = M_PI/180.0f * -90.0f; -+ device->speaker_angles[1] = M_PI/180.0f * 90.0f; -+ device->speaker_num[0] = 0; /* Left */ -+ device->speaker_num[1] = 1; /* Right */ -+ device->num_speakers = 2; -+ device->lfe_channel = -1; -+ break; -+ -+ case DSSPEAKER_QUAD: -+ device->speaker_angles[0] = M_PI/180.0f * -135.0f; -+ device->speaker_angles[1] = M_PI/180.0f * -45.0f; -+ device->speaker_angles[2] = M_PI/180.0f * 45.0f; -+ device->speaker_angles[3] = M_PI/180.0f * 135.0f; -+ device->speaker_num[0] = 2; /* Rear left */ -+ device->speaker_num[1] = 0; /* Front left */ -+ device->speaker_num[2] = 1; /* Front right */ -+ device->speaker_num[3] = 3; /* Rear right */ -+ device->num_speakers = 4; -+ device->lfe_channel = -1; -+ break; -+ -+ case DSSPEAKER_5POINT1_BACK: -+ device->speaker_angles[0] = M_PI/180.0f * -135.0f; -+ device->speaker_angles[1] = M_PI/180.0f * -45.0f; -+ device->speaker_angles[2] = M_PI/180.0f * 0.0f; -+ device->speaker_angles[3] = M_PI/180.0f * 45.0f; -+ device->speaker_angles[4] = M_PI/180.0f * 135.0f; -+ device->speaker_angles[5] = 9999.0f; -+ device->speaker_num[0] = 4; /* Rear left */ -+ device->speaker_num[1] = 0; /* Front left */ -+ device->speaker_num[2] = 2; /* Front centre */ -+ device->speaker_num[3] = 1; /* Front right */ -+ device->speaker_num[4] = 5; /* Rear right */ -+ device->speaker_num[5] = 3; /* LFE */ -+ device->num_speakers = 6; -+ device->lfe_channel = 3; -+ break; -+ -+ case DSSPEAKER_5POINT1_SURROUND: -+ device->speaker_angles[0] = M_PI/180.0f * -90.0f; -+ device->speaker_angles[1] = M_PI/180.0f * -30.0f; -+ device->speaker_angles[2] = M_PI/180.0f * 0.0f; -+ device->speaker_angles[3] = M_PI/180.0f * 30.0f; -+ device->speaker_angles[4] = M_PI/180.0f * 90.0f; -+ device->speaker_angles[5] = 9999.0f; -+ device->speaker_num[0] = 4; /* Rear left */ -+ device->speaker_num[1] = 0; /* Front left */ -+ device->speaker_num[2] = 2; /* Front centre */ -+ device->speaker_num[3] = 1; /* Front right */ -+ device->speaker_num[4] = 5; /* Rear right */ -+ device->speaker_num[5] = 3; /* LFE */ -+ device->num_speakers = 6; -+ device->lfe_channel = 3; -+ break; -+ -+ default: -+ WARN("unknown speaker_config %u\n", device->speaker_config); -+ } -+} -+ - static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client, - BOOL forcewave, WAVEFORMATEX **wfx) - { -@@ -123,7 +196,7 @@ static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client - if (FAILED(hr)) - return hr; - -- if (mixwfe->Format.nChannels < device->num_speakers) { -+ if (device->num_speakers == 0 || mixwfe->Format.nChannels < device->num_speakers) { - device->speaker_config = DSOUND_FindSpeakerConfig(device->mmdevice, mixwfe->Format.nChannels); - DSOUND_ParseSpeakerConfig(device); - } else if (mixwfe->Format.nChannels > device->num_speakers) { -From ae709d6c2345b60dbfc238a74a806d4f31afb3f6 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 7 Apr 2020 11:05:47 -0500 -Subject: [PATCH] winepulse: Add stub IAudioClockAdjustment implementation - ---- - dlls/winepulse.drv/mmdevdrv.c | 47 +++++++++++++++++++++++++++++++++++ - 1 file changed, 47 insertions(+) - -diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c -index 35a66e18d8a..16b9f90e0b5 100644 ---- a/dlls/winepulse.drv/mmdevdrv.c -+++ b/dlls/winepulse.drv/mmdevdrv.c -@@ -130,6 +130,7 @@ struct ACImpl { - IAudioCaptureClient IAudioCaptureClient_iface; - IAudioClock IAudioClock_iface; - IAudioClock2 IAudioClock2_iface; -+ IAudioClockAdjustment IAudioClockAdjustment_iface; - IAudioStreamVolume IAudioStreamVolume_iface; - IUnknown *marshal; - IMMDevice *parent; -@@ -157,6 +158,7 @@ static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl; - static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl; - static const IAudioClockVtbl AudioClock_Vtbl; - static const IAudioClock2Vtbl AudioClock2_Vtbl; -+static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl; - static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl; - - static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client); -@@ -201,6 +203,11 @@ static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface) - return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface); - } - -+static inline ACImpl *impl_from_IAudioClockAdjustment(IAudioClockAdjustment *iface) -+{ -+ return CONTAINING_RECORD(iface, ACImpl, IAudioClockAdjustment_iface); -+} -+ - static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) - { - return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); -@@ -339,6 +346,7 @@ HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient - This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl; - This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl; - This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl; -+ This->IAudioClockAdjustment_iface.lpVtbl = &AudioClockAdjustment_Vtbl; - This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl; - This->dataflow = dataflow; - This->parent = dev; -@@ -372,6 +380,8 @@ static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface, - IsEqualIID(riid, &IID_IAudioClient2) || - IsEqualIID(riid, &IID_IAudioClient3)) - *ppv = iface; -+ else if (IsEqualIID(riid, &IID_IAudioClockAdjustment)) -+ *ppv = &This->IAudioClockAdjustment_iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -@@ -1481,6 +1491,43 @@ static const IAudioClock2Vtbl AudioClock2_Vtbl = - AudioClock2_GetDevicePosition - }; - -+static HRESULT WINAPI AudioClockAdjustment_QueryInterface(IAudioClockAdjustment *iface, -+ REFIID riid, void **ppv) -+{ -+ ACImpl *This = impl_from_IAudioClockAdjustment(iface); -+ return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv); -+} -+ -+static ULONG WINAPI AudioClockAdjustment_AddRef(IAudioClockAdjustment *iface) -+{ -+ ACImpl *This = impl_from_IAudioClockAdjustment(iface); -+ return IAudioClient_AddRef((IAudioClient *)&This->IAudioClient3_iface); -+} -+ -+static ULONG WINAPI AudioClockAdjustment_Release(IAudioClockAdjustment *iface) -+{ -+ ACImpl *This = impl_from_IAudioClockAdjustment(iface); -+ return IAudioClient_Release((IAudioClient *)&This->IAudioClient3_iface); -+} -+ -+static HRESULT WINAPI AudioClockAdjustment_SetSampleRate(IAudioClockAdjustment *iface, -+ float new_rate) -+{ -+ ACImpl *This = impl_from_IAudioClockAdjustment(iface); -+ -+ TRACE("(%p)->(%f)\n", This, new_rate); -+ -+ return E_NOTIMPL; -+} -+ -+static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl = -+{ -+ AudioClockAdjustment_QueryInterface, -+ AudioClockAdjustment_AddRef, -+ AudioClockAdjustment_Release, -+ AudioClockAdjustment_SetSampleRate -+}; -+ - static HRESULT WINAPI AudioStreamVolume_QueryInterface( - IAudioStreamVolume *iface, REFIID riid, void **ppv) - { -From 73a43758cb69cb02526d5bc0c3204730bb4f233f Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 1 Oct 2021 12:47:58 +0200 -Subject: [PATCH] winepulse: Implement IAudioClockAdjustment::SetSampleRate - ---- - dlls/winepulse.drv/mmdevdrv.c | 9 ++++++-- - dlls/winepulse.drv/pulse.c | 40 +++++++++++++++++++++++++++++++++-- - dlls/winepulse.drv/unixlib.h | 8 +++++++ - 3 files changed, 53 insertions(+), 4 deletions(-) - -diff --git a/dlls/winepulse.drv/mmdevdrv.c b/dlls/winepulse.drv/mmdevdrv.c -index 16b9f90e0b5..96dd5374f2a 100644 ---- a/dlls/winepulse.drv/mmdevdrv.c -+++ b/dlls/winepulse.drv/mmdevdrv.c -@@ -1514,10 +1514,15 @@ static HRESULT WINAPI AudioClockAdjustment_SetSampleRate(IAudioClockAdjustment * - float new_rate) - { - ACImpl *This = impl_from_IAudioClockAdjustment(iface); -+ struct set_sample_rate_params params; - -- TRACE("(%p)->(%f)\n", This, new_rate); -+ if (!This->pulse_stream) -+ return AUDCLNT_E_NOT_INITIALIZED; - -- return E_NOTIMPL; -+ params.stream = This->pulse_stream; -+ params.new_rate = new_rate; -+ pulse_call(set_sample_rate, ¶ms); -+ return params.result; - } - - static const IAudioClockAdjustmentVtbl AudioClockAdjustment_Vtbl = -diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c -index 356f68e0db2..1c77734cf1b 100644 ---- a/dlls/winepulse.drv/pulse.c -+++ b/dlls/winepulse.drv/pulse.c -@@ -925,7 +923,7 @@ static HRESULT pulse_spec_from_waveformat(struct pulse_stream *stream, const WAV - - static HRESULT pulse_stream_connect(struct pulse_stream *stream, const char *pulse_name, UINT32 period_bytes) - { -- pa_stream_flags_t flags = PA_STREAM_START_CORKED | PA_STREAM_START_UNMUTED | PA_STREAM_ADJUST_LATENCY; -+ pa_stream_flags_t flags = PA_STREAM_START_CORKED | PA_STREAM_START_UNMUTED | PA_STREAM_ADJUST_LATENCY | PA_STREAM_VARIABLE_RATE; - int ret; - char buffer[64]; - static LONG number; -@@ -1949,6 +1949,41 @@ static NTSTATUS pulse_set_event_handle(void *args) - return STATUS_SUCCESS; - } - -+static NTSTATUS pulse_set_sample_rate(void *args) -+{ -+ struct set_sample_rate_params *params = args; -+ struct pulse_stream *stream = params->stream; -+ HRESULT hr = S_OK; -+ pa_operation *o; -+ int success; -+ -+ pulse_lock(); -+ if (!pulse_stream_valid(stream)) -+ hr = AUDCLNT_E_DEVICE_INVALIDATED; -+ else -+ { -+ if (!(o = pa_stream_update_sample_rate(stream->stream, params->new_rate, pulse_op_cb, &success))) -+ success = 0; -+ else -+ { -+ while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) -+ pthread_cond_wait(&pulse_cond, &pulse_mutex); -+ pa_operation_unref(o); -+ } -+ -+ if (!success) hr = E_FAIL; -+ else -+ { -+ stream->ss.rate = params->new_rate; -+ stream->period_bytes = pa_frame_size(&stream->ss) * muldiv(stream->mmdev_period_usec, stream->ss.rate, 1000000); -+ } -+ } -+ pulse_unlock(); -+ -+ params->result = hr; -+ return STATUS_SUCCESS; -+} -+ - static NTSTATUS pulse_is_started(void *args) - { - struct is_started_params *params = args; -@@ -1984,6 +2019,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - pulse_get_position, - pulse_set_volumes, - pulse_set_event_handle, -+ pulse_set_sample_rate, - pulse_test_connect, - pulse_is_started, - }; -diff --git a/dlls/winepulse.drv/unixlib.h b/dlls/winepulse.drv/unixlib.h -index d28a73ca649..e80dcd50817 100644 ---- a/dlls/winepulse.drv/unixlib.h -+++ b/dlls/winepulse.drv/unixlib.h -@@ -173,6 +173,13 @@ struct set_event_handle_params - HRESULT result; - }; - -+struct set_sample_rate_params -+{ -+ struct pulse_stream *stream; -+ float new_rate; -+ HRESULT result; -+}; -+ - struct test_connect_params - { - const char *name; -@@ -209,6 +216,7 @@ enum unix_funcs - get_position, - set_volumes, - set_event_handle, -+ set_sample_rate, - test_connect, - is_started, - }; -From 3b176c060227854a40333c0ec5c634a2e9d39fd4 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 10 Dec 2018 12:48:41 -0600 -Subject: [PATCH] winepulse: Set PulseAudio application name property in the - environment. - -So PA doesn't present all Wine applications as "wine-preloader", and -allows PA to store per-application settings. ---- - dlls/winepulse.drv/pulse.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/winepulse.drv/pulse.c b/dlls/winepulse.drv/pulse.c -index 1c77734cf1b..e93449cc570 100644 ---- a/dlls/winepulse.drv/pulse.c -+++ b/dlls/winepulse.drv/pulse.c -@@ -292,6 +292,7 @@ static HRESULT pulse_connect(const char *name) - pa_context_unref(pulse_ctx); - - pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), name); -+ setenv("PULSE_PROP_application.name", name, 1); - if (!pulse_ctx) { - ERR("Failed to create context\n"); - return E_FAIL; -From b4db762e36a0ec88d1da45c88fd099bbdb015956 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 16 Jun 2021 17:36:15 +0200 -Subject: [PATCH] devenum: Register IEEE float for Direct Sound default device. - -Fixes some music does not play in Planet Coaster. - -CW-Bug-Id: #18986 ---- - dlls/devenum/createdevenum.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c -index bec462e0f5a..447d71efc8a 100644 ---- a/dlls/devenum/createdevenum.c -+++ b/dlls/devenum/createdevenum.c -@@ -477,7 +477,7 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons - static const WCHAR defaultW[] = L"Default DirectSound Device"; - IPropertyBag *prop_bag = NULL; - REGFILTERPINS2 rgpins = {0}; -- REGPINTYPES rgtypes = {0}; -+ REGPINTYPES rgtypes[2] = {}; - REGFILTER2 rgf = {0}; - WCHAR clsid[CHARS_IN_GUID]; - VARIANT var; -@@ -508,10 +508,12 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons - rgf.rgPins2 = &rgpins; - rgpins.dwFlags = REG_PINFLAG_B_RENDERER; - /* FIXME: native registers many more formats */ -- rgpins.nMediaTypes = 1; -- rgpins.lpMediaType = &rgtypes; -- rgtypes.clsMajorType = &MEDIATYPE_Audio; -- rgtypes.clsMinorType = &MEDIASUBTYPE_PCM; -+ rgpins.nMediaTypes = 2; -+ rgpins.lpMediaType = rgtypes; -+ rgtypes[0].clsMajorType = &MEDIATYPE_Audio; -+ rgtypes[0].clsMinorType = &MEDIASUBTYPE_PCM; -+ rgtypes[1].clsMajorType = &MEDIATYPE_Audio; -+ rgtypes[1].clsMinorType = &MEDIASUBTYPE_IEEE_FLOAT; - - write_filter_data(prop_bag, &rgf); - -From 5fa7d93d8e52122029e625ea0ca5b4f1882adb83 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 20 Jan 2022 12:24:47 +0100 -Subject: [PATCH] faudio: Clear the end of WMA buffer when decoded output is - too short. - ---- - libs/faudio/src/FAudio_platform_win32.c | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/libs/faudio/src/FAudio_platform_win32.c b/libs/faudio/src/FAudio_platform_win32.c -index d99bae044a4..6345a359997 100644 ---- a/libs/faudio/src/FAudio_platform_win32.c -+++ b/libs/faudio/src/FAudio_platform_win32.c -@@ -1143,8 +1143,8 @@ static void FAudio_INTERNAL_DecodeWMAMF( - uint32_t samples - ) { - const FAudioWaveFormatExtensible *wfx = (FAudioWaveFormatExtensible *)voice->src.format; -+ size_t samples_pos, samples_size, copy_size = 0; - struct FAudioWMADEC *impl = voice->src.wmadec; -- size_t samples_pos, samples_size, copy_size; - HRESULT hr; - - LOG_FUNC_ENTER(voice->audio) -@@ -1216,8 +1216,12 @@ static void FAudio_INTERNAL_DecodeWMAMF( - impl->input_size = 0; - } - -- copy_size = FAudio_clamp(impl->output_pos - samples_pos, 0, samples_size); -- FAudio_memcpy(decodeCache, impl->output_buf + samples_pos, copy_size); -+ if (impl->output_pos > samples_pos) -+ { -+ copy_size = FAudio_min(impl->output_pos - samples_pos, samples_size); -+ FAudio_memcpy(decodeCache, impl->output_buf + samples_pos, copy_size); -+ } -+ FAudio_zero(decodeCache + copy_size, samples_size - copy_size); - LOG_INFO( - voice->audio, - "decoded %x / %x bytes, copied %x / %x bytes", -From e2c6ce707e8b91277eaf637d0923f03ee38c5e1f Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 31 Jan 2022 10:57:51 -0600 -Subject: [PATCH] mmdevapi: Force PCM format for DeviceFormat property - -Native xaudio2 returns this format directly from GetDeviceDetails. Far -Cry 4 expects to get a PCM format from GetDeviceDetails, so we need to -set it to PCM here. ---- - dlls/mmdevapi/devenum.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c -index b17572425f3..e59396ae48e 100644 ---- a/dlls/mmdevapi/devenum.c -+++ b/dlls/mmdevapi/devenum.c -@@ -433,6 +433,7 @@ static HRESULT set_format(MMDevice *dev) - HRESULT hr; - IAudioClient *client; - WAVEFORMATEX *fmt; -+ WAVEFORMATEXTENSIBLE *fmtex; - PROPVARIANT pv = { VT_EMPTY }; - - hr = drvs.pGetAudioEndpoint(&dev->devguid, &dev->IMMDevice_iface, &client); -@@ -447,6 +448,24 @@ static HRESULT set_format(MMDevice *dev) - - IAudioClient_Release(client); - -+ /* for most devices, native Windows only allows PCM formats for -+ * DeviceFormat. GetMixFormat often returns float. */ -+ if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ -+ fmtex = (WAVEFORMATEXTENSIBLE *)fmt; -+ if(IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){ -+ fmt->wBitsPerSample = 16; -+ fmt->nBlockAlign = fmt->wBitsPerSample * fmt->nChannels / 8; -+ fmt->nAvgBytesPerSec = fmt->nSamplesPerSec * fmt->nBlockAlign; -+ fmtex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; -+ fmtex->Samples.wValidBitsPerSample = fmt->wBitsPerSample; -+ } -+ }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT){ -+ fmt->wFormatTag = WAVE_FORMAT_PCM; -+ fmt->wBitsPerSample = 16; -+ fmt->nBlockAlign = fmt->wBitsPerSample * fmt->nChannels / 8; -+ fmt->nAvgBytesPerSec = fmt->nSamplesPerSec * fmt->nBlockAlign; -+ } -+ - pv.vt = VT_BLOB; - pv.blob.cbSize = sizeof(WAVEFORMATEX) + fmt->cbSize; - pv.blob.pBlobData = (BYTE*)fmt; diff --git a/patches/proton/12-proton-steam-bits.patch b/patches/proton/12-proton-steam-bits.patch deleted file mode 100755 index 24dcc745d..000000000 --- a/patches/proton/12-proton-steam-bits.patch +++ /dev/null @@ -1,778 +0,0 @@ -From 60365fa2e1f55e51b44788d5eac68c6ddce77266 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Wed, 27 Dec 2017 13:31:59 -0600 -Subject: [PATCH] HACK: steam: wine.inf: Add required Steam registry entries. - ---- - loader/wine.inf.in | 25 ++++++++++++++++++++++--- - 1 file changed, 22 insertions(+), 3 deletions(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 5f9f61e2535..43cae2a2bc2 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -73,7 +73,8 @@ AddReg=\ - Tapi,\ - Timezones,\ - VersionInfo,\ -- LicenseInformation -+ LicenseInformation, \ -+ SteamClient - - [DefaultInstall.ntamd64] - RegisterDlls=RegisterDllsSection -@@ -100,7 +101,8 @@ AddReg=\ - Tapi,\ - Timezones,\ - VersionInfo.ntamd64,\ -- LicenseInformation -+ LicenseInformation, \ -+ SteamClient.ntamd64 - - [DefaultInstall.ntarm64] - RegisterDlls=RegisterDllsSection -@@ -142,7 +144,8 @@ AddReg=\ - Misc,\ - Tapi,\ - VersionInfo.ntamd64,\ -- LicenseInformation -+ LicenseInformation, \ -+ SteamClient.ntamd64 - - [Wow64Install.ntarm64] - WineFakeDlls=FakeDllsWin32 -@@ -3867,6 +3870,22 @@ l_intl.nls - winehid.inf,"@%12%\winehid.sys,-1" - wineusb.inf,"@%12%\wineusb.sys,-1" - winexinput.inf,"@%12%\winexinput.sys,-1" -+ -+[SteamClient] -+HKCU,Software\Valve\Steam,"SteamPath",,"%16422%\Steam" -+HKCU,Software\Valve\Steam,"SteamExe",,"%16422%\Steam\Steam.exe" -+HKCU,Software\Valve\Steam\ActiveProcess,"PID",0x10001,0x0000fffe -+HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll",,"%16422%\Steam\steamclient.dll" -+HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16422%\Steam" -+ -+[SteamClient.ntamd64] -+HKCU,Software\Valve\Steam,"SteamPath",,"%16422%\Steam" -+HKCU,Software\Valve\Steam,"SteamExe",,"%16422%\Steam\Steam.exe" -+HKCU,Software\Valve\Steam\ActiveProcess,"PID",0x10001,0x0000fffe -+HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll",,"%16426%\Steam\steamclient.dll" -+HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steamclient64.dll" -+HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" -+HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" - - [NlsFiles] - c_037.nls - -From f725f3ce82ddb6b8ab9d427dda5dcd30b512b7f8 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 27 Apr 2017 13:25:04 -0500 -Subject: [PATCH] HACK: steam: kernelbase: Substitute the current pid for the - Steam client pid. - ---- - dlls/kernelbase/process.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c -index 12187b92e5c..a22b59ad80b 100644 ---- a/dlls/kernelbase/process.c -+++ b/dlls/kernelbase/process.c -@@ -1014,6 +1014,21 @@ HANDLE WINAPI DECLSPEC_HOTPATCH OpenProcess( DWORD access, BOOL inherit, DWORD i - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - -+ /* PROTON HACK: -+ * On Windows, the Steam client puts its process ID into the registry -+ * at: -+ * -+ * [HKCU\Software\Valve\Steam\ActiveProcess] -+ * PID=dword:00000008 -+ * -+ * Games get that pid from the registry and then query it with -+ * OpenProcess to ensure Steam is running. Since we aren't running the -+ * Windows Steam in Wine, instead we hack this magic number into the -+ * registry and then substitute the game's process itself in its place -+ * so it can query a valid process. -+ */ -+ if (id == 0xfffe) id = GetCurrentProcessId(); -+ - cid.UniqueProcess = ULongToHandle(id); - cid.UniqueThread = 0; - -From df134c39cab2e1a32c75d34d7b9348482abe73d1 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 19 Jan 2018 14:01:07 -0600 -Subject: [PATCH] HACK: proton: advapi32: Use steamuser as Wine username. - ---- - dlls/advapi32/advapi.c | 34 ++++++++++++++++++---------------- - 1 file changed, 18 insertions(+), 16 deletions(-) - -diff --git a/dlls/advapi32/advapi.c b/dlls/advapi32/advapi.c -index 33c63f3cb20..0ebe6a354b5 100644 ---- a/dlls/advapi32/advapi.c -+++ b/dlls/advapi32/advapi.c -@@ -43,14 +43,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(advapi); - */ - BOOL WINAPI GetUserNameA( LPSTR name, LPDWORD size ) - { -- DWORD len = GetEnvironmentVariableA( "WINEUSERNAME", name, *size ); -- BOOL ret; -- -- if (!len) return FALSE; -- if ((ret = (len < *size))) len++; -- else SetLastError( ERROR_INSUFFICIENT_BUFFER ); -- *size = len; -- return ret; -+ static const char steamuserA[] = {'s','t','e','a','m','u','s','e','r',0}; -+ if(*size < ARRAY_SIZE(steamuserA)){ -+ SetLastError( ERROR_INSUFFICIENT_BUFFER ); -+ *size = ARRAY_SIZE(steamuserA); -+ return FALSE; -+ } -+ memcpy(name, steamuserA, sizeof(steamuserA)); -+ *size = ARRAY_SIZE(steamuserA); -+ return TRUE; - } - - /****************************************************************************** -@@ -58,14 +59,15 @@ BOOL WINAPI GetUserNameA( LPSTR name, LPDWORD size ) - */ - BOOL WINAPI GetUserNameW( LPWSTR name, LPDWORD size ) - { -- DWORD len = GetEnvironmentVariableW( L"WINEUSERNAME", name, *size ); -- BOOL ret; -- -- if (!len) return FALSE; -- if ((ret = (len < *size))) len++; -- else SetLastError( ERROR_INSUFFICIENT_BUFFER ); -- *size = len; -- return ret; -+ static const WCHAR steamuserW[] = {'s','t','e','a','m','u','s','e','r',0}; -+ if(*size < ARRAY_SIZE(steamuserW)){ -+ SetLastError( ERROR_INSUFFICIENT_BUFFER ); -+ *size = ARRAY_SIZE(steamuserW); -+ return FALSE; -+ } -+ memcpy(name, steamuserW, sizeof(steamuserW)); -+ *size = ARRAY_SIZE(steamuserW); -+ return TRUE; - } - - /****************************************************************************** -From c3fadbbbeadb8fd49fb2edfd2ee4ca37a46cfbff Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 30 Sep 2021 19:44:00 +0200 -Subject: [PATCH] HACK: proton: shell32: Never create links to the user's home - dirs. - ---- - dlls/shell32/shellpath.c | 181 --------------------------------------- - 1 file changed, 181 deletions(-) - -diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c -index 7bfa504a62f..ab04c39dc24 100644 ---- a/dlls/shell32/shellpath.c -+++ b/dlls/shell32/shellpath.c -@@ -2640,183 +2640,6 @@ static HRESULT _SHExpandEnvironmentStrings(LPCWSTR szSrc, LPWSTR szDest) - return hr; - } - --static char *xdg_config; --static DWORD xdg_config_len; -- --static BOOL WINAPI init_xdg_dirs( INIT_ONCE *once, void *param, void **context ) --{ -- const WCHAR *var, *fmt = L"\\??\\unix%s/user-dirs.dirs"; -- char *p; -- WCHAR *name, *ptr; -- HANDLE file; -- DWORD len; -- -- if (!(var = _wgetenv( L"XDG_CONFIG_HOME" )) || var[0] != '/') -- { -- if (!(var = _wgetenv( L"WINEHOMEDIR" ))) return TRUE; -- fmt = L"%s/.config/user-dirs.dirs"; -- } -- len = lstrlenW(var) + lstrlenW(fmt); -- name = heap_alloc( len * sizeof(WCHAR) ); -- swprintf( name, len, fmt, var ); -- name[1] = '\\'; /* change \??\ to \\?\ */ -- for (ptr = name; *ptr; ptr++) if (*ptr == '/') *ptr = '\\'; -- -- file = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); -- heap_free( name ); -- if (file != INVALID_HANDLE_VALUE) -- { -- len = GetFileSize( file, NULL ); -- if (!(xdg_config = heap_alloc( len + 1 ))) return TRUE; -- if (!ReadFile( file, xdg_config, len, &xdg_config_len, NULL )) -- { -- heap_free( xdg_config ); -- xdg_config = NULL; -- } -- else -- { -- for (p = xdg_config; p < xdg_config + xdg_config_len; p++) if (*p == '\n') *p = 0; -- *p = 0; /* append null to simplify string parsing */ -- } -- CloseHandle( file ); -- } -- return TRUE; --} -- --static char *get_xdg_path( const char *var ) --{ -- static INIT_ONCE once; -- char *p, *ret = NULL; -- int i; -- -- InitOnceExecuteOnce( &once, init_xdg_dirs, NULL, NULL ); -- if (!xdg_config) return NULL; -- -- for (p = xdg_config; p < xdg_config + xdg_config_len; p += strlen(p) + 1) -- { -- while (*p == ' ' || *p == '\t') p++; -- if (strncmp( p, var, strlen(var) )) continue; -- p += strlen(var); -- while (*p == ' ' || *p == '\t') p++; -- if (*p != '=') continue; -- p++; -- while (*p == ' ' || *p == '\t') p++; -- if (*p != '"') continue; -- p++; -- if (*p != '/' && strncmp( p, "$HOME/", 6 )) continue; -- -- if (!(ret = heap_alloc( strlen(p) + 1 ))) break; -- for (i = 0; *p && *p != '"'; i++, p++) -- { -- if (*p == '\\' && p[1]) p++; -- ret[i] = *p; -- } -- ret[i] = 0; -- if (*p != '"') -- { -- heap_free( ret ); -- ret = NULL; -- } -- break; -- } -- return ret; --} -- --static BOOL link_folder( HANDLE mgr, const UNICODE_STRING *path, const char *link ) --{ -- struct mountmgr_shell_folder *ioctl; -- DWORD len = sizeof(*ioctl) + path->Length + strlen(link) + 1; -- BOOL ret; -- -- if (!(ioctl = heap_alloc( len ))) return FALSE; -- ioctl->create_backup = FALSE; -- ioctl->folder_offset = sizeof(*ioctl); -- ioctl->folder_size = path->Length; -- memcpy( (char *)ioctl + ioctl->folder_offset, path->Buffer, ioctl->folder_size ); -- ioctl->symlink_offset = ioctl->folder_offset + ioctl->folder_size; -- strcpy( (char *)ioctl + ioctl->symlink_offset, link ); -- -- ret = DeviceIoControl( mgr, IOCTL_MOUNTMGR_DEFINE_SHELL_FOLDER, ioctl, len, NULL, 0, NULL, NULL ); -- heap_free( ioctl ); -- return ret; --} -- --/****************************************************************************** -- * create_link -- * -- * Sets up a symbolic link for one of the 'My Whatever' shell folders to point -- * into the corresponding XDG directory. -- */ --static void create_link( const WCHAR *path, const char *xdg_name, const char *default_name ) --{ -- UNICODE_STRING nt_name; -- char *target = NULL; -- HANDLE mgr; -- -- if ((mgr = CreateFileW( MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, -- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, -- 0, 0 )) == INVALID_HANDLE_VALUE) -- { -- FIXME( "failed to connect to mount manager\n" ); -- return; -- } -- -- nt_name.Buffer = NULL; -- if (!RtlDosPathNameToNtPathName_U( path, &nt_name, NULL, NULL )) goto done; -- -- if ((target = get_xdg_path( xdg_name ))) -- { -- if (link_folder( mgr, &nt_name, target )) goto done; -- } -- if (link_folder( mgr, &nt_name, default_name )) goto done; -- -- /* fall back to HOME */ -- link_folder( mgr, &nt_name, "$HOME" ); -- --done: -- RtlFreeUnicodeString( &nt_name ); -- heap_free( target ); -- CloseHandle( mgr ); --} -- --/****************************************************************************** -- * _SHCreateSymbolicLink [Internal] -- * -- * Sets up a symbolic link for one of the special shell folders to point into -- * the users home directory. -- * -- * PARAMS -- * nFolder [I] CSIDL identifying the folder. -- */ --static void _SHCreateSymbolicLink(int nFolder, const WCHAR *path) --{ -- DWORD folder = nFolder & CSIDL_FOLDER_MASK; -- -- switch (folder) { -- case CSIDL_PERSONAL: -- create_link( path, "XDG_DOCUMENTS_DIR", "$HOME/Documents" ); -- break; -- case CSIDL_DESKTOPDIRECTORY: -- create_link( path, "XDG_DESKTOP_DIR", "$HOME/Desktop" ); -- break; -- case CSIDL_MYPICTURES: -- create_link( path, "XDG_PICTURES_DIR", "$HOME/Pictures" ); -- break; -- case CSIDL_MYVIDEO: -- create_link( path, "XDG_VIDEOS_DIR", "$HOME/Movies" ); -- break; -- case CSIDL_MYMUSIC: -- create_link( path, "XDG_MUSIC_DIR", "$HOME/Music" ); -- break; -- case CSIDL_DOWNLOADS: -- create_link( path, "XDG_DOWNLOAD_DIR", "$HOME/Downloads" ); -- break; -- case CSIDL_TEMPLATES: -- create_link( path, "XDG_TEMPLATES_DIR", "$HOME/Templates" ); -- break; -- } --} -- - /****************************************************************************** - * SHGetFolderPathW [SHELL32.@] - * -@@ -3005,10 +2828,6 @@ HRESULT WINAPI SHGetFolderPathAndSubDirW( - goto end; - } - -- /* create symbolic links rather than directories for specific -- * user shell folders */ -- _SHCreateSymbolicLink(folder, szBuildPath); -- - /* create directory/directories */ - ret = SHCreateDirectoryExW(hwndOwner, szBuildPath, NULL); - if (ret && ret != ERROR_ALREADY_EXISTS) -From 17d19e1b23bce6fc6ff5b4e61131c9c58fd57ae5 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Wed, 28 Mar 2018 09:21:41 -0500 -Subject: [PATCH] HACK: Don't build winemenubuilder - ---- - configure | 2 -- - configure.ac | 1 - - loader/wine.inf.in | 1 - - 3 files changed, 4 deletions(-) - -diff --git a/configure b/configure -index 649a8917f54..4581015d576 100755 ---- a/configure -+++ b/configure -@@ -1746,7 +1746,6 @@ enable_wineconsole - enable_winedbg - enable_winedevice - enable_winefile --enable_winemenubuilder - enable_winemine - enable_winemsibuilder - enable_winepath -@@ -20315,7 +20314,6 @@ wine_fn_config_makefile programs/wineconsole enable_wineconsole - wine_fn_config_makefile programs/winedbg enable_winedbg - wine_fn_config_makefile programs/winedevice enable_winedevice - wine_fn_config_makefile programs/winefile enable_winefile --wine_fn_config_makefile programs/winemenubuilder enable_winemenubuilder - wine_fn_config_makefile programs/winemine enable_winemine - wine_fn_config_makefile programs/winemsibuilder enable_winemsibuilder - wine_fn_config_makefile programs/winepath enable_winepath -diff --git a/configure.ac b/configure.ac -index 704da15f404..d4168e410bc 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3998,7 +3998,6 @@ WINE_CONFIG_MAKEFILE(programs/wineconsole) - WINE_CONFIG_MAKEFILE(programs/winedbg) - WINE_CONFIG_MAKEFILE(programs/winedevice) - WINE_CONFIG_MAKEFILE(programs/winefile) --WINE_CONFIG_MAKEFILE(programs/winemenubuilder) - WINE_CONFIG_MAKEFILE(programs/winemine) - WINE_CONFIG_MAKEFILE(programs/winemsibuilder) - WINE_CONFIG_MAKEFILE(programs/winepath) -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 2b049eb91f8..e6948a73427 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -3598,7 +3598,6 @@ HKR,Parameters,"ServiceDll",,"%11%\schedsvc.dll" - HKLM,%CurrentVersionNT%\SvcHost,"netsvcs",0x00010008,"Schedule" - - [Services] --HKLM,%CurrentVersion%\RunServices,"winemenubuilder",2,"%11%\winemenubuilder.exe -a -r" - HKLM,"System\CurrentControlSet\Services\Eventlog\Application",,16 - HKLM,"System\CurrentControlSet\Services\Eventlog\System","Sources",0x10000,"" - HKLM,"System\CurrentControlSet\Services\Tcpip\Parameters","DataBasePath",2,"%11%\drivers" - -From ea8d4cc0a661d5588383baa2ed1a6c56d2e66ffc Mon Sep 17 00:00:00 2001 -From: Patryk Obara -Date: Fri, 26 Apr 2019 20:40:31 +0200 -Subject: [PATCH] HACK: proton: winex11: Fill WM_CLASS based on Steam appid. - -Some desktop environments (Gnome 3, Cinnamon) decide on an application -icon in the following order: - -- If the first string in WM_CLASS property can be correlated to - a name or StartupWMClass key in a .desktop entry file, then - the associated icon will be used. -- If the second string in WM_CLASS property can be correlated to - a name or StartupWMClass key in a .desktop entry file, then - the associated icon will be used. -- If the application has indicated an icon resource through WM_HINTS - property, then the associated X window or pixmaps will be used. - -Upstream Wine usually deals with this by placing a .desktop file with -StartupWMClass filled to match first string in WM_CLASS property -(which is the name of exe file being run). - -Wine in Proton does not do it, but still puts "Wine" as second string, -therefore desktop environment can't differentiate between Wine in -Proton and Wine installed in OS. - -By replacing "Wine" with "steam_app_" we force DE to fallback -to icon indicated by WM_HINTS (ico file embedded in exe file). -Steam can override this behaviour by installing properly crafted -.desktop entry file. If SteamAppId environment variable is missing, -then generic "steam_proton" name is used instead. ---- - dlls/winex11.drv/window.c | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 36fb41ac710..916350c685a 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -855,8 +855,19 @@ static void set_initial_wm_hints( Display *display, Window window ) - /* class hints */ - if ((class_hints = XAllocClassHint())) - { -- class_hints->res_name = process_name; -- class_hints->res_class = process_name; -+ static char steam_proton[] = "steam_proton"; -+ const char *app_id = getenv("SteamAppId"); -+ char proton_app_class[128]; -+ -+ if(app_id && *app_id){ -+ snprintf(proton_app_class, sizeof(proton_app_class), "steam_app_%s", app_id); -+ class_hints->res_name = proton_app_class; -+ class_hints->res_class = proton_app_class; -+ }else{ -+ class_hints->res_name = steam_proton; -+ class_hints->res_class = steam_proton; -+ } -+ - XSetClassHint( display, window, class_hints ); - XFree( class_hints ); - } -From 30d2ea38ead1a2f1de872c9725e67084feaf5024 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 24 Sep 2018 12:37:49 -0500 -Subject: [PATCH] HACK: proton: HACK: dbghelp: Disable DWARF parsing - -Patch by Zeb. Our DWARF parser has been known to crash winedbg in some -cases. Since probably no concerned parties are going to be using plain -winedbg, just don't bother parsing anything. ---- - dlls/dbghelp/dwarf.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c -index 7472b6070e6..e049ee51525 100644 ---- a/dlls/dbghelp/dwarf.c -+++ b/dlls/dbghelp/dwarf.c -@@ -4162,6 +4162,11 @@ BOOL dwarf2_parse(struct module* module, ULONG_PTR load_offset, - struct module_format* dwarf2_modfmt; - dwarf2_parse_module_context_t module_ctx; - -+/* Our DWARF parser has been known to crash winedbg in some cases. Since -+ * probably no concerned parties are going to be using plain winedbg, just don't -+ * bother parsing anything. */ -+return FALSE; -+ - if (!dwarf2_init_section(&eh_frame, fmap, ".eh_frame", NULL, &eh_frame_sect)) - /* lld produces .eh_fram to avoid generating a long name */ - dwarf2_init_section(&eh_frame, fmap, ".eh_fram", NULL, &eh_frame_sect); - -From daabcc156e6b63cf438aa004ac3f40a741872ad4 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 30 Mar 2018 10:40:43 -0500 -Subject: [PATCH] HACK: proton: winedbg: When crash dialog is not shown, dump - crash info to stderr - -This way the backtrace and such will appear in the log file instead of -going to stdout, which we don't capture. ---- - programs/winedbg/tgt_active.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c -index 70ad7e8b437..5a26e1aef1f 100644 ---- a/programs/winedbg/tgt_active.c -+++ b/programs/winedbg/tgt_active.c -@@ -965,6 +965,9 @@ enum dbg_start dbg_active_auto(int argc, char* argv[]) - if (event) thread = display_crash_details( event ); - if (thread) dbg_houtput = output = create_temp_file(); - break; -+ case TRUE: -+ dbg_houtput = GetStdHandle(STD_ERROR_HANDLE); -+ break; - } - - input = parser_generate_command_file("echo Modules:", "info share", -From 05b798206ccddbf1a546a97746d32aff2ca1d8b9 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 18 May 2021 13:34:47 -0500 -Subject: [PATCH] HACK: proton: winedbg: Support dumping crash logs to a - directory - -CW-Bug-Id: #18944 ---- - programs/winedbg/debugger.h | 1 + - programs/winedbg/tgt_active.c | 45 +++++++++++++++++++++++++++++++++++ - programs/winedbg/winedbg.c | 3 +++ - 3 files changed, 49 insertions(+) - -diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h -index b676bc8d955..e4e40bb487f 100644 ---- a/programs/winedbg/debugger.h -+++ b/programs/winedbg/debugger.h -@@ -283,6 +283,7 @@ extern DWORD dbg_curr_tid; - extern dbg_ctx_t dbg_context; - extern BOOL dbg_interactiveP; - extern HANDLE dbg_houtput; -+extern HANDLE dbg_crash_report_file; - - struct dbg_internal_var - { -diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c -index 5a26e1aef1f..d89a76272b0 100644 ---- a/programs/winedbg/tgt_active.c -+++ b/programs/winedbg/tgt_active.c -@@ -22,6 +22,8 @@ - #include - #include - #include -+#include -+#include - - #include "debugger.h" - #include "psapi.h" -@@ -784,6 +786,48 @@ static HANDLE create_temp_file(void) - NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0 ); - } - -+static HANDLE create_crash_report_file(void) -+{ -+ const char *dir = getenv("WINE_CRASH_REPORT_DIR"); -+ const char *sgi; -+ char timestr[32]; -+ char name[MAX_PATH], *c; -+ time_t t; -+ struct tm lt; -+ -+ if(!dir || dir[0] == 0) -+ return INVALID_HANDLE_VALUE; -+ -+ strcpy(name, dir); -+ -+ for(c = name + 1; *c; ++c){ -+ if(*c == '/'){ -+ *c = 0; -+ CreateDirectoryA(name, NULL); -+ *c = '/'; -+ } -+ } -+ CreateDirectoryA(name, NULL); -+ -+ sgi = getenv("SteamGameId"); -+ -+ t = time(NULL); -+ lt = *localtime(&t); -+ strftime(timestr, ARRAY_SIZE(timestr), "%Y-%m-%d_%H:%M:%S", <); -+ -+ /* /path/to/crash/reports/2021-05-18_13:21:15_appid-976310_crash.log */ -+ snprintf(name, ARRAY_SIZE(name), -+ "%s%s/%s_appid-%s_crash.log", -+ dir[0] == '/' ? "Z:/" : "", -+ dir, -+ timestr, -+ sgi ? sgi : "0" -+ ); -+ -+ return CreateFileA( name, GENERIC_WRITE, FILE_SHARE_READ, -+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 ); -+} -+ - static const struct - { - int type; -@@ -967,6 +1011,7 @@ enum dbg_start dbg_active_auto(int argc, char* argv[]) - break; - case TRUE: - dbg_houtput = GetStdHandle(STD_ERROR_HANDLE); -+ dbg_crash_report_file = create_crash_report_file(); - break; - } - -diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c -index dab5fbd85a3..21391bcdcec 100644 ---- a/programs/winedbg/winedbg.c -+++ b/programs/winedbg/winedbg.c -@@ -82,6 +82,7 @@ DWORD dbg_curr_pid = 0; - dbg_ctx_t dbg_context; - BOOL dbg_interactiveP = FALSE; - HANDLE dbg_houtput = 0; -+HANDLE dbg_crash_report_file = INVALID_HANDLE_VALUE; - - static struct list dbg_process_list = LIST_INIT(dbg_process_list); - -@@ -108,6 +109,8 @@ static void dbg_outputA(const char* buffer, int len) - else break; - } - WriteFile(dbg_houtput, line_buff, i, &w, NULL); -+ if (dbg_crash_report_file != INVALID_HANDLE_VALUE) -+ WriteFile(dbg_crash_report_file, line_buff, i, &w, NULL); - memmove( line_buff, line_buff + i, line_pos - i ); - line_pos -= i; - } - -From a7542e9e279970c2ab3ac9c6c986b300135286a0 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Wed, 28 Mar 2018 09:17:30 -0500 -Subject: [PATCH] wine.inf: Don't show crash dialog by default - ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 7fe2f49dcd9..e72d0dcaba1 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -540,6 +540,7 @@ HKLM,%CurrentVersionNT%\AeDebug,"Debugger",2,"winedbg --auto %ld %ld" - HKLM,%CurrentVersionNT%\AeDebug,"Auto",2,"1" - HKCU,Software\Wine\Debug,"RelayExclude",2,"ntdll.RtlEnterCriticalSection;ntdll.RtlTryEnterCriticalSection;ntdll.RtlLeaveCriticalSection;kernel32.48;kernel32.49;kernel32.94;kernel32.95;kernel32.96;kernel32.97;kernel32.98;kernel32.TlsGetValue;kernel32.TlsSetValue;kernel32.FlsGetValue;kernel32.FlsSetValue;kernel32.SetLastError" - HKCU,Software\Wine\Debug,"RelayFromExclude",2,"winex11.drv;winemac.drv;user32;gdi32;advapi32;kernel32" -+HKCU,Software\Wine\WineDbg,"ShowCrashDialog",0x00010003,0x00000000 - - [DirectX] - HKLM,Software\Microsoft\DirectX,"Version",,"4.09.00.0904" - -From ec87f47caa8a9461c2a983cb4cf7d0b7816b1ded Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Mon, 18 May 2020 14:20:30 -0500 -Subject: [PATCH] wine.inf: Associate the "steam" protocol with winebrowser. - ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 247eb906422..0b014dce63c 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -317,6 +317,7 @@ HKCR,https\shell\open\ddeexec,"NoActivateHandler",2,"" - HKCR,http\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" - HKCR,https\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" - HKCR,mailto\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" -+HKCR,steam\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" - - HKCR,MIME\Database\Charset\_iso-2022-jp$ESC,"Codepage",0x10003,932 - HKCR,MIME\Database\Charset\_iso-2022-jp$ESC,"InternetEncoding",0x10003,50221 - -From 4208548dbb789b3f3bd112a4dc1a19ebf0d1f307 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 22 Jan 2018 14:35:51 -0600 -Subject: [PATCH] HACK: wineboot: Don't show "updating prefix" window - ---- - programs/wineboot/wineboot.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index b85a3b6b6ea..6dfc797313e 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -1035,6 +1035,7 @@ static INT_PTR CALLBACK wait_dlgproc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp - return 0; - } - -+/* - static HWND show_wait_window(void) - { - const char *config_dir = wine_get_config_dir(); -@@ -1051,6 +1052,7 @@ static HWND show_wait_window(void) - HeapFree( GetProcessHeap(), 0, name ); - return hwnd; - } -+*/ - - static HANDLE start_rundll32( const char *inf_path, BOOL wow64 ) - { -@@ -1127,7 +1129,7 @@ static void update_wineprefix( BOOL force ) - - if ((process = start_rundll32( inf_path, FALSE ))) - { -- HWND hwnd = show_wait_window(); -+/* HWND hwnd = show_wait_window();*/ - for (;;) - { - MSG msg; -@@ -1139,7 +1141,7 @@ static void update_wineprefix( BOOL force ) - } - else while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); - } -- DestroyWindow( hwnd ); -+/* DestroyWindow( hwnd );*/ - } - WINE_MESSAGE( "wine: configuration in '%s' has been updated.\n", config_dir ); - } - -From 1d06745fc4cc9353b5e8bdb48d4cb716b2a7ec85 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 7 May 2021 16:50:29 +0300 -Subject: [PATCH] wine.inf: Associate the steam protocol with steam.exe. - -For 2K Launcher. - -CW-Bug-Id: 18912 ---- - loader/wine.inf.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index a2b45b3c28f..851a31b7d05 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -330,7 +330,7 @@ HKCR,https\shell\open\ddeexec,"NoActivateHandler",2,"" - HKCR,http\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" - HKCR,https\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" - HKCR,mailto\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" --HKCR,steam\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" -+HKCR,steam\shell\open\command,,,"""%16426%\Steam\Steam.exe"" -- ""%1""" - - HKCR,MIME\Database\Charset\_iso-2022-jp$ESC,"Codepage",0x10003,932 - HKCR,MIME\Database\Charset\_iso-2022-jp$ESC,"InternetEncoding",0x10003,50221 diff --git a/patches/proton/14-proton-sdl-joy.patch b/patches/proton/14-proton-sdl-joy.patch deleted file mode 100644 index b546a7ad4..000000000 --- a/patches/proton/14-proton-sdl-joy.patch +++ /dev/null @@ -1,1002 +0,0 @@ -From 10543c51d9fb259ccc061f49d09ec6e74603e25c Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 6 Aug 2019 13:27:25 -0500 -Subject: [PATCH] winebus.sys: Disable UDEV lnxev devices by default. - -Based on a patch from Simon McVittie . ---- - dlls/winebus.sys/main.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c -index 111953c3bae..2a583871f1a 100644 ---- a/dlls/winebus.sys/main.c -+++ b/dlls/winebus.sys/main.c -@@ -742,7 +742,7 @@ static NTSTATUS udev_driver_init(void) - - bus_options.disable_hidraw = check_bus_option(L"DisableHidraw", 0); - if (bus_options.disable_hidraw) TRACE("UDEV hidraw devices disabled in registry\n"); -- bus_options.disable_input = check_bus_option(L"DisableInput", 0); -+ bus_options.disable_input = check_bus_option(L"DisableInput", 1); - if (bus_options.disable_input) TRACE("UDEV input devices disabled in registry\n"); - bus_options.disable_udevd = check_bus_option(L"DisableUdevd", 0); - if (bus_options.disable_udevd) TRACE("UDEV udevd use disabled in registry\n"); -From 22d2f82678b9babe0a315df4f311221e999e7fbc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 30 Sep 2021 15:07:25 +0200 -Subject: [PATCH] HACK: winebus.sys: Prefer devices on UDEV hidraw bus over SDL - bus. - ---- - dlls/winebus.sys/main.c | 42 ++++++++++++++++++++++++++++++++--------- - 1 file changed, 33 insertions(+), 9 deletions(-) - -diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c -index 2a583871f1a..1af7b5070f6 100644 ---- a/dlls/winebus.sys/main.c -+++ b/dlls/winebus.sys/main.c -@@ -71,6 +71,7 @@ struct device_extension - { - struct list entry; - DEVICE_OBJECT *device; -+ const WCHAR *bus_name; - - CRITICAL_SECTION cs; - enum device_state state; -@@ -284,7 +285,7 @@ static void remove_pending_irps(DEVICE_OBJECT *device) - } - } - --static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, struct unix_device *unix_device) -+static DEVICE_OBJECT *bus_create_hid_device(const WCHAR *bus_name, struct device_desc *desc, struct unix_device *unix_device) - { - struct device_extension *ext; - DEVICE_OBJECT *device; -@@ -307,6 +308,7 @@ static DEVICE_OBJECT *bus_create_hid_device(struct device_desc *desc, struct uni - - /* fill out device_extension struct */ - ext = (struct device_extension *)device->DeviceExtension; -+ ext->bus_name = bus_name; - ext->device = device; - ext->desc = *desc; - ext->index = get_device_index(desc); -@@ -333,6 +335,17 @@ static DEVICE_OBJECT *bus_find_unix_device(struct unix_device *unix_device) - return NULL; - } - -+static DEVICE_OBJECT *bus_find_device_from_vid_pid(const WCHAR *bus_name, struct device_desc *desc) -+{ -+ struct device_extension *ext; -+ -+ LIST_FOR_EACH_ENTRY(ext, &device_list, struct device_extension, entry) -+ if (!wcscmp(ext->bus_name, bus_name) && ext->desc.vid == desc->vid && -+ ext->desc.pid == desc->pid) return ext->device; -+ -+ return NULL; -+} -+ - static void bus_unlink_hid_device(DEVICE_OBJECT *device) - { - struct device_extension *ext = (struct device_extension *)device->DeviceExtension; -@@ -519,7 +532,7 @@ static void mouse_device_create(void) - struct device_create_params params = {{0}}; - - if (winebus_call(mouse_create, ¶ms)) return; -- mouse_obj = bus_create_hid_device(¶ms.desc, params.device); -+ mouse_obj = bus_create_hid_device(L"WINEBUS", ¶ms.desc, params.device); - IoInvalidateDeviceRelations(bus_pdo, BusRelations); - } - -@@ -528,7 +541,7 @@ static void keyboard_device_create(void) - struct device_create_params params = {{0}}; - - if (winebus_call(keyboard_create, ¶ms)) return; -- keyboard_obj = bus_create_hid_device(¶ms.desc, params.device); -+ keyboard_obj = bus_create_hid_device(L"WINEBUS", ¶ms.desc, params.device); - IoInvalidateDeviceRelations(bus_pdo, BusRelations); - } - -@@ -574,7 +587,20 @@ static DWORD CALLBACK bus_main_thread(void *args) - IoInvalidateDeviceRelations(bus_pdo, BusRelations); - break; - case BUS_EVENT_TYPE_DEVICE_CREATED: -- device = bus_create_hid_device(&event->device_created.desc, event->device); -+ RtlEnterCriticalSection(&device_list_cs); -+ if (!wcscmp(bus.name, L"SDL")) -+ { -+ if (bus_find_device_from_vid_pid(L"UDEV", &event->device_created.desc)) device = NULL; -+ else device = bus_create_hid_device(bus.name, &event->device_created.desc, event->device); -+ } -+ else if (!wcscmp(bus.name, L"UDEV")) -+ { -+ if ((device = bus_find_device_from_vid_pid(L"SDL", &event->device_created.desc))) -+ bus_unlink_hid_device(device); -+ device = bus_create_hid_device(bus.name, &event->device_created.desc, event->device); -+ } -+ else device = bus_create_hid_device(bus.name, &event->device_created.desc, event->device); -+ RtlLeaveCriticalSection(&device_list_cs); - if (device) IoInvalidateDeviceRelations(bus_pdo, BusRelations); - else - { -@@ -778,11 +804,9 @@ static NTSTATUS fdo_pnp_dispatch(DEVICE_OBJECT *device, IRP *irp) - mouse_device_create(); - keyboard_device_create(); - -- if (!check_bus_option(L"Enable SDL", 1) || sdl_driver_init()) -- { -- udev_driver_init(); -- iohid_driver_init(); -- } -+ udev_driver_init(); -+ iohid_driver_init(); -+ sdl_driver_init(); - - irp->IoStatus.Status = STATUS_SUCCESS; - break; -From f33bc009edb3349d6b3302cbe9de994926a3a4c3 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 6 Aug 2019 13:37:38 -0500 -Subject: [PATCH] HACK: winebus.sys: Don't use hidraw for XBox controllers. - ---- - dlls/winebus.sys/bus_udev.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c -index 2269f5b904e..334373f82e6 100644 ---- a/dlls/winebus.sys/bus_udev.c -+++ b/dlls/winebus.sys/bus_udev.c -@@ -1287,7 +1287,12 @@ static void udev_add_device(struct udev_device *dev, int fd) - } - - if (is_xbox_gamepad(desc.vid, desc.pid)) -- desc.is_gamepad = TRUE; -+ { -+ /* SDL handles xbox (and steam) controllers */ -+ TRACE("hidraw %s: ignoring %s, xbox gamepad\n", debugstr_a(devnode), debugstr_device_desc(&desc)); -+ close(fd); -+ return; -+ } - #ifdef HAS_PROPER_INPUT_HEADER - else - { -From 9d9d0ea6f5041b6f10a3ee031d2b0e72818841cb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 30 Sep 2021 15:28:03 +0200 -Subject: [PATCH] HACK: winebus.sys: Don't use hidraw for Steam controllers. - ---- - dlls/winebus.sys/bus_udev.c | 7 +++++++ - dlls/winebus.sys/unix_private.h | 1 + - dlls/winebus.sys/unixlib.c | 13 +++++++++++++ - 3 files changed, 21 insertions(+) - -diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c -index 334373f82e6..4d1124f5cc4 100644 ---- a/dlls/winebus.sys/bus_udev.c -+++ b/dlls/winebus.sys/bus_udev.c -@@ -1286,6 +1286,13 @@ static void udev_add_device(struct udev_device *dev, int fd) - memcpy(desc.serialnumber, zeros, sizeof(zeros)); - } - -+ if (is_steam_controller(desc.vid, desc.pid)) -+ { -+ /* this device is being used as a virtual Steam controller */ -+ TRACE("hidraw %s: ignoring %s, steam controller\n", debugstr_a(devnode), debugstr_device_desc(&desc)); -+ close(fd); -+ return; -+ } - if (is_xbox_gamepad(desc.vid, desc.pid)) - { - /* SDL handles xbox (and steam) controllers */ -diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h -index efecf6cdbe3..6441f987a95 100644 ---- a/dlls/winebus.sys/unix_private.h -+++ b/dlls/winebus.sys/unix_private.h -@@ -264,6 +264,7 @@ extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN; - - extern void hid_device_set_effect_state(struct unix_device *iface, BYTE index, BYTE flags) DECLSPEC_HIDDEN; - -+BOOL is_steam_controller(WORD vid, WORD pid) DECLSPEC_HIDDEN; - BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; - BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; - -diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c -index 1269ae05c2b..e88d2181446 100644 ---- a/dlls/winebus.sys/unixlib.c -+++ b/dlls/winebus.sys/unixlib.c -@@ -38,6 +38,19 @@ - - #include "unix_private.h" - -+BOOL is_steam_controller(WORD vid, WORD pid) -+{ -+ if (vid != 0x28de) return FALSE; -+ if (pid == 0x1101) return TRUE; /* Valve Legacy Steam Controller */ -+ if (pid == 0x1102) return TRUE; /* Valve wired Steam Controller */ -+ if (pid == 0x1105) return TRUE; /* Valve Bluetooth Steam Controller */ -+ if (pid == 0x1106) return TRUE; /* Valve Bluetooth Steam Controller */ -+ if (pid == 0x1142) return TRUE; /* Valve wireless Steam Controller */ -+ if (pid == 0x1201) return TRUE; /* Valve wired Steam Controller */ -+ if (pid == 0x1202) return TRUE; /* Valve Bluetooth Steam Controller */ -+ return FALSE; -+} -+ - BOOL is_xbox_gamepad(WORD vid, WORD pid) - { - if (vid != 0x045e) return FALSE; -From 1cf8f159e76931d5e4c975e1a659bf8867fa8034 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 7 Oct 2021 15:29:05 +0200 -Subject: [PATCH] HACK: winebus.sys: Ignore blacklisted SDL controllers and - joysticks. - ---- - dlls/winebus.sys/bus_sdl.c | 27 +++++++++++++++++---------- - dlls/winebus.sys/bus_udev.c | 7 +++++++ - dlls/winebus.sys/unix_private.h | 1 + - dlls/winebus.sys/unixlib.c | 18 ++++++++++++++++++ - 4 files changed, 43 insertions(+), 10 deletions(-) - -diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c -index 37d75d0bc95..7dfa8edb3b5 100644 ---- a/dlls/winebus.sys/bus_sdl.c -+++ b/dlls/winebus.sys/bus_sdl.c -@@ -862,16 +862,8 @@ static void sdl_add_device(unsigned int index) - return; - } - -- if (options.map_controllers && pSDL_IsGameController(index)) -- controller = pSDL_GameControllerOpen(index); -- -- if (controller) str = pSDL_GameControllerName(controller); -- else str = pSDL_JoystickName(joystick); -- if (str) ntdll_umbstowcs(str, strlen(str) + 1, desc.product, ARRAY_SIZE(desc.product)); -- -- id = pSDL_JoystickInstanceID(joystick); -- -- if (pSDL_JoystickGetProductVersion != NULL) { -+ if (pSDL_JoystickGetProductVersion != NULL) -+ { - desc.vid = pSDL_JoystickGetVendor(joystick); - desc.pid = pSDL_JoystickGetProduct(joystick); - desc.version = pSDL_JoystickGetProductVersion(joystick); -@@ -883,6 +875,21 @@ static void sdl_add_device(unsigned int index) - desc.version = 0; - } - -+ if (is_sdl_blacklisted(desc.vid, desc.pid)) -+ { -+ /* this device is blacklisted */ -+ TRACE("ignoring %s, in SDL blacklist\n", debugstr_device_desc(&desc)); -+ return; -+ } -+ -+ if (options.map_controllers && pSDL_IsGameController(index)) -+ controller = pSDL_GameControllerOpen(index); -+ -+ if (controller) str = pSDL_GameControllerName(controller); -+ else str = pSDL_JoystickName(joystick); -+ if (str) ntdll_umbstowcs(str, strlen(str) + 1, desc.product, ARRAY_SIZE(desc.product)); -+ -+ id = pSDL_JoystickInstanceID(joystick); - guid = pSDL_JoystickGetGUID(joystick); - pSDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); - ntdll_umbstowcs(guid_str, strlen(guid_str) + 1, desc.serialnumber, ARRAY_SIZE(desc.serialnumber)); -diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c -index 4d1124f5cc4..3a525b235c6 100644 ---- a/dlls/winebus.sys/bus_udev.c -+++ b/dlls/winebus.sys/bus_udev.c -@@ -1286,6 +1286,13 @@ static void udev_add_device(struct udev_device *dev, int fd) - memcpy(desc.serialnumber, zeros, sizeof(zeros)); - } - -+ if (is_sdl_blacklisted(desc.vid, desc.pid)) -+ { -+ /* this device is blacklisted */ -+ TRACE("hidraw %s: ignoring %s, in SDL blacklist\n", debugstr_a(devnode), debugstr_device_desc(&desc)); -+ close(fd); -+ return; -+ } - if (is_steam_controller(desc.vid, desc.pid)) - { - /* this device is being used as a virtual Steam controller */ -diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h -index 6441f987a95..02c9ff947c4 100644 ---- a/dlls/winebus.sys/unix_private.h -+++ b/dlls/winebus.sys/unix_private.h -@@ -264,6 +264,7 @@ extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN; - - extern void hid_device_set_effect_state(struct unix_device *iface, BYTE index, BYTE flags) DECLSPEC_HIDDEN; - -+BOOL is_sdl_blacklisted(DWORD vid, DWORD pid) DECLSPEC_HIDDEN; - BOOL is_steam_controller(WORD vid, WORD pid) DECLSPEC_HIDDEN; - BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; - BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; -diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c -index e88d2181446..8cff984ac20 100644 ---- a/dlls/winebus.sys/unixlib.c -+++ b/dlls/winebus.sys/unixlib.c -@@ -38,6 +38,24 @@ - - #include "unix_private.h" - -+/* logic from SDL2's SDL_ShouldIgnoreGameController */ -+BOOL is_sdl_blacklisted(DWORD vid, DWORD pid) -+{ -+ const char *allow_virtual = getenv("SDL_GAMECONTROLLER_ALLOW_STEAM_VIRTUAL_GAMEPAD"); -+ const char *whitelist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT"); -+ const char *blacklist = getenv("SDL_GAMECONTROLLER_IGNORE_DEVICES"); -+ char needle[16]; -+ -+ if (vid == 0x28de && pid == 0x11ff && allow_virtual && *allow_virtual && -+ *allow_virtual != '0' && strcasecmp(allow_virtual, "false")) -+ return FALSE; -+ -+ sprintf(needle, "0x%04x/0x%04x", vid, pid); -+ if (whitelist) return strcasestr(whitelist, needle) == NULL; -+ if (blacklist) return strcasestr(blacklist, needle) != NULL; -+ return FALSE; -+} -+ - BOOL is_steam_controller(WORD vid, WORD pid) - { - if (vid != 0x28de) return FALSE; -From 7ea1cc2581b35b6d630d0399a0e230b3f57a2014 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 30 Aug 2019 10:20:16 -0500 -Subject: [PATCH] HACK: winebus.sys: Override Steam virtual controller vid/pid - with Xbox. - -Matches Windows Steam client behavior. ---- - dlls/winebus.sys/bus_sdl.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c -index 7dfa8edb3b5..079a615333e 100644 ---- a/dlls/winebus.sys/bus_sdl.c -+++ b/dlls/winebus.sys/bus_sdl.c -@@ -882,6 +882,13 @@ static void sdl_add_device(unsigned int index) - return; - } - -+ if (desc.vid == 0x28de && desc.pid == 0x11ff) -+ { -+ TRACE("Steam virtual controller, pretending it's an Xbox 360 controller\n"); -+ desc.vid = 0x045e; -+ desc.pid = 0x028e; -+ } -+ - if (options.map_controllers && pSDL_IsGameController(index)) - controller = pSDL_GameControllerOpen(index); - -From e62a27bb284c4a7364d69fb09ae4df18c8860185 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 30 Sep 2021 20:38:04 +0200 -Subject: [PATCH] winebus.sys: Ignore some joysticks that SDL reports. - -SDL has a blacklist, but it isn't complete. Ignore some more devices -while we fix upstream. ---- - dlls/winebus.sys/bus_sdl.c | 7 +++++++ - dlls/winebus.sys/unix_private.h | 1 + - dlls/winebus.sys/unixlib.c | 14 ++++++++++++++ - include/wine/js_blacklist.h | 3 +++ - 4 files changed, 25 insertions(+) - create mode 100644 include/wine/js_blacklist.h - -diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c -index 079a615333e..84c8721270c 100644 ---- a/dlls/winebus.sys/bus_sdl.c -+++ b/dlls/winebus.sys/bus_sdl.c -@@ -882,6 +882,13 @@ static void sdl_add_device(unsigned int index) - return; - } - -+ if (is_wine_blacklisted(desc.vid, desc.pid)) -+ { -+ /* this device is blacklisted */ -+ TRACE("ignoring %s, in Wine blacklist\n", debugstr_device_desc(&desc)); -+ return; -+ } -+ - if (desc.vid == 0x28de && desc.pid == 0x11ff) - { - TRACE("Steam virtual controller, pretending it's an Xbox 360 controller\n"); -diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h -index 02c9ff947c4..a204eacb3bf 100644 ---- a/dlls/winebus.sys/unix_private.h -+++ b/dlls/winebus.sys/unix_private.h -@@ -265,6 +265,7 @@ extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN; - extern void hid_device_set_effect_state(struct unix_device *iface, BYTE index, BYTE flags) DECLSPEC_HIDDEN; - - BOOL is_sdl_blacklisted(DWORD vid, DWORD pid) DECLSPEC_HIDDEN; -+BOOL is_wine_blacklisted(DWORD vid, DWORD pid) DECLSPEC_HIDDEN; - BOOL is_steam_controller(WORD vid, WORD pid) DECLSPEC_HIDDEN; - BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; - BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; -diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c -index 8cff984ac20..ae742b0cba4 100644 ---- a/dlls/winebus.sys/unixlib.c -+++ b/dlls/winebus.sys/unixlib.c -@@ -35,9 +35,23 @@ - #include "wine/debug.h" - #include "wine/list.h" - #include "wine/unixlib.h" -+#include "wine/js_blacklist.h" /* for wine_js_blacklist */ - - #include "unix_private.h" - -+BOOL is_wine_blacklisted(DWORD vid, DWORD pid) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(wine_js_blacklist); ++i) -+ { -+ if (vid != wine_js_blacklist[i].vid) continue; -+ if (!wine_js_blacklist[i].pid || wine_js_blacklist[i].pid == pid) return TRUE; -+ } -+ -+ return FALSE; -+} -+ - /* logic from SDL2's SDL_ShouldIgnoreGameController */ - BOOL is_sdl_blacklisted(DWORD vid, DWORD pid) - { -diff --git a/include/wine/js_blacklist.h b/include/wine/js_blacklist.h -new file mode 100644 -index 00000000000..b8f2ec7dd28 ---- /dev/null -+++ b/include/wine/js_blacklist.h -@@ -0,0 +1,3 @@ -+static const struct { short vid; short pid; } wine_js_blacklist[] = { -+ {0x056a, 0x0000}, /* all Wacom devices */ -+}; -From 62f3031decd2500dbfc48c767cc662e812c1cf78 Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Tue, 10 Nov 2020 18:32:28 +0000 -Subject: [PATCH] winebus.sys: Automatically bypass udevd in Flatpak or - pressure-vessel. - -Flatpak uses unprivileged containers that don't normally map uid 0 -into the container, so netlink events won't work there, as described -in previous commits. Steam's pressure-vessel container tool behaves -similarly. ---- - dlls/winebus.sys/bus_udev.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c -index 3a525b235c6..5d8d2384e69 100644 ---- a/dlls/winebus.sys/bus_udev.c -+++ b/dlls/winebus.sys/bus_udev.c -@@ -1708,6 +1708,12 @@ NTSTATUS udev_bus_init(void *args) - goto error; - } - -+ if (access("/run/pressure-vessel", R_OK) || access("/.flatpak-info", R_OK)) -+ { -+ TRACE("Container detected, bypassing udevd by default\n"); -+ options.disable_udevd = TRUE; -+ } -+ - #if HAVE_SYS_INOTIFY_H - if (options.disable_udevd) monitor_fd = create_inotify(); - if (monitor_fd < 0) options.disable_udevd = FALSE; -From dd54394cee8090d2ef55c0da2ecde7a724c6a8c6 Mon Sep 17 00:00:00 2001 -From: Simon McVittie -Date: Tue, 10 Nov 2020 19:03:47 +0000 -Subject: [PATCH] winebus.sys: Guess the type of evdev input devices. - -Ordinarily, we can get the type of an evdev input device from udev: -the input_id builtin sets udev properties of the form ID_INPUT_FOO -that we can read. - -However, in a container there is no guarantee that the libudev in the -container will interoperate with the udevd on the host system, so we -need to be prepared to do this ourselves from first principles, using -a heuristic similar to the one in udev's input_id. - -We cannot simply copy the heuristic from udev's input_id, because its -licensing is incompatible (GPL). Instead, use a vaguely similar heuristic -that works from the same inputs and will generally produce similar results. ---- - dlls/winebus.sys/bus_udev.c | 330 +++++++++++++++++++++++++++++++++++- - 1 file changed, 328 insertions(+), 2 deletions(-) - -diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c -index 5d8d2384e69..4592b095ff5 100644 ---- a/dlls/winebus.sys/bus_udev.c -+++ b/dlls/winebus.sys/bus_udev.c -@@ -25,6 +25,7 @@ - #include "config.h" - #include - #include -+#include - #include - #include - #include -@@ -500,7 +501,303 @@ static struct base_device *find_device_from_syspath(const char *path) - - #define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7))) - --static const BYTE* what_am_I(struct udev_device *dev) -+/* Minimal compatibility with code taken from steam-runtime-tools */ -+typedef int gboolean; -+#define g_debug(fmt, ...) TRACE(fmt "\n", ## __VA_ARGS__) -+#define G_N_ELEMENTS(arr) (sizeof(arr)/sizeof(arr[0])) -+ -+typedef enum -+{ -+ SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK = (1 << 0), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER = (1 << 1), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD = (1 << 2), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS = (1 << 3), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE = (1 << 4), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD = (1 << 5), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN = (1 << 6), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET = (1 << 7), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET_PAD = (1 << 8), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK = (1 << 9), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_SWITCH = (1 << 10), -+ SRT_INPUT_DEVICE_TYPE_FLAGS_NONE = 0 -+} SrtInputDeviceTypeFlags; -+ -+#define BITS_PER_LONG (sizeof (unsigned long) * CHAR_BIT) -+#define LONGS_FOR_BITS(x) ((((x)-1)/BITS_PER_LONG)+1) -+typedef struct -+{ -+ unsigned long ev[LONGS_FOR_BITS (EV_MAX)]; -+ unsigned long keys[LONGS_FOR_BITS (KEY_MAX)]; -+ unsigned long abs[LONGS_FOR_BITS (ABS_MAX)]; -+ unsigned long rel[LONGS_FOR_BITS (REL_MAX)]; -+ unsigned long ff[LONGS_FOR_BITS (FF_MAX)]; -+ unsigned long props[LONGS_FOR_BITS (INPUT_PROP_MAX)]; -+} SrtEvdevCapabilities; -+ -+static gboolean -+_srt_get_caps_from_evdev (int fd, -+ unsigned int type, -+ unsigned long *bitmask, -+ size_t bitmask_len_longs) -+{ -+ size_t bitmask_len_bytes = bitmask_len_longs * sizeof (*bitmask); -+ -+ memset (bitmask, 0, bitmask_len_bytes); -+ -+ if (ioctl (fd, EVIOCGBIT (type, bitmask_len_bytes), bitmask) < 0) -+ return FALSE; -+ -+ return TRUE; -+} -+ -+static gboolean -+_srt_evdev_capabilities_set_from_evdev (SrtEvdevCapabilities *caps, -+ int fd) -+{ -+ if (_srt_get_caps_from_evdev (fd, 0, caps->ev, G_N_ELEMENTS (caps->ev))) -+ { -+ _srt_get_caps_from_evdev (fd, EV_KEY, caps->keys, G_N_ELEMENTS (caps->keys)); -+ _srt_get_caps_from_evdev (fd, EV_ABS, caps->abs, G_N_ELEMENTS (caps->abs)); -+ _srt_get_caps_from_evdev (fd, EV_REL, caps->rel, G_N_ELEMENTS (caps->rel)); -+ _srt_get_caps_from_evdev (fd, EV_FF, caps->ff, G_N_ELEMENTS (caps->ff)); -+ ioctl (fd, EVIOCGPROP (sizeof (caps->props)), caps->props); -+ return TRUE; -+ } -+ -+ memset (caps, 0, sizeof (*caps)); -+ return FALSE; -+} -+ -+#define JOYSTICK_ABS_AXES \ -+ ((1 << ABS_X) | (1 << ABS_Y) \ -+ | (1 << ABS_RX) | (1 << ABS_RY) \ -+ | (1 << ABS_THROTTLE) | (1 << ABS_RUDDER) \ -+ | (1 << ABS_WHEEL) | (1 << ABS_GAS) | (1 << ABS_BRAKE) \ -+ | (1 << ABS_HAT0X) | (1 << ABS_HAT0Y) \ -+ | (1 << ABS_HAT1X) | (1 << ABS_HAT1Y) \ -+ | (1 << ABS_HAT2X) | (1 << ABS_HAT2Y) \ -+ | (1 << ABS_HAT3X) | (1 << ABS_HAT3Y)) -+ -+static const unsigned int first_mouse_button = BTN_MOUSE; -+static const unsigned int last_mouse_button = BTN_JOYSTICK - 1; -+ -+static const unsigned int first_joystick_button = BTN_JOYSTICK; -+static const unsigned int last_joystick_button = BTN_GAMEPAD - 1; -+ -+static const unsigned int first_gamepad_button = BTN_GAMEPAD; -+static const unsigned int last_gamepad_button = BTN_DIGI - 1; -+ -+static const unsigned int first_dpad_button = BTN_DPAD_UP; -+static const unsigned int last_dpad_button = BTN_DPAD_RIGHT; -+ -+static const unsigned int first_extra_joystick_button = BTN_TRIGGER_HAPPY; -+static const unsigned int last_extra_joystick_button = BTN_TRIGGER_HAPPY40; -+ -+SrtInputDeviceTypeFlags -+_srt_evdev_capabilities_guess_type (const SrtEvdevCapabilities *caps) -+{ -+ SrtInputDeviceTypeFlags flags = SRT_INPUT_DEVICE_TYPE_FLAGS_NONE; -+ unsigned int i; -+ gboolean has_joystick_axes = FALSE; -+ gboolean has_joystick_buttons = FALSE; -+ -+ /* Some properties let us be fairly sure about a device */ -+ if (test_bit (caps->props, INPUT_PROP_ACCELEROMETER)) -+ { -+ g_debug ("INPUT_PROP_ACCELEROMETER => is accelerometer"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; -+ } -+ -+ if (test_bit (caps->props, INPUT_PROP_POINTING_STICK)) -+ { -+ g_debug ("INPUT_PROP_POINTING_STICK => is pointing stick"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK; -+ } -+ -+ if (test_bit (caps->props, INPUT_PROP_BUTTONPAD) -+ || test_bit (caps->props, INPUT_PROP_TOPBUTTONPAD)) -+ { -+ g_debug ("INPUT_PROP_[TOP]BUTTONPAD => is touchpad"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD; -+ } -+ -+ /* Devices with a stylus or pen are assumed to be graphics tablets */ -+ if (test_bit (caps->keys, BTN_STYLUS) -+ || test_bit (caps->keys, BTN_TOOL_PEN)) -+ { -+ g_debug ("Stylus or pen => is tablet"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET; -+ } -+ -+ /* Devices that accept a finger touch are assumed to be touchpads or -+ * touchscreens. -+ * -+ * In Steam we mostly only care about these as a way to -+ * reject non-joysticks, so we're not very precise here yet. -+ * -+ * SDL assumes that TOUCH means a touchscreen and FINGER -+ * means a touchpad. */ -+ if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE -+ && (test_bit (caps->keys, BTN_TOOL_FINGER) -+ || test_bit (caps->keys, BTN_TOUCH) -+ || test_bit (caps->props, INPUT_PROP_SEMI_MT))) -+ { -+ g_debug ("Finger or touch or semi-MT => is touchpad or touchscreen"); -+ -+ if (test_bit (caps->props, INPUT_PROP_POINTER)) -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD; -+ else -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN; -+ } -+ -+ /* Devices with mouse buttons are ... probably mice? */ -+ if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE) -+ { -+ for (i = first_mouse_button; i <= last_mouse_button; i++) -+ { -+ if (test_bit (caps->keys, i)) -+ { -+ g_debug ("Mouse button => mouse"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE; -+ } -+ } -+ } -+ -+ if (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE) -+ { -+ for (i = ABS_X; i < ABS_Z; i++) -+ { -+ if (!test_bit (caps->abs, i)) -+ break; -+ } -+ -+ /* If it has 3 axes and no buttons it's probably an accelerometer. */ -+ if (i == ABS_Z && !test_bit (caps->ev, EV_KEY)) -+ { -+ g_debug ("3 left axes and no buttons => accelerometer"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; -+ } -+ -+ /* Same for RX..RZ (e.g. Wiimote) */ -+ for (i = ABS_RX; i < ABS_RZ; i++) -+ { -+ if (!test_bit (caps->abs, i)) -+ break; -+ } -+ -+ if (i == ABS_RZ && !test_bit (caps->ev, EV_KEY)) -+ { -+ g_debug ("3 right axes and no buttons => accelerometer"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_ACCELEROMETER; -+ } -+ } -+ -+ /* Bits 1 to 31 are ESC, numbers and Q to D, which SDL and udev both -+ * consider to be enough to count as a fully-functioned keyboard. */ -+ if ((caps->keys[0] & 0xfffffffe) == 0xfffffffe) -+ { -+ g_debug ("First few keys => keyboard"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD; -+ } -+ -+ /* If we have *any* keys, consider it to be something a bit -+ * keyboard-like. Bits 0 to 63 are all keyboard keys. -+ * Make sure we stop before reaching KEY_UP which is sometimes -+ * used on game controller mappings, e.g. for the Wiimote. */ -+ for (i = 0; i < (64 / BITS_PER_LONG); i++) -+ { -+ if (caps->keys[i] != 0) -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS; -+ } -+ -+ if (caps->abs[0] & JOYSTICK_ABS_AXES) -+ has_joystick_axes = TRUE; -+ -+ /* Flight stick buttons */ -+ for (i = first_joystick_button; i <= last_joystick_button; i++) -+ { -+ if (test_bit (caps->keys, i)) -+ has_joystick_buttons = TRUE; -+ } -+ -+ /* Gamepad buttons (Xbox, PS3, etc.) */ -+ for (i = first_gamepad_button; i <= last_gamepad_button; i++) -+ { -+ if (test_bit (caps->keys, i)) -+ has_joystick_buttons = TRUE; -+ } -+ -+ /* Gamepad digital dpad */ -+ for (i = first_dpad_button; i <= last_dpad_button; i++) -+ { -+ if (test_bit (caps->keys, i)) -+ has_joystick_buttons = TRUE; -+ } -+ -+ /* Steering wheel gear-change buttons */ -+ for (i = BTN_GEAR_DOWN; i <= BTN_GEAR_UP; i++) -+ { -+ if (test_bit (caps->keys, i)) -+ has_joystick_buttons = TRUE; -+ } -+ -+ /* Reserved space for extra game-controller buttons, e.g. on Corsair -+ * gaming keyboards */ -+ for (i = first_extra_joystick_button; i <= last_extra_joystick_button; i++) -+ { -+ if (test_bit (caps->keys, i)) -+ has_joystick_buttons = TRUE; -+ } -+ -+ if (test_bit (caps->keys, last_mouse_button)) -+ { -+ /* Mice with a very large number of buttons can apparently -+ * overflow into the joystick-button space, but they're still not -+ * joysticks. */ -+ has_joystick_buttons = FALSE; -+ } -+ -+ /* TODO: Do we want to consider BTN_0 up to BTN_9 to be joystick buttons? -+ * libmanette and SDL look for BTN_1, udev does not. -+ * -+ * They're used by some game controllers, like BTN_1 and BTN_2 for the -+ * Wiimote, BTN_1..BTN_9 for the SpaceTec SpaceBall and BTN_0..BTN_3 -+ * for Playstation dance pads, but they're also used by -+ * non-game-controllers like Logitech mice. For now we entirely ignore -+ * these buttons: they are not evidence that it's a joystick, but -+ * neither are they evidence that it *isn't* a joystick. */ -+ -+ /* We consider it to be a joystick if there is some evidence that it is, -+ * and no evidence that it's something else. -+ * -+ * Unlike SDL, we accept devices with only axes and no buttons as a -+ * possible joystick, unless they have X/Y/Z axes in which case we -+ * assume they're accelerometers. */ -+ if ((has_joystick_buttons || has_joystick_axes) -+ && (flags == SRT_INPUT_DEVICE_TYPE_FLAGS_NONE)) -+ { -+ g_debug ("Looks like a joystick"); -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK; -+ } -+ -+ /* If we have *any* keys below BTN_MISC, consider it to be something -+ * a bit keyboard-like, but don't rule out *also* being considered -+ * to be a joystick (again for e.g. the Wiimote). */ -+ for (i = 0; i < (BTN_MISC / BITS_PER_LONG); i++) -+ { -+ if (caps->keys[i] != 0) -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS; -+ } -+ -+ /* Also non-exclusive: don't rule out a device being a joystick and -+ * having a switch */ -+ if (test_bit (caps->ev, EV_SW)) -+ flags |= SRT_INPUT_DEVICE_TYPE_FLAGS_SWITCH; -+ -+ return flags; -+} -+ -+static const BYTE* what_am_I(struct udev_device *dev, int fd) - { - static const BYTE Unknown[2] = {HID_USAGE_PAGE_GENERIC, 0}; - static const BYTE Mouse[2] = {HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_MOUSE}; -@@ -510,6 +807,7 @@ static const BYTE* what_am_I(struct udev_device *dev) - static const BYTE Tablet[2] = {HID_USAGE_PAGE_DIGITIZER, HID_USAGE_DIGITIZER_PEN}; - static const BYTE Touchscreen[2] = {HID_USAGE_PAGE_DIGITIZER, HID_USAGE_DIGITIZER_TOUCH_SCREEN}; - static const BYTE Touchpad[2] = {HID_USAGE_PAGE_DIGITIZER, HID_USAGE_DIGITIZER_TOUCH_PAD}; -+ SrtEvdevCapabilities caps; - - struct udev_device *parent = dev; - -@@ -533,6 +831,34 @@ static const BYTE* what_am_I(struct udev_device *dev) - - parent = udev_device_get_parent_with_subsystem_devtype(parent, "input", NULL); - } -+ -+ /* In a container, udev properties might not be available. Fall back to deriving the device -+ * type from the fd's evdev capabilities. */ -+ if (_srt_evdev_capabilities_set_from_evdev (&caps, fd)) -+ { -+ SrtInputDeviceTypeFlags guessed_type; -+ -+ guessed_type = _srt_evdev_capabilities_guess_type (&caps); -+ -+ if (guessed_type & (SRT_INPUT_DEVICE_TYPE_FLAGS_MOUSE -+ | SRT_INPUT_DEVICE_TYPE_FLAGS_POINTING_STICK)) -+ return Mouse; -+ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_KEYBOARD) -+ return Keyboard; -+ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_JOYSTICK) -+ return Gamepad; -+ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_HAS_KEYS) -+ return Keypad; -+ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHPAD) -+ return Touchpad; -+ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TOUCHSCREEN) -+ return Touchscreen; -+ else if (guessed_type & SRT_INPUT_DEVICE_TYPE_FLAGS_TABLET) -+ return Tablet; -+ -+ /* Mapped to Unknown: ACCELEROMETER, TABLET_PAD, SWITCH. */ -+ } -+ - return Unknown; - } - -@@ -587,8 +913,8 @@ static NTSTATUS build_report_descriptor(struct unix_device *iface, struct udev_d - USHORT count = 0; - USAGE usages[16]; - INT i, button_count, abs_count, rel_count, hat_count; -- const BYTE *device_usage = what_am_I(dev); - struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); -+ const BYTE *device_usage = what_am_I(dev, impl->base.device_fd); - - if (ioctl(impl->base.device_fd, EVIOCGBIT(EV_REL, sizeof(relbits)), relbits) == -1) - { -From e62a27bb284c4a7364d69fb09ae4df18c8860185 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 30 Sep 2021 20:38:04 +0200 -Subject: [PATCH] winebus.sys: Ignore some joysticks that SDL reports. - -SDL has a blacklist, but it isn't complete. Ignore some more devices -while we fix upstream. ---- - dlls/winebus.sys/bus_sdl.c | 7 +++++++ - dlls/winebus.sys/unix_private.h | 1 + - dlls/winebus.sys/unixlib.c | 14 ++++++++++++++ - include/wine/js_blacklist.h | 3 +++ - 4 files changed, 25 insertions(+) - create mode 100644 include/wine/js_blacklist.h - -diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c -index 079a615333e..84c8721270c 100644 ---- a/dlls/winebus.sys/bus_sdl.c -+++ b/dlls/winebus.sys/bus_sdl.c -@@ -882,6 +882,13 @@ static void sdl_add_device(unsigned int index) - return; - } - -+ if (is_wine_blacklisted(desc.vid, desc.pid)) -+ { -+ /* this device is blacklisted */ -+ TRACE("ignoring %s, in Wine blacklist\n", debugstr_device_desc(&desc)); -+ return; -+ } -+ - if (desc.vid == 0x28de && desc.pid == 0x11ff) - { - TRACE("Steam virtual controller, pretending it's an Xbox 360 controller\n"); -diff --git a/dlls/winebus.sys/unix_private.h b/dlls/winebus.sys/unix_private.h -index 02c9ff947c4..a204eacb3bf 100644 ---- a/dlls/winebus.sys/unix_private.h -+++ b/dlls/winebus.sys/unix_private.h -@@ -265,6 +265,7 @@ extern void hid_device_drop_report(struct unix_device *iface) DECLSPEC_HIDDEN; - extern void hid_device_set_effect_state(struct unix_device *iface, BYTE index, BYTE flags) DECLSPEC_HIDDEN; - - BOOL is_sdl_blacklisted(DWORD vid, DWORD pid) DECLSPEC_HIDDEN; -+BOOL is_wine_blacklisted(DWORD vid, DWORD pid) DECLSPEC_HIDDEN; - BOOL is_steam_controller(WORD vid, WORD pid) DECLSPEC_HIDDEN; - BOOL is_xbox_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; - BOOL is_dualshock4_gamepad(WORD vid, WORD pid) DECLSPEC_HIDDEN; -diff --git a/dlls/winebus.sys/unixlib.c b/dlls/winebus.sys/unixlib.c -index 8cff984ac20..ae742b0cba4 100644 ---- a/dlls/winebus.sys/unixlib.c -+++ b/dlls/winebus.sys/unixlib.c -@@ -35,9 +35,23 @@ - #include "wine/debug.h" - #include "wine/list.h" - #include "wine/unixlib.h" -+#include "wine/js_blacklist.h" /* for wine_js_blacklist */ - - #include "unix_private.h" - -+BOOL is_wine_blacklisted(DWORD vid, DWORD pid) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(wine_js_blacklist); ++i) -+ { -+ if (vid != wine_js_blacklist[i].vid) continue; -+ if (!wine_js_blacklist[i].pid || wine_js_blacklist[i].pid == pid) return TRUE; -+ } -+ -+ return FALSE; -+} -+ - /* logic from SDL2's SDL_ShouldIgnoreGameController */ - BOOL is_sdl_blacklisted(DWORD vid, DWORD pid) - { -diff --git a/include/wine/js_blacklist.h b/include/wine/js_blacklist.h -new file mode 100644 -index 00000000000..b8f2ec7dd28 ---- /dev/null -+++ b/include/wine/js_blacklist.h -@@ -0,0 +1,3 @@ -+static const struct { short vid; short pid; } wine_js_blacklist[] = { -+ {0x056a, 0x0000}, /* all Wacom devices */ -+}; - -From 7926577b40f525e5c4081328e8c2f1dd113ef13b Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 15 Dec 2020 12:23:31 -0600 -Subject: [PATCH] winebus.sys: Enable SDL input logging when hid channel is - enabled. - ---- - dlls/winebus.sys/bus_sdl.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c -index 84c8721270c..42bee61f0f0 100644 ---- a/dlls/winebus.sys/bus_sdl.c -+++ b/dlls/winebus.sys/bus_sdl.c -@@ -112,6 +112,7 @@ MAKE_FUNCPTR(SDL_GameControllerAddMapping); - MAKE_FUNCPTR(SDL_RegisterEvents); - MAKE_FUNCPTR(SDL_PushEvent); - MAKE_FUNCPTR(SDL_GetTicks); -+MAKE_FUNCPTR(SDL_LogSetPriority); - static int (*pSDL_JoystickRumble)(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms); - static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick); - static Uint16 (*pSDL_JoystickGetProductVersion)(SDL_Joystick * joystick); -@@ -1029,6 +1030,7 @@ NTSTATUS sdl_bus_init(void *args) - LOAD_FUNCPTR(SDL_RegisterEvents); - LOAD_FUNCPTR(SDL_PushEvent); - LOAD_FUNCPTR(SDL_GetTicks); -+ LOAD_FUNCPTR(SDL_LogSetPriority); - #undef LOAD_FUNCPTR - pSDL_JoystickRumble = dlsym(sdl_handle, "SDL_JoystickRumble"); - pSDL_JoystickGetProduct = dlsym(sdl_handle, "SDL_JoystickGetProduct"); -@@ -1047,6 +1049,11 @@ NTSTATUS sdl_bus_init(void *args) - goto failed; - } - -+ if (TRACE_ON(hid)) -+ { -+ pSDL_LogSetPriority(SDL_LOG_CATEGORY_INPUT, SDL_LOG_PRIORITY_VERBOSE); -+ } -+ - pSDL_JoystickEventState(SDL_ENABLE); - pSDL_GameControllerEventState(SDL_ENABLE); - diff --git a/patches/proton/15-proton-gamepad-additions.patch b/patches/proton/15-proton-gamepad-additions.patch deleted file mode 100644 index 1b8d03623..000000000 --- a/patches/proton/15-proton-gamepad-additions.patch +++ /dev/null @@ -1,1335 +0,0 @@ -From cf3783be65fe36469de4a73d1db5b5db383e9f65 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 6 Nov 2020 12:20:16 -0600 -Subject: [PATCH] Revert "winex11.drv: Interpret mouse 6/7 as horiz scroll." - -This reverts commit 893080e4df5a45929320ebb88b8668eea316476c. - -We have a trade-off here between supporting horizontal scroll, or -mapping those actions to the XBUTTON{1,2} messages. Some users were -using those buttons in their games, which broke with this change. It -seems more likely that the extra button mapping will be useful than -horizontal scrolling, so let's revert this commit. ---- - dlls/winex11.drv/mouse.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 51a6828f10c..7029983b92d 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -75,8 +75,8 @@ static const UINT button_down_flags[NB_BUTTONS] = - MOUSEEVENTF_RIGHTDOWN, - MOUSEEVENTF_WHEEL, - MOUSEEVENTF_WHEEL, -- MOUSEEVENTF_HWHEEL, -- MOUSEEVENTF_HWHEEL, -+ MOUSEEVENTF_XDOWN, /* FIXME: horizontal wheel */ -+ MOUSEEVENTF_XDOWN, - MOUSEEVENTF_XDOWN, - MOUSEEVENTF_XDOWN - }; -@@ -88,8 +88,8 @@ static const UINT button_up_flags[NB_BUTTONS] = - MOUSEEVENTF_RIGHTUP, - 0, - 0, -- 0, -- 0, -+ MOUSEEVENTF_XUP, -+ MOUSEEVENTF_XUP, - MOUSEEVENTF_XUP, - MOUSEEVENTF_XUP - }; -@@ -101,8 +101,8 @@ static const UINT button_down_data[NB_BUTTONS] = - 0, - WHEEL_DELTA, - -WHEEL_DELTA, -- -WHEEL_DELTA, -- WHEEL_DELTA, -+ XBUTTON1, -+ XBUTTON2, - XBUTTON1, - XBUTTON2 - }; -@@ -114,8 +114,8 @@ static const UINT button_up_data[NB_BUTTONS] = - 0, - 0, - 0, -- 0, -- 0, -+ XBUTTON1, -+ XBUTTON2, - XBUTTON1, - XBUTTON2 - }; -From cf051b76ba4972b7383f074fa1d127c5c3c03946 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 17 Jan 2020 12:45:32 +0100 -Subject: [PATCH] winex11.drv: Rename EVENT_x11_time_to_win32_time to - x11drv_time_to_ticks. - ---- - dlls/winex11.drv/event.c | 8 ++++---- - dlls/winex11.drv/keyboard.c | 2 +- - dlls/winex11.drv/mouse.c | 10 +++++----- - dlls/winex11.drv/wintab.c | 6 +++--- - dlls/winex11.drv/x11drv.h | 2 +- - 5 files changed, 14 insertions(+), 14 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 170111e9c28..24b0a3da2f2 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -503,12 +503,12 @@ DWORD CDECL X11DRV_MsgWaitForMultipleObjectsEx( DWORD count, const HANDLE *handl - } - - /*********************************************************************** -- * EVENT_x11_time_to_win32_time -+ * x11drv_time_to_ticks - * - * Make our timer and the X timer line up as best we can - * Pass 0 to retrieve the current adjustment value (times -1) - */ --DWORD EVENT_x11_time_to_win32_time(Time time) -+DWORD x11drv_time_to_ticks( Time time ) - { - static DWORD adjust = 0; - DWORD now = GetTickCount(); -@@ -569,10 +569,10 @@ static void set_input_focus( struct x11drv_win_data *data ) - - if (!data->whole_window) return; - -- if (EVENT_x11_time_to_win32_time(0)) -+ if (x11drv_time_to_ticks(0)) - /* ICCCM says don't use CurrentTime, so try to use last message time if possible */ - /* FIXME: this is not entirely correct */ -- timestamp = GetMessageTime() - EVENT_x11_time_to_win32_time(0); -+ timestamp = GetMessageTime() - x11drv_time_to_ticks(0); - else - timestamp = CurrentTime; - -diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c -index c6eab6f5cfa..e70e1254c9e 100644 ---- a/dlls/winex11.drv/keyboard.c -+++ b/dlls/winex11.drv/keyboard.c -@@ -1330,7 +1330,7 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) - DWORD dwFlags; - int ascii_chars; - XIC xic = X11DRV_get_ic( hwnd ); -- DWORD event_time = EVENT_x11_time_to_win32_time(event->time); -+ DWORD event_time = x11drv_time_to_ticks( event->time ); - Status status = 0; - - TRACE_(key)("type %d, window %lx, state 0x%04x, keycode %u\n", -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 7029983b92d..b053aba973c 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -1704,7 +1704,7 @@ BOOL X11DRV_ButtonPress( HWND hwnd, XEvent *xev ) - input.u.mi.dy = event->y; - input.u.mi.mouseData = button_down_data[buttonNum]; - input.u.mi.dwFlags = button_down_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; -- input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); -+ input.u.mi.time = x11drv_time_to_ticks( event->time ); - input.u.mi.dwExtraInfo = 0; - - update_user_time( event->time ); -@@ -1731,7 +1731,7 @@ BOOL X11DRV_ButtonRelease( HWND hwnd, XEvent *xev ) - input.u.mi.dy = event->y; - input.u.mi.mouseData = button_up_data[buttonNum]; - input.u.mi.dwFlags = button_up_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; -- input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); -+ input.u.mi.time = x11drv_time_to_ticks( event->time ); - input.u.mi.dwExtraInfo = 0; - - map_event_coords( hwnd, event->window, event->root, event->x_root, event->y_root, &input ); -@@ -1755,7 +1755,7 @@ BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *xev ) - input.u.mi.dy = event->y; - input.u.mi.mouseData = 0; - input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; -- input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); -+ input.u.mi.time = x11drv_time_to_ticks( event->time ); - input.u.mi.dwExtraInfo = 0; - - if (!hwnd && is_old_motion_event( event->serial )) -@@ -1787,7 +1787,7 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev ) - input.u.mi.dy = event->y; - input.u.mi.mouseData = 0; - input.u.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; -- input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); -+ input.u.mi.time = x11drv_time_to_ticks( event->time ); - input.u.mi.dwExtraInfo = 0; - - if (is_old_motion_event( event->serial )) -@@ -1907,7 +1907,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - input.type = INPUT_MOUSE; - input.u.mi.mouseData = 0; - input.u.mi.dwFlags = MOUSEEVENTF_MOVE; -- input.u.mi.time = EVENT_x11_time_to_win32_time( event->time ); -+ input.u.mi.time = x11drv_time_to_ticks( event->time ); - input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; -diff --git a/dlls/winex11.drv/wintab.c b/dlls/winex11.drv/wintab.c -index 331601c3325..692d0872286 100644 ---- a/dlls/winex11.drv/wintab.c -+++ b/dlls/winex11.drv/wintab.c -@@ -893,7 +893,7 @@ static BOOL motion_event( HWND hwnd, XEvent *event ) - - /* Set cursor to inverted if cursor is the eraser */ - gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); -- gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(motion->time); -+ gMsgPacket.pkTime = x11drv_time_to_ticks(motion->time); - gMsgPacket.pkSerialNumber = gSerial++; - gMsgPacket.pkCursor = curnum; - gMsgPacket.pkX = motion->axis_data[0]; -@@ -926,7 +926,7 @@ static BOOL button_event( HWND hwnd, XEvent *event ) - /* Set cursor to inverted if cursor is the eraser */ - gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); - set_button_state(curnum, button->deviceid); -- gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(button->time); -+ gMsgPacket.pkTime = x11drv_time_to_ticks(button->time); - gMsgPacket.pkSerialNumber = gSerial++; - gMsgPacket.pkCursor = curnum; - if (button->axes_count > 0) { -@@ -976,7 +976,7 @@ static BOOL proximity_event( HWND hwnd, XEvent *event ) - /* Set cursor to inverted if cursor is the eraser */ - gMsgPacket.pkStatus = (cursor->TYPE == CSR_TYPE_ERASER ? TPS_INVERT:0); - gMsgPacket.pkStatus |= (event->type==proximity_out_type)?TPS_PROXIMITY:0; -- gMsgPacket.pkTime = EVENT_x11_time_to_win32_time(proximity->time); -+ gMsgPacket.pkTime = x11drv_time_to_ticks(proximity->time); - gMsgPacket.pkSerialNumber = gSerial++; - gMsgPacket.pkCursor = curnum; - gMsgPacket.pkX = proximity->axis_data[0]; -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 8dc74aa2e39..0f09c1891f6 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -569,7 +569,7 @@ extern int xinput2_opcode DECLSPEC_HIDDEN; - extern Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) DECLSPEC_HIDDEN; - extern void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) DECLSPEC_HIDDEN; - --extern DWORD EVENT_x11_time_to_win32_time(Time time) DECLSPEC_HIDDEN; -+extern DWORD x11drv_time_to_ticks(Time time) DECLSPEC_HIDDEN; - - /* X11 driver private messages, must be in the range 0x80001000..0x80001fff */ - enum x11drv_window_messages -From ad9001792de0e8227aa7aa218bc42a29864ebd39 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 4 Jan 2022 00:11:25 +0100 -Subject: [PATCH] dinput/tests: Add some RegisterDeviceNotificationA and - hotplug tests. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -CW-Bug-Id: #19841 -CW-Bug-Id: #19843 -CW-Bug-Id: #19844 - -Signed-off-by: Rémi Bernon -Signed-off-by: Alexandre Julliard -(cherry picked from commit 22f9f5caead14be79751879ec117d9a2760eb4d2) ---- - dlls/dinput/tests/dinput_test.h | 1 + - dlls/dinput/tests/hid.c | 86 ++++++++++ - dlls/dinput/tests/joystick8.c | 282 ++++++++++++++++++++++++++++++++ - 3 files changed, 369 insertions(+) - -diff --git a/dlls/dinput/tests/dinput_test.h b/dlls/dinput/tests/dinput_test.h -index 0a4c9ba5fa4..97eed949a36 100644 ---- a/dlls/dinput/tests/dinput_test.h -+++ b/dlls/dinput/tests/dinput_test.h -@@ -66,6 +66,7 @@ BOOL dinput_test_init_( const char *file, int line ); - void dinput_test_exit(void); - - HRESULT dinput_test_create_device( DWORD version, DIDEVICEINSTANCEW *devinst, IDirectInputDevice8W **device ); -+DWORD WINAPI dinput_test_device_thread( void *stop_event ); - - #define check_member_( file, line, val, exp, fmt, member ) \ - ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member ) -diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c -index a0fd2f6c660..534269d1dfe 100644 ---- a/dlls/dinput/tests/hid.c -+++ b/dlls/dinput/tests/hid.c -@@ -3478,6 +3478,92 @@ HRESULT dinput_test_create_device( DWORD version, DIDEVICEINSTANCEW *devinst, ID - return DI_OK; - } - -+DWORD WINAPI dinput_test_device_thread( void *stop_event ) -+{ -+#include "psh_hid_macros.h" -+ static const unsigned char gamepad_desc[] = -+ { -+ USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), -+ USAGE(1, HID_USAGE_GENERIC_GAMEPAD), -+ COLLECTION(1, Application), -+ USAGE(1, HID_USAGE_GENERIC_GAMEPAD), -+ COLLECTION(1, Physical), -+ USAGE(1, HID_USAGE_GENERIC_X), -+ USAGE(1, HID_USAGE_GENERIC_Y), -+ LOGICAL_MINIMUM(1, 0), -+ LOGICAL_MAXIMUM(1, 127), -+ PHYSICAL_MINIMUM(1, 0), -+ PHYSICAL_MAXIMUM(1, 127), -+ REPORT_SIZE(1, 8), -+ REPORT_COUNT(1, 2), -+ INPUT(1, Data|Var|Abs), -+ -+ 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, -+ }; -+#include "pop_hid_macros.h" -+ static const HID_DEVICE_ATTRIBUTES attributes = -+ { -+ .Size = sizeof(HID_DEVICE_ATTRIBUTES), -+ .VendorID = LOWORD( EXPECT_VIDPID ), -+ .ProductID = HIWORD( EXPECT_VIDPID ), -+ .VersionNumber = 0x0100, -+ }; -+ static const HIDP_CAPS caps = -+ { -+ .InputReportByteLength = 3, -+ }; -+ -+ WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; -+ DWORD report_id = 1, polled = 0; -+ char context[64]; -+ LSTATUS status; -+ HKEY hkey; -+ -+ GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); -+ GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); -+ SetCurrentDirectoryW( tempdir ); -+ -+ status = RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services\\winetest", -+ 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ); -+ ok( !status, "RegCreateKeyExW returned %#x\n", status ); -+ status = RegSetValueExW( hkey, L"ReportID", 0, REG_DWORD, (void *)&report_id, sizeof(report_id) ); -+ ok( !status, "RegSetValueExW returned %#x\n", status ); -+ status = RegSetValueExW( hkey, L"PolledMode", 0, REG_DWORD, (void *)&polled, sizeof(polled) ); -+ ok( !status, "RegSetValueExW returned %#x\n", status ); -+ status = RegSetValueExW( hkey, L"Descriptor", 0, REG_BINARY, (void *)gamepad_desc, sizeof(gamepad_desc) ); -+ ok( !status, "RegSetValueExW returned %#x\n", status ); -+ status = RegSetValueExW( hkey, L"Attributes", 0, REG_BINARY, (void *)&attributes, sizeof(attributes) ); -+ ok( !status, "RegSetValueExW returned %#x\n", status ); -+ status = RegSetValueExW( hkey, L"Caps", 0, REG_BINARY, (void *)&caps, sizeof(caps) ); -+ ok( !status, "RegSetValueExW returned %#x\n", status ); -+ status = RegSetValueExW( hkey, L"Expect", 0, REG_BINARY, (void *)NULL, 0 ); -+ ok( !status, "RegSetValueExW returned %#x\n", status ); -+ status = RegSetValueExW( hkey, L"Input", 0, REG_BINARY, NULL, 0 ); -+ ok( !status, "RegSetValueExW returned %#x\n", status ); -+ fill_context( __LINE__, context, ARRAY_SIZE(context) ); -+ status = RegSetValueExW( hkey, L"Context", 0, REG_BINARY, (void *)context, sizeof(context) ); -+ ok( !status, "RegSetValueExW returned %#x\n", status ); -+ -+ pnp_driver_start( L"driver_hid.dll" ); -+ WaitForSingleObject( stop_event, INFINITE ); -+ pnp_driver_stop(); -+ -+ SetCurrentDirectoryW( cwd ); -+ -+ return 0; -+} -+ - START_TEST( hid ) - { - if (!dinput_test_init()) return; -diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c -index d06b56cbf8c..0943d44fd58 100644 ---- a/dlls/dinput/tests/joystick8.c -+++ b/dlls/dinput/tests/joystick8.c -@@ -30,6 +30,7 @@ - #include "dinput.h" - #include "dinputd.h" - #include "devguid.h" -+#include "dbt.h" - #include "mmsystem.h" - - #include "wine/hid.h" -@@ -2741,6 +2742,285 @@ static BOOL test_winmm_joystick(void) - return device != NULL; - } - -+static int device_change_count; -+static int device_change_expect; -+static HWND device_change_hwnd; -+static BOOL device_change_all; -+ -+static BOOL all_upper( const WCHAR *str, const WCHAR *end ) -+{ -+ while (str++ != end) if (towupper( str[-1] ) != str[-1]) return FALSE; -+ return TRUE; -+} -+ -+static BOOL all_lower( const WCHAR *str, const WCHAR *end ) -+{ -+ while (str++ != end) if (towlower( str[-1] ) != str[-1]) return FALSE; -+ return TRUE; -+} -+ -+static LRESULT CALLBACK devnotify_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) -+{ -+ if (msg == WM_DEVICECHANGE) -+ { -+ DEV_BROADCAST_HDR *header = (DEV_BROADCAST_HDR *)lparam; -+ DEV_BROADCAST_DEVICEINTERFACE_W *iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)lparam; -+ const WCHAR *upper_end, *name_end, *expect_prefix; -+ GUID expect_guid; -+ -+ if (device_change_all && (device_change_count == 0 || device_change_count == 3)) -+ { -+ expect_guid = control_class; -+ expect_prefix = L"\\\\?\\ROOT#"; -+ } -+ else -+ { -+ expect_guid = GUID_DEVINTERFACE_HID; -+ expect_prefix = L"\\\\?\\HID#"; -+ } -+ -+ ok( hwnd == device_change_hwnd, "got hwnd %p\n", hwnd ); -+ ok( header->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE, "got dbch_devicetype %u\n", -+ header->dbch_devicetype ); -+ -+ winetest_push_context( "%u", device_change_count ); -+ -+ todo_wine_if( IsEqualGUID( &iface->dbcc_classguid, &control_class ) && !device_change_all ) -+ ok( IsEqualGUID( &iface->dbcc_classguid, &expect_guid ), "got dbch_classguid %s\n", -+ debugstr_guid( &iface->dbcc_classguid ) ); -+ ok( iface->dbcc_size >= offsetof( DEV_BROADCAST_DEVICEINTERFACE_W, dbcc_name[wcslen( iface->dbcc_name ) + 1] ), -+ "got dbcc_size %u\n", iface->dbcc_size ); -+ todo_wine -+ ok( !wcsncmp( iface->dbcc_name, expect_prefix, wcslen( expect_prefix ) ), -+ "got dbcc_name %s\n", debugstr_w(iface->dbcc_name) ); -+ -+ upper_end = wcschr( iface->dbcc_name + wcslen( expect_prefix ), '#' ); -+ name_end = iface->dbcc_name + wcslen( iface->dbcc_name ) + 1; -+ ok( !!upper_end, "got dbcc_name %s\n", debugstr_w(iface->dbcc_name) ); -+ todo_wine -+ ok( all_upper( iface->dbcc_name, upper_end ), "got dbcc_name %s\n", debugstr_w(iface->dbcc_name) ); -+ ok( all_lower( upper_end, name_end ), "got dbcc_name %s\n", debugstr_w(iface->dbcc_name) ); -+ -+ if (device_change_count++ >= device_change_expect / 2) -+ ok( wparam == DBT_DEVICEREMOVECOMPLETE, "got wparam %#x\n", (DWORD)wparam ); -+ else -+ ok( wparam == DBT_DEVICEARRIVAL, "got wparam %#x\n", (DWORD)wparam ); -+ -+ winetest_pop_context(); -+ } -+ -+ return DefWindowProcW( hwnd, msg, wparam, lparam ); -+} -+ -+static void test_RegisterDeviceNotification(void) -+{ -+ DEV_BROADCAST_DEVICEINTERFACE_A iface_filter_a = -+ { -+ .dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_A), -+ .dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE, -+ .dbcc_classguid = GUID_DEVINTERFACE_HID, -+ }; -+ WNDCLASSEXW class = -+ { -+ .cbSize = sizeof(WNDCLASSEXW), -+ .hInstance = GetModuleHandleW( NULL ), -+ .lpszClassName = L"devnotify", -+ .lpfnWndProc = devnotify_wndproc, -+ }; -+ char buffer[1024] = {0}; -+ DEV_BROADCAST_HDR *header = (DEV_BROADCAST_HDR *)buffer; -+ HANDLE hwnd, thread, stop_event; -+ HDEVNOTIFY devnotify; -+ MSG msg; -+ -+ RegisterClassExW( &class ); -+ -+ hwnd = CreateWindowW( class.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL ); -+ ok( !!hwnd, "CreateWindowW failed, error %u\n", GetLastError() ); -+ -+ SetLastError( 0xdeadbeef ); -+ devnotify = RegisterDeviceNotificationA( NULL, NULL, 0 ); -+ todo_wine -+ ok( !devnotify, "RegisterDeviceNotificationA succeeded\n" ); -+ todo_wine -+ ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError() ); -+ if (devnotify) UnregisterDeviceNotification( devnotify ); -+ -+ SetLastError( 0xdeadbeef ); -+ devnotify = RegisterDeviceNotificationA( (HWND)0xdeadbeef, NULL, 0 ); -+ todo_wine -+ ok( !devnotify, "RegisterDeviceNotificationA succeeded\n" ); -+ todo_wine -+ ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError() ); -+ if (devnotify) UnregisterDeviceNotification( devnotify ); -+ -+ SetLastError( 0xdeadbeef ); -+ devnotify = RegisterDeviceNotificationA( hwnd, NULL, 2 ); -+ todo_wine -+ ok( !devnotify, "RegisterDeviceNotificationA succeeded\n" ); -+ todo_wine -+ ok( GetLastError() == ERROR_INVALID_PARAMETER, "got error %u\n", GetLastError() ); -+ if (devnotify) UnregisterDeviceNotification( devnotify ); -+ -+ SetLastError( 0xdeadbeef ); -+ memset( header, 0, sizeof(DEV_BROADCAST_OEM) ); -+ header->dbch_size = sizeof(DEV_BROADCAST_OEM); -+ header->dbch_devicetype = DBT_DEVTYP_OEM; -+ devnotify = RegisterDeviceNotificationA( hwnd, header, 0 ); -+ todo_wine -+ ok( !devnotify, "RegisterDeviceNotificationA succeeded\n" ); -+ todo_wine -+ ok( GetLastError() == ERROR_INVALID_DATA || GetLastError() == ERROR_SERVICE_SPECIFIC_ERROR, -+ "got error %u\n", GetLastError() ); -+ if (devnotify) UnregisterDeviceNotification( devnotify ); -+ -+ SetLastError( 0xdeadbeef ); -+ memset( header, 0, sizeof(DEV_BROADCAST_DEVNODE) ); -+ header->dbch_size = sizeof(DEV_BROADCAST_DEVNODE); -+ header->dbch_devicetype = DBT_DEVTYP_DEVNODE; -+ devnotify = RegisterDeviceNotificationA( hwnd, header, 0 ); -+ todo_wine -+ ok( !devnotify, "RegisterDeviceNotificationA succeeded\n" ); -+ todo_wine -+ ok( GetLastError() == ERROR_INVALID_DATA || GetLastError() == ERROR_SERVICE_SPECIFIC_ERROR, -+ "got error %u\n", GetLastError() ); -+ if (devnotify) UnregisterDeviceNotification( devnotify ); -+ -+ SetLastError( 0xdeadbeef ); -+ memset( header, 0, sizeof(DEV_BROADCAST_VOLUME) ); -+ header->dbch_size = sizeof(DEV_BROADCAST_VOLUME); -+ header->dbch_devicetype = DBT_DEVTYP_VOLUME; -+ devnotify = RegisterDeviceNotificationA( hwnd, header, 0 ); -+ todo_wine -+ ok( !devnotify, "RegisterDeviceNotificationA succeeded\n" ); -+ todo_wine -+ ok( GetLastError() == ERROR_INVALID_DATA || GetLastError() == ERROR_SERVICE_SPECIFIC_ERROR, -+ "got error %u\n", GetLastError() ); -+ if (devnotify) UnregisterDeviceNotification( devnotify ); -+ -+ SetLastError( 0xdeadbeef ); -+ memset( header, 0, sizeof(DEV_BROADCAST_PORT_A) ); -+ header->dbch_size = sizeof(DEV_BROADCAST_PORT_A); -+ header->dbch_devicetype = DBT_DEVTYP_PORT; -+ devnotify = RegisterDeviceNotificationA( hwnd, header, 0 ); -+ todo_wine -+ ok( !devnotify, "RegisterDeviceNotificationA succeeded\n" ); -+ todo_wine -+ ok( GetLastError() == ERROR_INVALID_DATA || GetLastError() == ERROR_SERVICE_SPECIFIC_ERROR, -+ "got error %u\n", GetLastError() ); -+ if (devnotify) UnregisterDeviceNotification( devnotify ); -+ -+ SetLastError( 0xdeadbeef ); -+ memset( header, 0, sizeof(DEV_BROADCAST_NET) ); -+ header->dbch_size = sizeof(DEV_BROADCAST_NET); -+ header->dbch_devicetype = DBT_DEVTYP_NET; -+ devnotify = RegisterDeviceNotificationA( hwnd, header, 0 ); -+ todo_wine -+ ok( !devnotify, "RegisterDeviceNotificationA succeeded\n" ); -+ todo_wine -+ ok( GetLastError() == ERROR_INVALID_DATA || GetLastError() == ERROR_SERVICE_SPECIFIC_ERROR, -+ "got error %u\n", GetLastError() ); -+ if (devnotify) UnregisterDeviceNotification( devnotify ); -+ -+ devnotify = RegisterDeviceNotificationA( hwnd, &iface_filter_a, DEVICE_NOTIFY_WINDOW_HANDLE ); -+ ok( !!devnotify, "RegisterDeviceNotificationA failed, error %u\n", GetLastError() ); -+ while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); -+ -+ device_change_count = 0; -+ if (!strcmp( winetest_platform, "wine" )) device_change_expect = 4; -+ else device_change_expect = 2; -+ device_change_hwnd = hwnd; -+ device_change_all = FALSE; -+ stop_event = CreateEventW( NULL, FALSE, FALSE, NULL ); -+ ok( !!stop_event, "CreateEventW failed, error %u\n", GetLastError() ); -+ thread = CreateThread( NULL, 0, dinput_test_device_thread, stop_event, 0, NULL ); -+ ok( !!thread, "CreateThread failed, error %u\n", GetLastError() ); -+ -+ while (device_change_count < device_change_expect) -+ { -+ while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) -+ { -+ TranslateMessage( &msg ); -+ ok( msg.message != WM_DEVICECHANGE, "got WM_DEVICECHANGE\n" ); -+ DispatchMessageW( &msg ); -+ } -+ if (device_change_count == device_change_expect / 2) SetEvent( stop_event ); -+ } -+ -+ WaitForSingleObject( thread, INFINITE ); -+ CloseHandle( thread ); -+ CloseHandle( stop_event ); -+ -+ UnregisterDeviceNotification( devnotify ); -+ -+ memcpy( buffer, &iface_filter_a, sizeof(iface_filter_a) ); -+ strcpy( ((DEV_BROADCAST_DEVICEINTERFACE_A *)buffer)->dbcc_name, "device name" ); -+ ((DEV_BROADCAST_DEVICEINTERFACE_A *)buffer)->dbcc_size += strlen( "device name" ) + 1; -+ devnotify = RegisterDeviceNotificationA( hwnd, buffer, DEVICE_NOTIFY_WINDOW_HANDLE ); -+ ok( !!devnotify, "RegisterDeviceNotificationA failed, error %u\n", GetLastError() ); -+ while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); -+ -+ device_change_count = 0; -+ if (!strcmp( winetest_platform, "wine" )) device_change_expect = 4; -+ else device_change_expect = 2; -+ device_change_hwnd = hwnd; -+ device_change_all = FALSE; -+ stop_event = CreateEventW( NULL, FALSE, FALSE, NULL ); -+ ok( !!stop_event, "CreateEventW failed, error %u\n", GetLastError() ); -+ thread = CreateThread( NULL, 0, dinput_test_device_thread, stop_event, 0, NULL ); -+ ok( !!thread, "CreateThread failed, error %u\n", GetLastError() ); -+ -+ while (device_change_count < device_change_expect) -+ { -+ while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) -+ { -+ TranslateMessage( &msg ); -+ ok( msg.message != WM_DEVICECHANGE, "got WM_DEVICECHANGE\n" ); -+ DispatchMessageW( &msg ); -+ } -+ if (device_change_count == device_change_expect / 2) SetEvent( stop_event ); -+ } -+ -+ WaitForSingleObject( thread, INFINITE ); -+ CloseHandle( thread ); -+ CloseHandle( stop_event ); -+ -+ UnregisterDeviceNotification( devnotify ); -+ -+ devnotify = RegisterDeviceNotificationA( hwnd, &iface_filter_a, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES ); -+ ok( !!devnotify, "RegisterDeviceNotificationA failed, error %u\n", GetLastError() ); -+ while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); -+ -+ device_change_count = 0; -+ device_change_expect = 4; -+ device_change_hwnd = hwnd; -+ device_change_all = TRUE; -+ stop_event = CreateEventW( NULL, FALSE, FALSE, NULL ); -+ ok( !!stop_event, "CreateEventW failed, error %u\n", GetLastError() ); -+ thread = CreateThread( NULL, 0, dinput_test_device_thread, stop_event, 0, NULL ); -+ ok( !!thread, "CreateThread failed, error %u\n", GetLastError() ); -+ -+ while (device_change_count < device_change_expect) -+ { -+ while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) -+ { -+ TranslateMessage( &msg ); -+ ok( msg.message != WM_DEVICECHANGE, "got WM_DEVICECHANGE\n" ); -+ DispatchMessageW( &msg ); -+ } -+ if (device_change_count == device_change_expect / 2) SetEvent( stop_event ); -+ } -+ -+ WaitForSingleObject( thread, INFINITE ); -+ CloseHandle( thread ); -+ CloseHandle( stop_event ); -+ -+ UnregisterDeviceNotification( devnotify ); -+ -+ DestroyWindow( hwnd ); -+ UnregisterClassW( class.lpszClassName, class.hInstance ); -+} -+ - START_TEST( joystick8 ) - { - if (!dinput_test_init()) return; -@@ -2758,6 +3038,8 @@ START_TEST( joystick8 ) - test_simple_joystick( 0x500 ); - test_simple_joystick( 0x700 ); - test_simple_joystick( 0x800 ); -+ -+ test_RegisterDeviceNotification(); - - test_driving_wheel_axes(); - } -From 2f1fb676d8bc1ab64c1702988d44e8cf6ddaa2b0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 24 Dec 2021 12:23:43 +0100 -Subject: [PATCH] user32: Remove FIXME from RegisterDeviceNotificationA. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -There's no conversion to do, the device name in the filter is ignored. - -CW-Bug-Id: #19841 -CW-Bug-Id: #19843 -CW-Bug-Id: #19844 -Signed-off-by: Rémi Bernon -Signed-off-by: Alexandre Julliard -(cherry picked from commit 30af95f45da07dbdc20f6c1684140803354b23db) ---- - dlls/user32/input.c | 8 ++------ - 1 file changed, 2 insertions(+), 6 deletions(-) - -diff --git a/dlls/user32/input.c b/dlls/user32/input.c -index a9624153bed..a1b140215c3 100644 ---- a/dlls/user32/input.c -+++ b/dlls/user32/input.c -@@ -1196,13 +1196,9 @@ extern BOOL WINAPI I_ScUnregisterDeviceNotification( HDEVNOTIFY handle ); - * - * See RegisterDeviceNotificationW. - */ --HDEVNOTIFY WINAPI RegisterDeviceNotificationA(HANDLE hRecipient, LPVOID pNotificationFilter, DWORD dwFlags) -+HDEVNOTIFY WINAPI RegisterDeviceNotificationA( HANDLE handle, void *filter, DWORD flags ) - { -- TRACE("(hwnd=%p, filter=%p,flags=0x%08x)\n", -- hRecipient,pNotificationFilter,dwFlags); -- if (pNotificationFilter) -- FIXME("The notification filter will requires an A->W when filter support is implemented\n"); -- return RegisterDeviceNotificationW(hRecipient, pNotificationFilter, dwFlags); -+ return RegisterDeviceNotificationW( handle, filter, flags ); - } - - /*********************************************************************** -From d609fdac26246e98d8476c7852820df532014eeb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 5 Jan 2022 15:19:33 +0100 -Subject: [PATCH] user32: Guard rawinput_devices against concurrent accesses. - -CW-Bug-Id: #19841 -CW-Bug-Id: #19843 -CW-Bug-Id: #19844 ---- - dlls/user32/rawinput.c | 41 +++++++++++++++++++++++++++++++++-------- - 1 file changed, 33 insertions(+), 8 deletions(-) - -diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c -index a774f12231b..96233329e04 100644 ---- a/dlls/user32/rawinput.c -+++ b/dlls/user32/rawinput.c -@@ -279,11 +279,25 @@ BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage) - - *usage_page = *usage = 0; - -- if (!(device = find_device_from_handle(handle))) return FALSE; -- if (device->info.dwType != RIM_TYPEHID) return FALSE; -+ EnterCriticalSection(&rawinput_devices_cs); -+ -+ if (!(device = find_device_from_handle(handle))) -+ { -+ WARN("could not find device for handle %p\n", handle); -+ LeaveCriticalSection(&rawinput_devices_cs); -+ return FALSE; -+ } -+ if (device->info.dwType != RIM_TYPEHID) -+ { -+ WARN("found non-hid device for handle %p\n", handle); -+ LeaveCriticalSection(&rawinput_devices_cs); -+ return FALSE; -+ } - - *usage_page = device->info.hid.usUsagePage; - *usage = device->info.hid.usUsage; -+ -+ LeaveCriticalSection(&rawinput_devices_cs); - return TRUE; - } - -@@ -423,7 +437,7 @@ BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_ms - UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_count, UINT size) - { - static UINT last_check; -- UINT i, ticks = GetTickCount(); -+ UINT i, count, ticks = GetTickCount(); - - TRACE("devices %p, device_count %p, size %u.\n", devices, device_count, size); - -@@ -439,32 +453,36 @@ UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_coun - return ~0U; - } - -+ EnterCriticalSection(&rawinput_devices_cs); - if (ticks - last_check > 2000) - { - last_check = ticks; - rawinput_update_device_list(); - } - -+ count = rawinput_devices_count; -+ LeaveCriticalSection(&rawinput_devices_cs); -+ - if (!devices) - { -- *device_count = rawinput_devices_count; -+ *device_count = count; - return 0; - } - -- if (*device_count < rawinput_devices_count) -+ if (*device_count < count) - { - SetLastError(ERROR_INSUFFICIENT_BUFFER); -- *device_count = rawinput_devices_count; -+ *device_count = count; - return ~0U; - } - -- for (i = 0; i < rawinput_devices_count; ++i) -+ for (i = 0; i < count; ++i) - { - devices[i].hDevice = rawinput_devices[i].handle; - devices[i].dwType = rawinput_devices[i].info.dwType; - } - -- return rawinput_devices_count; -+ return count; - } - - /*********************************************************************** -@@ -741,8 +759,12 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE handle, UINT command, void *data, UINT - SetLastError(ERROR_NOACCESS); - return ~0U; - } -+ -+ EnterCriticalSection(&rawinput_devices_cs); -+ - if (!(device = find_device_from_handle(handle))) - { -+ LeaveCriticalSection(&rawinput_devices_cs); - SetLastError(ERROR_INVALID_HANDLE); - return ~0U; - } -@@ -774,10 +796,13 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE handle, UINT command, void *data, UINT - - default: - FIXME("command %#x not supported\n", command); -+ LeaveCriticalSection(&rawinput_devices_cs); - SetLastError(ERROR_INVALID_PARAMETER); - return ~0U; - } - -+ LeaveCriticalSection(&rawinput_devices_cs); -+ - if (!data) - return 0; - -From a5f9baa9c61d71b09824f2a41e8d56c542241005 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 5 Jan 2022 16:14:02 +0100 -Subject: [PATCH] user32: Add or remove rawinput devices individually on - WM_DEVICECHANGE. - -CW-Bug-Id: #19841 -CW-Bug-Id: #19843 -CW-Bug-Id: #19844 ---- - dlls/user32/input.c | 4 ++++ - dlls/user32/rawinput.c | 42 +++++++++++++++++++++++++++++++++++++- - dlls/user32/user_private.h | 2 ++ - 3 files changed, 47 insertions(+), 1 deletion(-) - -diff --git a/dlls/user32/input.c b/dlls/user32/input.c -index a1b140215c3..c6b49d2a928 100644 ---- a/dlls/user32/input.c -+++ b/dlls/user32/input.c -@@ -1166,6 +1166,10 @@ BOOL WINAPI EnableMouseInPointer(BOOL enable) - - static DWORD CALLBACK devnotify_window_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) - { -+ DEV_BROADCAST_DEVICEINTERFACE_W *iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)header; -+ if (flags == DBT_DEVICEARRIVAL) rawinput_add_device(iface->dbcc_name); -+ if (flags == DBT_DEVICEREMOVECOMPLETE) rawinput_remove_device(iface->dbcc_name); -+ - SendMessageTimeoutW(handle, WM_DEVICECHANGE, flags, (LPARAM)header, SMTO_ABORTIFHUNG, 2000, NULL); - return 0; - } -diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c -index 96233329e04..05bc3709bd2 100644 ---- a/dlls/user32/rawinput.c -+++ b/dlls/user32/rawinput.c -@@ -172,6 +172,46 @@ static struct device *add_device(HDEVINFO set, SP_DEVICE_INTERFACE_DATA *iface) - return device; - } - -+void rawinput_add_device(const WCHAR *device_path) -+{ -+ ULONG i; -+ -+ EnterCriticalSection(&rawinput_devices_cs); -+ -+ for (i = 0; i < rawinput_devices_count; ++i) -+ if (!wcsicmp(rawinput_devices[i].detail->DevicePath, device_path)) -+ break; -+ -+ /* not there yet, force refresh the list, we cannot just add the device -+ here because it may not have its rawinput handle property assigned yet */ -+ if (i == rawinput_devices_count) rawinput_devices_count = 0; -+ -+ LeaveCriticalSection(&rawinput_devices_cs); -+} -+ -+void rawinput_remove_device(const WCHAR *device_path) -+{ -+ UINT i; -+ -+ EnterCriticalSection(&rawinput_devices_cs); -+ -+ for (i = 0; i < rawinput_devices_count; ++i) -+ if (!wcsicmp(rawinput_devices[i].detail->DevicePath, device_path)) -+ break; -+ -+ if (i < rawinput_devices_count) -+ { -+ HidD_FreePreparsedData(rawinput_devices[i].data); -+ CloseHandle(rawinput_devices[i].file); -+ free(rawinput_devices[i].detail); -+ -+ rawinput_devices_count--; -+ memmove(rawinput_devices + i, rawinput_devices + i + 1, rawinput_devices_count - i); -+ } -+ -+ LeaveCriticalSection(&rawinput_devices_cs); -+} -+ - void rawinput_update_device_list(void) - { - SP_DEVICE_INTERFACE_DATA iface = { sizeof(iface) }; -@@ -454,7 +494,7 @@ UINT WINAPI GetRawInputDeviceList(RAWINPUTDEVICELIST *devices, UINT *device_coun - } - - EnterCriticalSection(&rawinput_devices_cs); -- if (ticks - last_check > 2000) -+ if (ticks - last_check > 2000 || !rawinput_devices_count) - { - last_check = ticks; - rawinput_update_device_list(); -diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h -index e9dc214442b..c2c546a5865 100644 ---- a/dlls/user32/user_private.h -+++ b/dlls/user32/user_private.h -@@ -154,6 +154,8 @@ extern BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hard - extern BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage); - extern struct rawinput_thread_data *rawinput_thread_data(void); - extern void rawinput_update_device_list(void); -+extern void rawinput_add_device(const WCHAR *device_path); -+extern void rawinput_remove_device(const WCHAR *device_path); - - extern void create_offscreen_window_surface( const RECT *visible_rect, struct window_surface **surface ) DECLSPEC_HIDDEN; - -From 5975d0b5d870cfe1bf6c6fdce063a04957ed89a0 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Thu, 27 Jan 2022 19:17:58 +0200 -Subject: [PATCH] hidclass.sys: Add input.inf that matches all HID devices. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This makes it so that all the devices on the HID bus now have Class, -ClassGUID, Driver and DriverDesc register properties populated. - -Without having at least Driver and Class set SDL2 refuses to use HID -devices directly. - -Signed-off-by: Arkadiusz Hiler -Signed-off-by: Rémi Bernon -Signed-off-by: Alexandre Julliard -(cherry picked from commit 2f2aba45dd5f6e5bc1317afc7bc2e00ef78fff40) ---- - dlls/hidclass.sys/Makefile.in | 2 ++ - dlls/hidclass.sys/hidclass.rc | 20 ++++++++++++++++++++ - dlls/hidclass.sys/input.inf | 13 +++++++++++++ - loader/wine.inf.in | 1 + - 4 files changed, 36 insertions(+) - create mode 100644 dlls/hidclass.sys/hidclass.rc - create mode 100644 dlls/hidclass.sys/input.inf - -diff --git a/dlls/hidclass.sys/Makefile.in b/dlls/hidclass.sys/Makefile.in -index 25a0396dabe..788828ad66a 100644 ---- a/dlls/hidclass.sys/Makefile.in -+++ b/dlls/hidclass.sys/Makefile.in -@@ -5,3 +5,5 @@ IMPORTS = hal ntoskrnl user32 hidparse - C_SRCS = \ - device.c \ - pnp.c -+ -+RC_SRCS = hidclass.rc -diff --git a/dlls/hidclass.sys/hidclass.rc b/dlls/hidclass.sys/hidclass.rc -new file mode 100644 -index 00000000000..409bdc16b45 ---- /dev/null -+++ b/dlls/hidclass.sys/hidclass.rc -@@ -0,0 +1,20 @@ -+/* -+ * Copyright 2022 Arkadiusz Hiler -+ * -+ * 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 -+ */ -+ -+/* @makedep: input.inf */ -+1 WINE_DATA_FILE input.inf -diff --git a/dlls/hidclass.sys/input.inf b/dlls/hidclass.sys/input.inf -new file mode 100644 -index 00000000000..d9222b13672 ---- /dev/null -+++ b/dlls/hidclass.sys/input.inf -@@ -0,0 +1,13 @@ -+[Version] -+Signature="$CHICAGO$" -+ClassGuid={745a17a0-74d3-11d0-b6fe-00a0c90f57da} -+Class=HIDClass -+ -+[Manufacturer] -+Wine=mfg_section -+ -+[mfg_section] -+Wine HID device=device_section,HID\ -+ -+[device_section.Services] -+AddService = ,0x2 -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 677ae91a406..a3bf302ec6c 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -5760,6 +5760,7 @@ protocol,"@%11%\ws2_32.dll,-3" - services,"@%11%\ws2_32.dll,-4" - - [InfFiles] -+input.inf,"@%12%\hidclass.sys,-1" - winebus.inf,"@%12%\winebus.sys,-1" - winehid.inf,"@%12%\winehid.sys,-1" - wineusb.inf,"@%12%\wineusb.sys,-1" -From 9788768b62ddacb10fe00af888e54a79ad69e445 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Wed, 19 Jan 2022 15:04:20 +0200 -Subject: [PATCH] dinput/tests: Add static asserts for arrays that have to - match in size. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Arkadiusz Hiler -Signed-off-by: Rémi Bernon -Signed-off-by: Alexandre Julliard -(cherry picked from commit 2420f7e188e04cb428211aabef8ec2f327b0416f) ---- - dlls/dinput/tests/joystick8.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c -index 525f14f0bba..927d65abf4f 100644 ---- a/dlls/dinput/tests/joystick8.c -+++ b/dlls/dinput/tests/joystick8.c -@@ -2313,6 +2313,9 @@ static BOOL test_device_types( DWORD version ) - }, - }; - -+ C_ASSERT(ARRAY_SIZE(expect_caps) == ARRAY_SIZE(device_desc)); -+ C_ASSERT(ARRAY_SIZE(expect_devinst) == ARRAY_SIZE(device_desc)); -+ - DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; - DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; - WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; -From 2caa21b9221ed6406992f3f62b9c7c330b098f4f Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Wed, 19 Jan 2022 15:04:21 +0200 -Subject: [PATCH] include: Add HID_USAGE_SIMULATION_CLUTCH. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Arkadiusz Hiler -Signed-off-by: Rémi Bernon -Signed-off-by: Alexandre Julliard -(cherry picked from commit 87331939a2c7b5f4a164e77c2f2d3e6c13d3c5a9) ---- - include/hidusage.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/hidusage.h b/include/hidusage.h -index da7274b5945..3e2ee77f8c8 100644 ---- a/include/hidusage.h -+++ b/include/hidusage.h -@@ -207,6 +207,7 @@ typedef USHORT USAGE, *PUSAGE; - #define HID_USAGE_SIMULATION_THROTTLE ((USAGE) 0xBB) - #define HID_USAGE_SIMULATION_ACCELERATOR ((USAGE) 0xC4) - #define HID_USAGE_SIMULATION_BRAKE ((USAGE) 0xC5) -+#define HID_USAGE_SIMULATION_CLUTCH ((USAGE) 0xC6) - #define HID_USAGE_SIMULATION_STEERING ((USAGE) 0xC8) - - #define HID_USAGE_TELEPHONY_PHONE ((USAGE) 0x01) -From f1c5ef63f605a7ae7c729d01ef971459e9a2b6a8 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Wed, 5 Jan 2022 21:34:42 +0200 -Subject: [PATCH] winebus.sys: Add Logitech G920 mapping to the SDL backend. - -The HID input report format is different between Linux -(hid_logitech_hidpp) and Windows when it comes to axis HID usages. - -To correct that we can use the device through SDL and craft our own -HID mapping. ---- - dlls/winebus.sys/bus_sdl.c | 59 +++++++++++++++++++++++++++----------- - include/wine/hid.h | 5 ++++ - 2 files changed, 47 insertions(+), 17 deletions(-) - -diff --git a/dlls/winebus.sys/bus_sdl.c b/dlls/winebus.sys/bus_sdl.c -index 8cb1fea24e0..26191ccb3a5 100644 ---- a/dlls/winebus.sys/bus_sdl.c -+++ b/dlls/winebus.sys/bus_sdl.c -@@ -227,22 +227,44 @@ static BOOL descriptor_add_haptic(struct sdl_device *impl) - return TRUE; - } - --static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface) -+static const USAGE_AND_PAGE g920_absolute_usages[] = -+{ -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_X}, /* wheel */ -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Y}, /* accelerator */ -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Z}, /* brake */ -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RZ}, /* clutch */ -+}; -+ -+static const USAGE_AND_PAGE generic_absolute_usages[] = - { -- static const USAGE_AND_PAGE absolute_usages[] = -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_X}, -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Y}, -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Z}, -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RX}, -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RY}, -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RZ}, -+ {.UsagePage = HID_USAGE_PAGE_SIMULATION, .Usage = HID_USAGE_SIMULATION_THROTTLE}, -+ {.UsagePage = HID_USAGE_PAGE_SIMULATION, .Usage = HID_USAGE_SIMULATION_RUDDER}, -+ {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_WHEEL}, -+ {.UsagePage = HID_USAGE_PAGE_SIMULATION, .Usage = HID_USAGE_SIMULATION_ACCELERATOR}, -+ {.UsagePage = HID_USAGE_PAGE_SIMULATION, .Usage = HID_USAGE_SIMULATION_BRAKE}, -+}; -+ -+static int get_absolute_usages(struct sdl_device *impl, const USAGE_AND_PAGE **absolute_usages) -+{ -+ if (is_logitech_g920(pSDL_JoystickGetVendor(impl->sdl_joystick), pSDL_JoystickGetProduct(impl->sdl_joystick))) - { -- {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_X}, -- {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Y}, -- {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_Z}, -- {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RX}, -- {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RY}, -- {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_RZ}, -- {.UsagePage = HID_USAGE_PAGE_SIMULATION, .Usage = HID_USAGE_SIMULATION_THROTTLE}, -- {.UsagePage = HID_USAGE_PAGE_SIMULATION, .Usage = HID_USAGE_SIMULATION_RUDDER}, -- {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_WHEEL}, -- {.UsagePage = HID_USAGE_PAGE_SIMULATION, .Usage = HID_USAGE_SIMULATION_ACCELERATOR}, -- {.UsagePage = HID_USAGE_PAGE_SIMULATION, .Usage = HID_USAGE_SIMULATION_BRAKE}, -- }; -+ *absolute_usages = g920_absolute_usages; -+ return ARRAY_SIZE(g920_absolute_usages); -+ } -+ -+ *absolute_usages = generic_absolute_usages; -+ return ARRAY_SIZE(generic_absolute_usages); -+} -+ -+static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface) -+{ -+ const USAGE_AND_PAGE *absolute_usages = NULL; - static const USAGE_AND_PAGE relative_usages[] = - { - {.UsagePage = HID_USAGE_PAGE_GENERIC, .Usage = HID_USAGE_GENERIC_X}, -@@ -257,12 +279,15 @@ static NTSTATUS build_joystick_report_descriptor(struct unix_device *iface) - }; - struct sdl_device *impl = impl_from_unix_device(iface); - int i, button_count, axis_count, ball_count, hat_count; -+ size_t absolute_usages_count; -+ -+ absolute_usages_count = get_absolute_usages(impl, &absolute_usages); - - axis_count = pSDL_JoystickNumAxes(impl->sdl_joystick); -- if (axis_count > ARRAY_SIZE(absolute_usages)) -+ if (axis_count > absolute_usages_count) - { -- FIXME("More than %zu absolute axes found, ignoring.\n", ARRAY_SIZE(absolute_usages)); -- axis_count = ARRAY_SIZE(absolute_usages); -+ FIXME("More than %zu absolute axes found, ignoring.\n", absolute_usages_count); -+ axis_count = absolute_usages_count; - } - - ball_count = pSDL_JoystickNumBalls(impl->sdl_joystick); -diff --git a/include/wine/hid.h b/include/wine/hid.h -index 236888cbdc7..9a641cf00f7 100644 ---- a/include/wine/hid.h -+++ b/include/wine/hid.h -@@ -227,4 +227,9 @@ struct hid_preparsed_data - #define PID_USAGE_CREATE_NEW_EFFECT_REPORT ((USAGE) 0xab) - #define PID_USAGE_RAM_POOL_AVAILABLE ((USAGE) 0xac) - -+static inline BOOL is_logitech_g920(WORD vid, WORD pid) -+{ -+ return vid == 0x046D && pid == 0xC262; -+} -+ - #endif /* __WINE_PARSE_H */ -From 7c76a48943171f0def105a022860a0e198298534 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Mon, 24 Jan 2022 15:18:26 +0200 -Subject: [PATCH] HACK: winebus.sys: Defer Logitech G920 to the SDL backend. - ---- - dlls/winebus.sys/bus_udev.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dlls/winebus.sys/bus_udev.c b/dlls/winebus.sys/bus_udev.c -index b40c9f3f605..47597bc0c4c 100644 ---- a/dlls/winebus.sys/bus_udev.c -+++ b/dlls/winebus.sys/bus_udev.c -@@ -1670,6 +1670,12 @@ static void udev_add_device(struct udev_device *dev, int fd) - memcpy(desc.serialnumber, zeros, sizeof(zeros)); - } - -+ if (is_logitech_g920(desc.vid, desc.pid)) -+ { -+ TRACE("hidraw %s: deferring %s to a different backend\n", debugstr_a(devnode), debugstr_device_desc(&desc)); -+ close(fd); -+ return; -+ } - if (is_sdl_blacklisted(desc.vid, desc.pid)) - { - /* this device is blacklisted */ -From 8221592419d1e82f843c85422d069be9f0c37da7 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Tue, 18 Jan 2022 14:29:59 +0200 -Subject: [PATCH] dinput: Make it possible to add hacks that override names and - GUID of axes. - ---- - dlls/dinput/joystick_hid.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c -index fe59b69a93c..f8a392eb4f9 100644 ---- a/dlls/dinput/joystick_hid.c -+++ b/dlls/dinput/joystick_hid.c -@@ -532,6 +532,8 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, - struct hid_collection_node *node, *node_end; - WORD version = impl->base.dinput->dwVersion; - BOOL ret, seen_axis[6] = {0}; -+ const GUID *hack_guid; -+ const WCHAR *hack_name; - const WCHAR *tmp; - - button_ofs += impl->caps.NumberInputValueCaps * sizeof(LONG); -@@ -551,6 +553,8 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, - value_ofs += (caps->usage_max - caps->usage_min + 1) * sizeof(LONG); - else for (j = caps->usage_min; j <= caps->usage_max; ++j) - { -+ hack_name = NULL; -+ hack_guid = NULL; - instance.dwOfs = value_ofs; - switch (MAKELONG(j, caps->usage_page)) - { -@@ -597,12 +601,16 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, - } - instance.wUsagePage = caps->usage_page; - instance.wUsage = j; -- instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); -+ if (hack_guid) -+ instance.guidType = *hack_guid; -+ else -+ instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); - instance.wReportId = caps->report_id; - instance.wCollectionNumber = caps->link_collection; - instance.dwDimension = caps->units; - instance.wExponent = caps->units_exp; -- if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); -+ if (hack_name) lstrcpynW( instance.tszName, hack_name, MAX_PATH ); -+ else if ((tmp = object_usage_to_string( &instance ))) lstrcpynW( instance.tszName, tmp, MAX_PATH ); - else swprintf( instance.tszName, MAX_PATH, L"Unknown %u", DIDFT_GETINSTANCE( instance.dwType ) ); - check_pid_effect_axis_caps( impl, &instance ); - ret = enum_object( impl, filter, flags, callback, caps, &instance, data ); -From 7de2bfee4e5bb8a315ccdb348f0cf6c63f361455 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Tue, 18 Jan 2022 14:30:46 +0200 -Subject: [PATCH] dinput: Add mapping for Logitech G920. - -The wheel has a custom mapping and type override on Windows that do not -correspond what dinput would create by itself basing on HID descriptors. ---- - dlls/dinput/joystick_hid.c | 39 +++++++++++++++++++++++++++++++++++++- - 1 file changed, 38 insertions(+), 1 deletion(-) - -diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c -index f8a392eb4f9..1cac074facc 100644 ---- a/dlls/dinput/joystick_hid.c -+++ b/dlls/dinput/joystick_hid.c -@@ -46,6 +46,9 @@ - #include "wine/debug.h" - #include "wine/hid.h" - -+#define VID_LOGITECH 0x046D -+#define PID_LOGITECH_G920 0xC262 -+ - WINE_DEFAULT_DEBUG_CHANNEL(dinput); - - DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 ); -@@ -564,7 +567,38 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *filter, - case MAKELONG(HID_USAGE_GENERIC_RX, HID_USAGE_PAGE_GENERIC): - case MAKELONG(HID_USAGE_GENERIC_RY, HID_USAGE_PAGE_GENERIC): - case MAKELONG(HID_USAGE_GENERIC_RZ, HID_USAGE_PAGE_GENERIC): -- set_axis_type( &instance, seen_axis, j - HID_USAGE_GENERIC_X, &axis ); -+ if (impl->attrs.VendorID == VID_LOGITECH && impl->attrs.ProductID == PID_LOGITECH_G920) -+ { -+ if (j == HID_USAGE_GENERIC_X) -+ { -+ set_axis_type( &instance, seen_axis, 0, &axis ); -+ hack_guid = &GUID_XAxis; -+ hack_name = L"Wheel axis"; -+ } -+ else if (j == HID_USAGE_GENERIC_Y) -+ { -+ set_axis_type( &instance, seen_axis, 2, &axis ); -+ hack_guid = &GUID_YAxis; -+ hack_name = L"Accelerator"; -+ } -+ else if (j == HID_USAGE_GENERIC_Z) -+ { -+ set_axis_type( &instance, seen_axis, 5, &axis ); -+ hack_guid = &GUID_RzAxis; -+ hack_name = L"Brake"; -+ } -+ else if (j == HID_USAGE_GENERIC_RZ) -+ { -+ instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 + axis++ ); -+ hack_guid = &GUID_Slider; -+ hack_name = L"Clutch"; -+ } -+ else WARN("unknown axis usage page %x usage %x for Logitech G920\n", caps->usage_page, j); -+ } -+ else -+ { -+ set_axis_type( &instance, seen_axis, j - HID_USAGE_GENERIC_X, &axis ); -+ } - instance.dwFlags = DIDOI_ASPECTPOSITION; - break; - case MAKELONG(HID_USAGE_SIMULATION_STEERING, HID_USAGE_PAGE_SIMULATION): -@@ -1550,6 +1584,9 @@ static BOOL hid_joystick_device_try_open( UINT32 handle, const WCHAR *path, HAND - type |= (DI8DEVTYPEDRIVING_LIMITED << 8); - } - -+ if (attrs->VendorID == VID_LOGITECH && attrs->ProductID == PID_LOGITECH_G920) -+ type = DI8DEVTYPE_DRIVING | (DI8DEVTYPEDRIVING_DUALPEDALS << 8) | DIDEVTYPE_HID; -+ - instance->dwDevType = device_type_for_version( type, version ); - - *device = device_file; diff --git a/patches/proton/16-proton-vrclient-wined3d.patch b/patches/proton/16-proton-vrclient-wined3d.patch deleted file mode 100755 index 80c2b3921..000000000 --- a/patches/proton/16-proton-vrclient-wined3d.patch +++ /dev/null @@ -1,1621 +0,0 @@ -From 4ad17bc8a5651c65b7e1bced3c9e04bce9f77c91 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Wed, 4 Apr 2018 17:05:37 +0200 -Subject: [PATCH 01/12] wined3d: Implement GL texture access callbacks. - ---- - dlls/wined3d/cs.c | 52 ++++++++++++++++++++++++++++++++++ - dlls/wined3d/texture.c | 10 +++++++ - dlls/wined3d/wined3d_private.h | 3 ++ - include/wine/wined3d.h | 5 ++++ - 4 files changed, 70 insertions(+) - -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index 21aaa2e54b6..e291e2b550d 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -77,6 +77,7 @@ enum wined3d_cs_op - WINED3D_CS_OP_COPY_UAV_COUNTER, - WINED3D_CS_OP_GENERATE_MIPMAPS, - WINED3D_CS_OP_EXECUTE_COMMAND_LIST, -+ WINED3D_CS_OP_GL_TEXTURE_CALLBACK, - WINED3D_CS_OP_STOP, - }; - -@@ -457,6 +458,15 @@ struct wined3d_cs_generate_mipmaps - struct wined3d_shader_resource_view *view; - }; - -+struct wined3d_cs_gl_texture_callback -+{ -+ enum wined3d_cs_op opcode; -+ struct wined3d_texture *texture; -+ wined3d_gl_texture_callback callback; -+ unsigned int data_size; -+ BYTE data[1]; -+}; -+ - struct wined3d_cs_stop - { - enum wined3d_cs_op opcode; -@@ -2698,6 +2708,47 @@ void wined3d_device_context_emit_generate_mipmaps(struct wined3d_device_context - wined3d_device_context_submit(context, WINED3D_CS_QUEUE_DEFAULT); - } - -+static void wined3d_cs_exec_gl_texture_callback(struct wined3d_cs *cs, const void *data) -+{ -+ const struct wined3d_cs_gl_texture_callback *op = data; -+ struct wined3d_texture_gl *texture = wined3d_texture_gl(op->texture); -+ const struct wined3d_gl_info *gl_info; -+ struct wined3d_context *context; -+ -+ context = context_acquire(cs->c.device, NULL, 0); -+ gl_info = wined3d_context_gl(context)->gl_info; -+ -+ wined3d_texture_load_location(&texture->t, 0, context, WINED3D_LOCATION_TEXTURE_RGB); -+ -+ op->callback(texture->texture_rgb.name, op->data, op->data_size); -+ -+ context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); -+ context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); -+ -+ checkGLcall("texture callback\n"); -+ -+ context_release(context); -+ -+ wined3d_resource_release(&texture->t.resource); -+} -+ -+void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_texture *texture, -+ wined3d_gl_texture_callback callback, const void *data, unsigned int size) -+{ -+ struct wined3d_cs_gl_texture_callback *op; -+ -+ op = cs->c.ops->require_space(cs, sizeof(*op) + size, WINED3D_CS_QUEUE_DEFAULT); -+ op->opcode = WINED3D_CS_OP_GL_TEXTURE_CALLBACK; -+ op->texture = texture; -+ op->callback = callback; -+ op->data_size = size; -+ memcpy(op->data, data, size); -+ -+ wined3d_resource_acquire(&texture->resource); -+ -+ cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); -+} -+ - static void wined3d_cs_emit_stop(struct wined3d_cs *cs) - { - struct wined3d_cs_stop *op; -@@ -2865,6 +2916,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void - /* WINED3D_CS_OP_COPY_UAV_COUNTER */ wined3d_cs_exec_copy_uav_counter, - /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps, - /* WINED3D_CS_OP_EXECUTE_COMMAND_LIST */ wined3d_cs_exec_execute_command_list, -+ /* WINED3D_CS_OP_GL_TEXTURE_CALLBACK */ wined3d_cs_exec_gl_texture_callback, - }; - - static void *wined3d_cs_st_require_space(struct wined3d_device_context *context, -diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c -index 39e6e2a68b7..bdcd0b55ae6 100644 ---- a/dlls/wined3d/texture.c -+++ b/dlls/wined3d/texture.c -@@ -4574,6 +4574,16 @@ void wined3d_texture_download_from_texture(struct wined3d_texture *dst_texture, - wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location); - } - -+void CDECL wined3d_access_gl_texture(struct wined3d_texture *texture, -+ wined3d_gl_texture_callback callback, const void *data, unsigned int size) -+{ -+ struct wined3d_device *device = texture->resource.device; -+ -+ TRACE("texture %p, callback %p, data %p, size %u.\n", texture, callback, data, size); -+ -+ wined3d_cs_emit_gl_texture_callback(device->cs, texture, callback, data, size); -+} -+ - static void wined3d_texture_no3d_upload_data(struct wined3d_context *context, - const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, - const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index f5b1a078907..756d47ef20d 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -4762,6 +4762,9 @@ static inline void wined3d_cs_finish(struct wined3d_cs *cs, enum wined3d_cs_queu - cs->c.ops->finish(&cs->c, queue_id); - } - -+void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_texture *texture, -+ wined3d_gl_texture_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; -+ - static inline void wined3d_device_context_push_constants(struct wined3d_device_context *context, - enum wined3d_push_constants p, unsigned int start_idx, unsigned int count, const void *constants) - { -diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h -index dd1c15f14ed..2123e857a52 100644 ---- a/include/wine/wined3d.h -+++ b/include/wine/wined3d.h -@@ -2969,6 +2969,11 @@ ULONG __cdecl wined3d_vertex_declaration_incref(struct wined3d_vertex_declaratio - HRESULT __cdecl wined3d_extract_shader_input_signature_from_dxbc(struct wined3d_shader_signature *signature, - const void *byte_code, SIZE_T byte_code_size); - -+typedef void (__cdecl *wined3d_gl_texture_callback)(unsigned int gl_texture, const void *data, unsigned int size); -+ -+void __cdecl wined3d_access_gl_texture(struct wined3d_texture *texture, -+ wined3d_gl_texture_callback callback, const void *data, unsigned int size); -+ - /* Return the integer base-2 logarithm of x. Undefined for x == 0. */ - static inline unsigned int wined3d_log2i(unsigned int x) - { --- -2.30.2 - -From 34565d56b8cfcdcf787c5a3a0466f990918d1139 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Wed, 4 Apr 2018 17:05:37 +0200 -Subject: [PATCH 02/12] wined3d: Implement command stream callbacks. - ---- - dlls/wined3d/cs.c | 40 ++++++++++++++++++++++++++++++++++ - dlls/wined3d/device.c | 8 +++++++ - dlls/wined3d/wined3d_private.h | 2 ++ - include/wine/wined3d.h | 5 +++++ - 4 files changed, 55 insertions(+) - -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index e291e2b550d..cf55385c3c1 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -78,6 +78,7 @@ enum wined3d_cs_op - WINED3D_CS_OP_GENERATE_MIPMAPS, - WINED3D_CS_OP_EXECUTE_COMMAND_LIST, - WINED3D_CS_OP_GL_TEXTURE_CALLBACK, -+ WINED3D_CS_OP_USER_CALLBACK, - WINED3D_CS_OP_STOP, - }; - -@@ -467,6 +468,14 @@ struct wined3d_cs_gl_texture_callback - BYTE data[1]; - }; - -+struct wined3d_cs_user_callback -+{ -+ enum wined3d_cs_op opcode; -+ wined3d_cs_callback callback; -+ unsigned int data_size; -+ BYTE data[1]; -+}; -+ - struct wined3d_cs_stop - { - enum wined3d_cs_op opcode; -@@ -2749,6 +2758,36 @@ void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_t - cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); - } - -+static void wined3d_cs_exec_user_callback(struct wined3d_cs *cs, const void *data) -+{ -+ const struct wined3d_cs_user_callback *op = data; -+ const struct wined3d_gl_info *gl_info; -+ struct wined3d_context *context; -+ -+ context = context_acquire(cs->c.device, NULL, 0); -+ gl_info = wined3d_context_gl(context)->gl_info; -+ -+ op->callback(op->data, op->data_size); -+ -+ checkGLcall("user callback\n"); -+ -+ context_release(context); -+} -+ -+void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, -+ wined3d_cs_callback callback, const void *data, unsigned int size) -+{ -+ struct wined3d_cs_user_callback *op; -+ -+ op = cs->c.ops->require_space(cs, sizeof(*op) + size, WINED3D_CS_QUEUE_DEFAULT); -+ op->opcode = WINED3D_CS_OP_USER_CALLBACK; -+ op->callback = callback; -+ op->data_size = size; -+ memcpy(op->data, data, size); -+ -+ cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); -+} -+ - static void wined3d_cs_emit_stop(struct wined3d_cs *cs) - { - struct wined3d_cs_stop *op; -@@ -2893,6 +2932,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void - /* WINED3D_CS_OP_GENERATE_MIPMAPS */ wined3d_cs_exec_generate_mipmaps, - /* WINED3D_CS_OP_EXECUTE_COMMAND_LIST */ wined3d_cs_exec_execute_command_list, - /* WINED3D_CS_OP_GL_TEXTURE_CALLBACK */ wined3d_cs_exec_gl_texture_callback, -+ /* WINED3D_CS_OP_USER_CALLBACK */ wined3d_cs_exec_user_callback, - }; - - static void *wined3d_cs_st_require_space(struct wined3d_device_context *context, -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index 484130b3103..286d4d3acf5 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -6320,3 +6320,11 @@ LRESULT device_process_message(struct wined3d_device *device, HWND window, BOOL - else - return CallWindowProcA(proc, window, message, wparam, lparam); - } -+ -+void CDECL wined3d_device_run_cs_callback(struct wined3d_device *device, -+ wined3d_cs_callback callback, const void *data, unsigned int size) -+{ -+ TRACE("device %p, callback %p, data %p, size %u.\n", device, callback, data, size); -+ -+ wined3d_cs_emit_user_callback(device->cs, callback, data, size); -+} -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 756d47ef20d..602647b1e94 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -4764,6 +4764,8 @@ static inline void wined3d_cs_finish(struct wined3d_cs *cs, enum wined3d_cs_queu - - void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_texture *texture, - wined3d_gl_texture_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; -+void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, -+ wined3d_cs_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; - - static inline void wined3d_device_context_push_constants(struct wined3d_device_context *context, - enum wined3d_push_constants p, unsigned int start_idx, unsigned int count, const void *constants) -diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h -index 2123e857a52..39689bdb4e1 100644 ---- a/include/wine/wined3d.h -+++ b/include/wine/wined3d.h -@@ -2974,6 +2974,11 @@ typedef void (__cdecl *wined3d_gl_texture_callback)(unsigned int gl_texture, con - void __cdecl wined3d_access_gl_texture(struct wined3d_texture *texture, - wined3d_gl_texture_callback callback, const void *data, unsigned int size); - -+typedef void (__cdecl *wined3d_cs_callback)(const void *data, unsigned int size); -+ -+void __cdecl wined3d_device_run_cs_callback(struct wined3d_device *device, -+ wined3d_cs_callback callback, const void *data, unsigned int size); -+ - /* Return the integer base-2 logarithm of x. Undefined for x == 0. */ - static inline unsigned int wined3d_log2i(unsigned int x) - { --- -2.30.2 - -From 434e12794d7dda50554dbcf781af282816d39121 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Wed, 4 Apr 2018 17:05:37 +0200 -Subject: [PATCH 03/12] d3d11: Add IWineD3D11Texture2D interface. - ---- - dlls/d3d11/d3d11_private.h | 4 +- - dlls/d3d11/device.c | 4 +- - dlls/d3d11/texture.c | 65 +++++++++++++++++++++----------- - include/Makefile.in | 1 + - include/wine/wined3d-interop.idl | 31 +++++++++++++++ - 5 files changed, 80 insertions(+), 25 deletions(-) - create mode 100644 include/wine/wined3d-interop.idl - -diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h -index 1a8cdc6d77c..2b1809726ca 100644 ---- a/dlls/d3d11/d3d11_private.h -+++ b/dlls/d3d11/d3d11_private.h -@@ -39,6 +39,8 @@ - #include "wine/winedxgi.h" - #include "wine/rbtree.h" - -+#include "wine/wined3d-interop.h" -+ - #define MAKE_TAG(ch0, ch1, ch2, ch3) \ - ((DWORD)(ch0) | ((DWORD)(ch1) << 8) | \ - ((DWORD)(ch2) << 16) | ((DWORD)(ch3) << 24 )) -@@ -144,7 +146,7 @@ struct d3d_texture1d *unsafe_impl_from_ID3D10Texture1D(ID3D10Texture1D *iface) D - /* ID3D11Texture2D, ID3D10Texture2D */ - struct d3d_texture2d - { -- ID3D11Texture2D ID3D11Texture2D_iface; -+ IWineD3D11Texture2D ID3D11Texture2D_iface; - ID3D10Texture2D ID3D10Texture2D_iface; - LONG refcount; - -diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c -index 0819918b2a1..41967dd0a1c 100644 ---- a/dlls/d3d11/device.c -+++ b/dlls/d3d11/device.c -@@ -3165,7 +3165,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_device_CreateTexture2D(ID3D11Device2 *ifa - if (FAILED(hr = d3d_texture2d_create(device, desc, data, &object))) - return hr; - -- *texture = &object->ID3D11Texture2D_iface; -+ *texture = (ID3D11Texture2D *)&object->ID3D11Texture2D_iface; - - return S_OK; - } -@@ -6594,7 +6594,7 @@ static HRESULT CDECL device_parent_create_swapchain_texture(struct wined3d_devic - - *wined3d_texture = texture->wined3d_texture; - wined3d_texture_incref(*wined3d_texture); -- ID3D11Texture2D_Release(&texture->ID3D11Texture2D_iface); -+ IWineD3D11Texture2D_Release(&texture->ID3D11Texture2D_iface); - - return S_OK; - } -diff --git a/dlls/d3d11/texture.c b/dlls/d3d11/texture.c -index 061bbb09795..dd21c6d7f08 100644 ---- a/dlls/d3d11/texture.c -+++ b/dlls/d3d11/texture.c -@@ -518,13 +518,20 @@ HRESULT d3d_texture1d_create(struct d3d_device *device, const D3D11_TEXTURE1D_DE - - /* ID3D11Texture2D methods */ - --static HRESULT STDMETHODCALLTYPE d3d11_texture2d_QueryInterface(ID3D11Texture2D *iface, REFIID riid, void **object) -+static inline struct d3d_texture2d *impl_from_IWineD3D11Texture2D(IWineD3D11Texture2D *iface) - { -- struct d3d_texture2d *texture = impl_from_ID3D11Texture2D(iface); -+ return CONTAINING_RECORD(iface, struct d3d_texture2d, ID3D11Texture2D_iface); -+} -+ -+static HRESULT STDMETHODCALLTYPE d3d11_texture2d_QueryInterface(IWineD3D11Texture2D *iface, -+ REFIID riid, void **object) -+{ -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - - TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object); - -- if (IsEqualGUID(riid, &IID_ID3D11Texture2D) -+ if (IsEqualGUID(riid, &IID_IWineD3D11Texture2D) -+ || IsEqualGUID(riid, &IID_ID3D11Texture2D) - || IsEqualGUID(riid, &IID_ID3D11Resource) - || IsEqualGUID(riid, &IID_ID3D11DeviceChild) - || IsEqualGUID(riid, &IID_IUnknown)) -@@ -554,9 +561,9 @@ static HRESULT STDMETHODCALLTYPE d3d11_texture2d_QueryInterface(ID3D11Texture2D - return E_NOINTERFACE; - } - --static ULONG STDMETHODCALLTYPE d3d11_texture2d_AddRef(ID3D11Texture2D *iface) -+static ULONG STDMETHODCALLTYPE d3d11_texture2d_AddRef(IWineD3D11Texture2D *iface) - { -- struct d3d_texture2d *texture = impl_from_ID3D11Texture2D(iface); -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - ULONG refcount = InterlockedIncrement(&texture->refcount); - - TRACE("%p increasing refcount to %u.\n", texture, refcount); -@@ -572,9 +579,9 @@ static ULONG STDMETHODCALLTYPE d3d11_texture2d_AddRef(ID3D11Texture2D *iface) - return refcount; - } - --static ULONG STDMETHODCALLTYPE d3d11_texture2d_Release(ID3D11Texture2D *iface) -+static ULONG STDMETHODCALLTYPE d3d11_texture2d_Release(IWineD3D11Texture2D *iface) - { -- struct d3d_texture2d *texture = impl_from_ID3D11Texture2D(iface); -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - ULONG refcount = InterlockedDecrement(&texture->refcount); - - TRACE("%p decreasing refcount to %u.\n", texture, refcount); -@@ -594,9 +601,9 @@ static ULONG STDMETHODCALLTYPE d3d11_texture2d_Release(ID3D11Texture2D *iface) - return refcount; - } - --static void STDMETHODCALLTYPE d3d11_texture2d_GetDevice(ID3D11Texture2D *iface, ID3D11Device **device) -+static void STDMETHODCALLTYPE d3d11_texture2d_GetDevice(IWineD3D11Texture2D *iface, ID3D11Device **device) - { -- struct d3d_texture2d *texture = impl_from_ID3D11Texture2D(iface); -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - - TRACE("iface %p, device %p.\n", iface, device); - -@@ -604,10 +611,10 @@ static void STDMETHODCALLTYPE d3d11_texture2d_GetDevice(ID3D11Texture2D *iface, - ID3D11Device_AddRef(*device); - } - --static HRESULT STDMETHODCALLTYPE d3d11_texture2d_GetPrivateData(ID3D11Texture2D *iface, -+static HRESULT STDMETHODCALLTYPE d3d11_texture2d_GetPrivateData(IWineD3D11Texture2D *iface, - REFGUID guid, UINT *data_size, void *data) - { -- struct d3d_texture2d *texture = impl_from_ID3D11Texture2D(iface); -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - IDXGISurface *dxgi_surface; - HRESULT hr; - -@@ -624,10 +631,10 @@ static HRESULT STDMETHODCALLTYPE d3d11_texture2d_GetPrivateData(ID3D11Texture2D - return d3d_get_private_data(&texture->private_store, guid, data_size, data); - } - --static HRESULT STDMETHODCALLTYPE d3d11_texture2d_SetPrivateData(ID3D11Texture2D *iface, -+static HRESULT STDMETHODCALLTYPE d3d11_texture2d_SetPrivateData(IWineD3D11Texture2D *iface, - REFGUID guid, UINT data_size, const void *data) - { -- struct d3d_texture2d *texture = impl_from_ID3D11Texture2D(iface); -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - IDXGISurface *dxgi_surface; - HRESULT hr; - -@@ -644,10 +651,10 @@ static HRESULT STDMETHODCALLTYPE d3d11_texture2d_SetPrivateData(ID3D11Texture2D - return d3d_set_private_data(&texture->private_store, guid, data_size, data); - } - --static HRESULT STDMETHODCALLTYPE d3d11_texture2d_SetPrivateDataInterface(ID3D11Texture2D *iface, -+static HRESULT STDMETHODCALLTYPE d3d11_texture2d_SetPrivateDataInterface(IWineD3D11Texture2D *iface, - REFGUID guid, const IUnknown *data) - { -- struct d3d_texture2d *texture = impl_from_ID3D11Texture2D(iface); -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - IDXGISurface *dxgi_surface; - HRESULT hr; - -@@ -664,7 +671,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_texture2d_SetPrivateDataInterface(ID3D11T - return d3d_set_private_data_interface(&texture->private_store, guid, data); - } - --static void STDMETHODCALLTYPE d3d11_texture2d_GetType(ID3D11Texture2D *iface, -+static void STDMETHODCALLTYPE d3d11_texture2d_GetType(IWineD3D11Texture2D *iface, - D3D11_RESOURCE_DIMENSION *resource_dimension) - { - TRACE("iface %p, resource_dimension %p.\n", iface, resource_dimension); -@@ -672,21 +679,21 @@ static void STDMETHODCALLTYPE d3d11_texture2d_GetType(ID3D11Texture2D *iface, - *resource_dimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D; - } - --static void STDMETHODCALLTYPE d3d11_texture2d_SetEvictionPriority(ID3D11Texture2D *iface, UINT eviction_priority) -+static void STDMETHODCALLTYPE d3d11_texture2d_SetEvictionPriority(IWineD3D11Texture2D *iface, UINT eviction_priority) - { - FIXME("iface %p, eviction_priority %#x stub!\n", iface, eviction_priority); - } - --static UINT STDMETHODCALLTYPE d3d11_texture2d_GetEvictionPriority(ID3D11Texture2D *iface) -+static UINT STDMETHODCALLTYPE d3d11_texture2d_GetEvictionPriority(IWineD3D11Texture2D *iface) - { - FIXME("iface %p stub!\n", iface); - - return 0; - } - --static void STDMETHODCALLTYPE d3d11_texture2d_GetDesc(ID3D11Texture2D *iface, D3D11_TEXTURE2D_DESC *desc) -+static void STDMETHODCALLTYPE d3d11_texture2d_GetDesc(IWineD3D11Texture2D *iface, D3D11_TEXTURE2D_DESC *desc) - { -- struct d3d_texture2d *texture = impl_from_ID3D11Texture2D(iface); -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - struct wined3d_resource_desc wined3d_desc; - - TRACE("iface %p, desc %p.\n", iface, desc); -@@ -708,7 +715,19 @@ static void STDMETHODCALLTYPE d3d11_texture2d_GetDesc(ID3D11Texture2D *iface, D3 - desc->SampleDesc.Quality = wined3d_desc.multisample_quality; - } - --static const struct ID3D11Texture2DVtbl d3d11_texture2d_vtbl = -+static void STDMETHODCALLTYPE d3d11_texture2d_access_gl_texture(IWineD3D11Texture2D *iface, -+ gl_texture_callback callback, const void *data, unsigned int size) -+{ -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); -+ -+ TRACE("iface %p, callback %p, data %p, size %u.\n", iface, callback, data, size); -+ -+ wined3d_mutex_lock(); -+ wined3d_access_gl_texture(texture->wined3d_texture, callback, data, size); -+ wined3d_mutex_unlock(); -+} -+ -+static const struct IWineD3D11Texture2DVtbl d3d11_texture2d_vtbl = - { - /* IUnknown methods */ - d3d11_texture2d_QueryInterface, -@@ -725,13 +744,15 @@ static const struct ID3D11Texture2DVtbl d3d11_texture2d_vtbl = - d3d11_texture2d_GetEvictionPriority, - /* ID3D11Texture2D methods */ - d3d11_texture2d_GetDesc, -+ /* IWineD3D11Texture methods */ -+ d3d11_texture2d_access_gl_texture, - }; - - struct d3d_texture2d *unsafe_impl_from_ID3D11Texture2D(ID3D11Texture2D *iface) - { - if (!iface) - return NULL; -- assert(iface->lpVtbl == &d3d11_texture2d_vtbl); -+ assert(iface->lpVtbl == (void *)&d3d11_texture2d_vtbl); - return CONTAINING_RECORD(iface, struct d3d_texture2d, ID3D11Texture2D_iface); - } - -diff --git a/include/Makefile.in b/include/Makefile.in -index 9822bce6bdd..d9b646f7de1 100644 ---- a/include/Makefile.in -+++ b/include/Makefile.in -@@ -770,6 +770,7 @@ SOURCES = \ - wine/itss.idl \ - wine/orpc.idl \ - wine/svcctl.idl \ -+ wine/wined3d-interop.idl \ - wine/winedxgi.idl \ - winerror.h \ - winevt.h \ -diff --git a/include/wine/wined3d-interop.idl b/include/wine/wined3d-interop.idl -new file mode 100644 -index 00000000000..884baf958c2 ---- /dev/null -+++ b/include/wine/wined3d-interop.idl -@@ -0,0 +1,31 @@ -+/* -+ * Copyright 2018 Józef Kucia 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 -+ */ -+ -+typedef void (__cdecl *gl_texture_callback)(unsigned int gl_texture, const void *data, unsigned int data_size); -+ -+import "d3d11.idl"; -+ -+[ -+ object, -+ local, -+ uuid(267dc993-d15e-4015-aaac-b7559e226cc3) -+] -+interface IWineD3D11Texture2D : ID3D11Texture2D -+{ -+ void access_gl_texture(gl_texture_callback callback, const void *data, unsigned int data_size); -+} --- -2.30.2 - -From 17c027811a6641eea3298f5cb24c69c796dca328 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Wed, 4 Apr 2018 17:05:37 +0200 -Subject: [PATCH 04/12] d3d11: Add IWineD3D11Device interface. - ---- - dlls/d3d11/d3d11_private.h | 1 + - dlls/d3d11/device.c | 52 ++++++++++++++++++++++++++++++++ - include/wine/wined3d-interop.idl | 12 ++++++++ - 3 files changed, 65 insertions(+) - -diff --git a/dlls/d3d11/d3d11_private.h b/dlls/d3d11/d3d11_private.h -index 2b1809726ca..ec0bd79fdd5 100644 ---- a/dlls/d3d11/d3d11_private.h -+++ b/dlls/d3d11/d3d11_private.h -@@ -564,6 +564,7 @@ struct d3d_device - ID3D10Multithread ID3D10Multithread_iface; - IWineDXGIDeviceParent IWineDXGIDeviceParent_iface; - IUnknown *outer_unk; -+ IWineD3D11Device IWineD3D11Device_iface; - LONG refcount; - - BOOL d3d11_only; -diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c -index 41967dd0a1c..887e7de00e9 100644 ---- a/dlls/d3d11/device.c -+++ b/dlls/d3d11/device.c -@@ -3119,6 +3119,53 @@ static ULONG STDMETHODCALLTYPE d3d11_device_Release(ID3D11Device2 *iface) - return IUnknown_Release(device->outer_unk); - } - -+/* IWineD3D11Device methods */ -+ -+static inline struct d3d_device *impl_from_IWineD3D11Device(IWineD3D11Device *iface) -+{ -+ return CONTAINING_RECORD(iface, struct d3d_device, IWineD3D11Device_iface); -+} -+ -+static HRESULT STDMETHODCALLTYPE wine_device_QueryInterface(IWineD3D11Device *iface, REFIID riid, void **out) -+{ -+ struct d3d_device *device = impl_from_IWineD3D11Device(iface); -+ return IUnknown_QueryInterface(device->outer_unk, riid, out); -+} -+ -+static ULONG STDMETHODCALLTYPE wine_device_AddRef(IWineD3D11Device *iface) -+{ -+ struct d3d_device *device = impl_from_IWineD3D11Device(iface); -+ return IUnknown_AddRef(device->outer_unk); -+} -+ -+static ULONG STDMETHODCALLTYPE wine_device_Release(IWineD3D11Device *iface) -+{ -+ struct d3d_device *device = impl_from_IWineD3D11Device(iface); -+ return IUnknown_Release(device->outer_unk); -+} -+ -+static void STDMETHODCALLTYPE wine_device_run_on_command_stream(IWineD3D11Device *iface, -+ user_cs_callback callback, const void *data, unsigned int data_size) -+{ -+ struct d3d_device *device = impl_from_IWineD3D11Device(iface); -+ -+ TRACE("iface %p, callback %p, data %p, data_size %u.\n", iface, callback, data, data_size); -+ -+ wined3d_mutex_lock(); -+ wined3d_device_run_cs_callback(device->wined3d_device, callback, data, data_size); -+ wined3d_mutex_unlock(); -+} -+ -+static const struct IWineD3D11DeviceVtbl wine_device_vtbl = -+{ -+ /* IUnknown methods */ -+ wine_device_QueryInterface, -+ wine_device_AddRef, -+ wine_device_Release, -+ /* IWineD3D11Device methods */ -+ wine_device_run_on_command_stream, -+}; -+ - static HRESULT STDMETHODCALLTYPE d3d11_device_CreateBuffer(ID3D11Device2 *iface, const D3D11_BUFFER_DESC *desc, - const D3D11_SUBRESOURCE_DATA *data, ID3D11Buffer **buffer) - { -@@ -4264,6 +4311,10 @@ static HRESULT STDMETHODCALLTYPE d3d_device_inner_QueryInterface(IUnknown *iface - { - *out = &device->IWineDXGIDeviceParent_iface; - } -+ else if (IsEqualGUID(riid, &IID_IWineD3D11Device)) -+ { -+ *out = &device->IWineD3D11Device_iface; -+ } - else - { - WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); -@@ -6648,6 +6699,7 @@ void d3d_device_init(struct d3d_device *device, void *outer_unknown) - device->ID3D10Device1_iface.lpVtbl = &d3d10_device1_vtbl; - device->ID3D10Multithread_iface.lpVtbl = &d3d10_multithread_vtbl; - device->IWineDXGIDeviceParent_iface.lpVtbl = &d3d_dxgi_device_parent_vtbl; -+ device->IWineD3D11Device_iface.lpVtbl = &wine_device_vtbl; - device->device_parent.ops = &d3d_wined3d_device_parent_ops; - device->refcount = 1; - /* COM aggregation always takes place */ -diff --git a/include/wine/wined3d-interop.idl b/include/wine/wined3d-interop.idl -index 884baf958c2..d5c91623b3c 100644 ---- a/include/wine/wined3d-interop.idl -+++ b/include/wine/wined3d-interop.idl -@@ -29,3 +29,15 @@ interface IWineD3D11Texture2D : ID3D11Texture2D - { - void access_gl_texture(gl_texture_callback callback, const void *data, unsigned int data_size); - } -+ -+typedef void (__cdecl *user_cs_callback)(const void *data, unsigned int data_size); -+ -+[ -+ object, -+ local, -+ uuid(8f02de7e-d55d-457b-9423-83456e49c58a) -+] -+interface IWineD3D11Device : IUnknown -+{ -+ void run_on_command_stream(user_cs_callback callback, const void *data, unsigned int data_size); -+} --- -2.30.2 - -From af8a3f1e0c505ecb0a2f6a899989431e85013f74 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Thu, 19 Apr 2018 14:04:49 +0200 -Subject: [PATCH 05/12] wined3d: Implement wined3d_device_wait_idle(). - ---- - dlls/d3d11/device.c | 12 ++++++++++++ - dlls/wined3d/cs.c | 20 ++++++++++++++++++++ - dlls/wined3d/device.c | 7 +++++++ - dlls/wined3d/wined3d_private.h | 1 + - include/wine/wined3d-interop.idl | 2 ++ - include/wine/wined3d.h | 1 + - 6 files changed, 43 insertions(+) - -diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c -index 887e7de00e9..1ff3f32f2c2 100644 ---- a/dlls/d3d11/device.c -+++ b/dlls/d3d11/device.c -@@ -3156,6 +3156,17 @@ static void STDMETHODCALLTYPE wine_device_run_on_command_stream(IWineD3D11Device - wined3d_mutex_unlock(); - } - -+static void STDMETHODCALLTYPE wine_device_wait_idle(IWineD3D11Device *iface) -+{ -+ struct d3d_device *device = impl_from_IWineD3D11Device(iface); -+ -+ TRACE("iface %p.\n", iface); -+ -+ wined3d_mutex_lock(); -+ wined3d_device_wait_idle(device->wined3d_device); -+ wined3d_mutex_unlock(); -+} -+ - static const struct IWineD3D11DeviceVtbl wine_device_vtbl = - { - /* IUnknown methods */ -@@ -3164,6 +3175,7 @@ static const struct IWineD3D11DeviceVtbl wine_device_vtbl = - wine_device_Release, - /* IWineD3D11Device methods */ - wine_device_run_on_command_stream, -+ wine_device_wait_idle, - }; - - static HRESULT STDMETHODCALLTYPE d3d11_device_CreateBuffer(ID3D11Device2 *iface, const D3D11_BUFFER_DESC *desc, -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index cf55385c3c1..0eeabdb6640 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -476,6 +477,11 @@ struct wined3d_cs_user_callback - BYTE data[1]; - }; - -+struct wined3d_cs_wait_idle -+{ -+ enum wined3d_cs_op opcode; -+}; -+ - struct wined3d_cs_stop - { - enum wined3d_cs_op opcode; -@@ -2788,6 +2794,19 @@ void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, - cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); - } - -+static void wined3d_cs_exec_wait_idle(struct wined3d_cs *cs, const void *data) {} -+ -+void wined3d_cs_emit_wait_idle(struct wined3d_cs *cs) -+{ -+ struct wined3d_cs_wait_idle *op; -+ -+ op = cs->c.ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); -+ op->opcode = WINED3D_CS_OP_WAIT_IDLE; -+ -+ cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); -+ cs->c.ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT); -+} -+ - static void wined3d_cs_emit_stop(struct wined3d_cs *cs) - { - struct wined3d_cs_stop *op; -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index 286d4d3acf5..a3e41cb38ef 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -6328,3 +6328,10 @@ void CDECL wined3d_device_run_cs_callback(struct wined3d_device *device, - - wined3d_cs_emit_user_callback(device->cs, callback, data, size); - } -+ -+void CDECL wined3d_device_wait_idle(struct wined3d_device *device) -+{ -+ TRACE("device %p.\n", device); -+ -+ wined3d_cs_emit_wait_idle(device->cs); -+} -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 602647b1e94..8a38f6d4925 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -4766,6 +4766,7 @@ void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_t - wined3d_gl_texture_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; - void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, - wined3d_cs_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; -+void wined3d_cs_emit_wait_idle(struct wined3d_cs *cs) DECLSPEC_HIDDEN; - - static inline void wined3d_device_context_push_constants(struct wined3d_device_context *context, - enum wined3d_push_constants p, unsigned int start_idx, unsigned int count, const void *constants) -diff --git a/include/wine/wined3d-interop.idl b/include/wine/wined3d-interop.idl -index d5c91623b3c..6f8ea3770e3 100644 ---- a/include/wine/wined3d-interop.idl -+++ b/include/wine/wined3d-interop.idl -@@ -40,4 +40,6 @@ typedef void (__cdecl *user_cs_callback)(const void *data, unsigned int data_siz - interface IWineD3D11Device : IUnknown - { - void run_on_command_stream(user_cs_callback callback, const void *data, unsigned int data_size); -+ -+ void wait_idle(); - } -diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h -index 39689bdb4e1..c90a71dbd5b 100644 ---- a/include/wine/wined3d.h -+++ b/include/wine/wined3d.h -@@ -2978,6 +2978,7 @@ typedef void (__cdecl *wined3d_cs_callback)(const void *data, unsigned int size) - - void __cdecl wined3d_device_run_cs_callback(struct wined3d_device *device, - wined3d_cs_callback callback, const void *data, unsigned int size); -+void __cdecl wined3d_device_wait_idle(struct wined3d_device *device); - - /* Return the integer base-2 logarithm of x. Undefined for x == 0. */ - static inline unsigned int wined3d_log2i(unsigned int x) --- -2.30.2 - -From 9c84c7ec7714dc3f0f9038b60735788f9d37d77c Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 1 May 2018 15:06:30 -0500 -Subject: [PATCH 06/12] wined3d: Support retrieving depth texture in GL texture - callback - ---- - dlls/d3d11/texture.c | 20 +++++++++++++++++--- - dlls/wined3d/cs.c | 14 ++++++++++++-- - dlls/wined3d/texture.c | 7 ++++--- - dlls/wined3d/wined3d_private.h | 3 ++- - include/wine/wined3d-interop.idl | 4 ++-- - include/wine/wined3d.h | 4 ++-- - 6 files changed, 39 insertions(+), 13 deletions(-) - -diff --git a/dlls/d3d11/texture.c b/dlls/d3d11/texture.c -index dd21c6d7f08..c46aae99a24 100644 ---- a/dlls/d3d11/texture.c -+++ b/dlls/d3d11/texture.c -@@ -716,14 +716,28 @@ static void STDMETHODCALLTYPE d3d11_texture2d_GetDesc(IWineD3D11Texture2D *iface - } - - static void STDMETHODCALLTYPE d3d11_texture2d_access_gl_texture(IWineD3D11Texture2D *iface, -- gl_texture_callback callback, const void *data, unsigned int size) -+ gl_texture_callback callback, IUnknown *depth_unk, const void *data, unsigned int size) - { -- struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface), *depth_tex = NULL; -+ IWineD3D11Texture2D *depth_d3d11 = NULL; - - TRACE("iface %p, callback %p, data %p, size %u.\n", iface, callback, data, size); - - wined3d_mutex_lock(); -- wined3d_access_gl_texture(texture->wined3d_texture, callback, data, size); -+ -+ if (depth_unk) -+ { -+ HRESULT hr; -+ hr = IUnknown_QueryInterface(depth_unk, &IID_IWineD3D11Texture2D, (void**)&depth_d3d11); -+ if(hr == S_OK) -+ depth_tex = impl_from_IWineD3D11Texture2D(depth_d3d11); -+ } -+ -+ wined3d_access_gl_texture(texture->wined3d_texture, callback, depth_tex ? depth_tex->wined3d_texture : NULL, data, size); -+ -+ if (depth_d3d11) -+ IWineD3D11Texture2D_Release(depth_d3d11); -+ - wined3d_mutex_unlock(); - } - -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index 0eeabdb6640..edfdeecee3c 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -464,6 +464,7 @@ struct wined3d_cs_gl_texture_callback - { - enum wined3d_cs_op opcode; - struct wined3d_texture *texture; -+ struct wined3d_texture *depth_texture; - wined3d_gl_texture_callback callback; - unsigned int data_size; - BYTE data[1]; -@@ -2727,6 +2728,7 @@ static void wined3d_cs_exec_gl_texture_callback(struct wined3d_cs *cs, const voi - { - const struct wined3d_cs_gl_texture_callback *op = data; - struct wined3d_texture_gl *texture = wined3d_texture_gl(op->texture); -+ struct wined3d_texture_gl *depth_texture = wined3d_texture_gl(op->depth_texture); - const struct wined3d_gl_info *gl_info; - struct wined3d_context *context; - -@@ -2734,8 +2736,12 @@ static void wined3d_cs_exec_gl_texture_callback(struct wined3d_cs *cs, const voi - gl_info = wined3d_context_gl(context)->gl_info; - - wined3d_texture_load_location(&texture->t, 0, context, WINED3D_LOCATION_TEXTURE_RGB); -+ if (depth_texture) -+ wined3d_texture_load_location(&depth_texture->t, 0, context, WINED3D_LOCATION_TEXTURE_RGB); - -- op->callback(texture->texture_rgb.name, op->data, op->data_size); -+ op->callback(texture->texture_rgb.name, -+ depth_texture ? depth_texture->texture_rgb.name : 0, -+ op->data, op->data_size); - - context_invalidate_compute_state(context, STATE_COMPUTE_SHADER_RESOURCE_BINDING); - context_invalidate_state(context, STATE_GRAPHICS_SHADER_RESOURCE_BINDING); -@@ -2744,17 +2750,21 @@ static void wined3d_cs_exec_gl_texture_callback(struct wined3d_cs *cs, const voi - - context_release(context); - -+ if (depth_texture) -+ wined3d_resource_release(&depth_texture->t.resource); - wined3d_resource_release(&texture->t.resource); - } - - void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_texture *texture, -- wined3d_gl_texture_callback callback, const void *data, unsigned int size) -+ wined3d_gl_texture_callback callback, struct wined3d_texture *depth_texture, -+ const void *data, unsigned int size) - { - struct wined3d_cs_gl_texture_callback *op; - - op = cs->c.ops->require_space(cs, sizeof(*op) + size, WINED3D_CS_QUEUE_DEFAULT); - op->opcode = WINED3D_CS_OP_GL_TEXTURE_CALLBACK; - op->texture = texture; -+ op->depth_texture = depth_texture; - op->callback = callback; - op->data_size = size; - memcpy(op->data, data, size); -diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c -index bdcd0b55ae6..b8fa5d7d3ae 100644 ---- a/dlls/wined3d/texture.c -+++ b/dlls/wined3d/texture.c -@@ -4575,13 +4575,14 @@ void wined3d_texture_download_from_texture(struct wined3d_texture *dst_texture, - } - - void CDECL wined3d_access_gl_texture(struct wined3d_texture *texture, -- wined3d_gl_texture_callback callback, const void *data, unsigned int size) -+ wined3d_gl_texture_callback callback, struct wined3d_texture *depth_texture, -+ const void *data, unsigned int size) - { - struct wined3d_device *device = texture->resource.device; - -- TRACE("texture %p, callback %p, data %p, size %u.\n", texture, callback, data, size); -+ TRACE("texture %p, depth_texture %p, callback %p, data %p, size %u.\n", texture, depth_texture, callback, data, size); - -- wined3d_cs_emit_gl_texture_callback(device->cs, texture, callback, data, size); -+ wined3d_cs_emit_gl_texture_callback(device->cs, texture, callback, depth_texture, data, size); - } - - static void wined3d_texture_no3d_upload_data(struct wined3d_context *context, -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 8a38f6d4925..a01ee1690c1 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -4763,7 +4763,8 @@ static inline void wined3d_cs_finish(struct wined3d_cs *cs, enum wined3d_cs_queu - } - - void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_texture *texture, -- wined3d_gl_texture_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; -+ wined3d_gl_texture_callback callback, struct wined3d_texture *depth_texture, -+ const void *data, unsigned int size) DECLSPEC_HIDDEN; - void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, - wined3d_cs_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; - void wined3d_cs_emit_wait_idle(struct wined3d_cs *cs) DECLSPEC_HIDDEN; -diff --git a/include/wine/wined3d-interop.idl b/include/wine/wined3d-interop.idl -index 6f8ea3770e3..c5395ccc0ed 100644 ---- a/include/wine/wined3d-interop.idl -+++ b/include/wine/wined3d-interop.idl -@@ -16,7 +16,7 @@ - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - --typedef void (__cdecl *gl_texture_callback)(unsigned int gl_texture, const void *data, unsigned int data_size); -+typedef void (__cdecl *gl_texture_callback)(unsigned int gl_texture, unsigned int gl_depth_texture, const void *data, unsigned int data_size); - - import "d3d11.idl"; - -@@ -27,7 +27,7 @@ import "d3d11.idl"; - ] - interface IWineD3D11Texture2D : ID3D11Texture2D - { -- void access_gl_texture(gl_texture_callback callback, const void *data, unsigned int data_size); -+ void access_gl_texture(gl_texture_callback callback, IUnknown *depth_texture, const void *data, unsigned int data_size); - } - - typedef void (__cdecl *user_cs_callback)(const void *data, unsigned int data_size); -diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h -index c90a71dbd5b..81235a7677c 100644 ---- a/include/wine/wined3d.h -+++ b/include/wine/wined3d.h -@@ -2969,10 +2969,10 @@ ULONG __cdecl wined3d_vertex_declaration_incref(struct wined3d_vertex_declaratio - HRESULT __cdecl wined3d_extract_shader_input_signature_from_dxbc(struct wined3d_shader_signature *signature, - const void *byte_code, SIZE_T byte_code_size); - --typedef void (__cdecl *wined3d_gl_texture_callback)(unsigned int gl_texture, const void *data, unsigned int size); -+typedef void (__cdecl *wined3d_gl_texture_callback)(unsigned int gl_texture, unsigned int gl_depth_texture, const void *data, unsigned int size); - - void __cdecl wined3d_access_gl_texture(struct wined3d_texture *texture, -- wined3d_gl_texture_callback callback, const void *data, unsigned int size); -+ wined3d_gl_texture_callback callback, struct wined3d_texture *depth_texture, const void *data, unsigned int size); - - typedef void (__cdecl *wined3d_cs_callback)(const void *data, unsigned int size); - --- -2.30.2 - -From d00f400da6cc085c207d0501944804ad63cb486b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Tue, 18 Sep 2018 23:10:14 +0200 -Subject: [PATCH 07/12] wined3d: Get rid of wined3d_cs_emit_wait_idle(). - ---- - dlls/wined3d/cs.c | 15 --------------- - dlls/wined3d/device.c | 2 +- - dlls/wined3d/wined3d_private.h | 1 - - 3 files changed, 1 insertion(+), 17 deletions(-) - -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index edfdeecee3c..298f74c46c0 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -2804,19 +2803,6 @@ void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, - cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); - } - --static void wined3d_cs_exec_wait_idle(struct wined3d_cs *cs, const void *data) {} -- --void wined3d_cs_emit_wait_idle(struct wined3d_cs *cs) --{ -- struct wined3d_cs_wait_idle *op; -- -- op = cs->c.ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); -- op->opcode = WINED3D_CS_OP_WAIT_IDLE; -- -- cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); -- cs->c.ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT); --} -- - static void wined3d_cs_emit_stop(struct wined3d_cs *cs) - { - struct wined3d_cs_stop *op; -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index a3e41cb38ef..9ec837e837d 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -6333,5 +6333,5 @@ void CDECL wined3d_device_wait_idle(struct wined3d_device *device) - { - TRACE("device %p.\n", device); - -- wined3d_cs_emit_wait_idle(device->cs); -+ device->cs->c.ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT); - } -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index a01ee1690c1..0a18d909c5e 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -4767,7 +4767,6 @@ void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_t - const void *data, unsigned int size) DECLSPEC_HIDDEN; - void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, - wined3d_cs_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; --void wined3d_cs_emit_wait_idle(struct wined3d_cs *cs) DECLSPEC_HIDDEN; - - static inline void wined3d_device_context_push_constants(struct wined3d_device_context *context, - enum wined3d_push_constants p, unsigned int start_idx, unsigned int count, const void *constants) --- -2.30.2 - -From 08d1dd39399a79f3f701cbcb37b733a5f48af5fa Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Tue, 18 Sep 2018 22:04:21 +0200 -Subject: [PATCH 08/12] wined3d: Implement synchronous texture access. - -For vrclient. ---- - dlls/d3d11/texture.c | 15 ++++ - dlls/wined3d/cs.c | 48 ++++++++++++ - dlls/wined3d/device.c | 2 + - dlls/wined3d/texture.c | 123 +++++++++++++++++++++++++++++++ - dlls/wined3d/wined3d_private.h | 15 ++++ - include/wine/wined3d-interop.idl | 2 + - include/wine/wined3d.h | 2 + - 7 files changed, 207 insertions(+) - -diff --git a/dlls/d3d11/texture.c b/dlls/d3d11/texture.c -index c46aae99a24..7f7e8254225 100644 ---- a/dlls/d3d11/texture.c -+++ b/dlls/d3d11/texture.c -@@ -741,6 +741,20 @@ static void STDMETHODCALLTYPE d3d11_texture2d_access_gl_texture(IWineD3D11Textur - wined3d_mutex_unlock(); - } - -+static unsigned int STDMETHODCALLTYPE d3d11_texture2d_get_gl_texture(IWineD3D11Texture2D *iface) -+{ -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); -+ unsigned int id; -+ -+ TRACE("iface %p.\n", iface); -+ -+ wined3d_mutex_lock(); -+ id = wined3d_get_gl_texture(texture->wined3d_texture); -+ wined3d_mutex_unlock(); -+ -+ return id; -+} -+ - static const struct IWineD3D11Texture2DVtbl d3d11_texture2d_vtbl = - { - /* IUnknown methods */ -@@ -760,6 +774,7 @@ static const struct IWineD3D11Texture2DVtbl d3d11_texture2d_vtbl = - d3d11_texture2d_GetDesc, - /* IWineD3D11Texture methods */ - d3d11_texture2d_access_gl_texture, -+ d3d11_texture2d_get_gl_texture, - }; - - struct d3d_texture2d *unsafe_impl_from_ID3D11Texture2D(ID3D11Texture2D *iface) -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index 298f74c46c0..511883924a1 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -79,6 +79,7 @@ enum wined3d_cs_op - WINED3D_CS_OP_EXECUTE_COMMAND_LIST, - WINED3D_CS_OP_GL_TEXTURE_CALLBACK, - WINED3D_CS_OP_USER_CALLBACK, -+ WINED3D_CS_OP_FENCE, - WINED3D_CS_OP_STOP, - }; - -@@ -482,6 +483,12 @@ struct wined3d_cs_wait_idle - enum wined3d_cs_op opcode; - }; - -+struct wined3d_cs_fence -+{ -+ enum wined3d_cs_op opcode; -+ GLsync *fence; -+}; -+ - struct wined3d_cs_stop - { - enum wined3d_cs_op opcode; -@@ -2803,6 +2810,46 @@ void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, - cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); - } - -+static void wined3d_cs_exec_fence(struct wined3d_cs *cs, const void *data) -+{ -+ const struct wined3d_cs_fence *op = data; -+ const struct wined3d_gl_info *gl_info; -+ struct wined3d_context *context; -+ GLsync fence; -+ -+ context = context_acquire(cs->c.device, NULL, 0); -+ gl_info = wined3d_context_gl(context)->gl_info; -+ -+ fence = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); -+ wined3d_context_gl(context)->gl_info->gl_ops.gl.p_glFlush(); -+ -+ *op->fence = fence; -+ -+ checkGLcall("fence"); -+ -+ context_release(context); -+} -+ -+static GLsync wined3d_cs_emit_fence(struct wined3d_cs *cs) -+{ -+ struct wined3d_cs_fence *op; -+ GLsync fence; -+ -+ op = cs->c.ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); -+ op->opcode = WINED3D_CS_OP_FENCE; -+ op->fence = &fence; -+ -+ cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); -+ cs->c.ops->finish(cs, WINED3D_CS_QUEUE_DEFAULT); -+ -+ return fence; -+} -+ -+GLsync wined3d_cs_synchronize(struct wined3d_cs *cs) -+{ -+ return wined3d_cs_emit_fence(cs); -+} -+ - static void wined3d_cs_emit_stop(struct wined3d_cs *cs) - { - struct wined3d_cs_stop *op; -@@ -2918,6 +2965,7 @@ static void (* const wined3d_cs_op_handlers[])(struct wined3d_cs *cs, const void - /* WINED3D_CS_OP_EXECUTE_COMMAND_LIST */ wined3d_cs_exec_execute_command_list, - /* WINED3D_CS_OP_GL_TEXTURE_CALLBACK */ wined3d_cs_exec_gl_texture_callback, - /* WINED3D_CS_OP_USER_CALLBACK */ wined3d_cs_exec_user_callback, -+ /* WINED3D_CS_OP_FENCE */ wined3d_cs_exec_fence, - }; - - static void *wined3d_cs_st_require_space(struct wined3d_device_context *context, -diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c -index 9ec837e837d..9d042f4d0e1 100644 ---- a/dlls/wined3d/device.c -+++ b/dlls/wined3d/device.c -@@ -218,6 +218,8 @@ void wined3d_device_cleanup(struct wined3d_device *device) - if (device->swapchain_count) - wined3d_device_uninit_3d(device); - -+ wined3d_destroy_gl_vr_context(&device->vr_context); -+ - wined3d_cs_destroy(device->cs); - - for (i = 0; i < ARRAY_SIZE(device->multistate_funcs); ++i) -diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c -index b8fa5d7d3ae..25c5e57fca0 100644 ---- a/dlls/wined3d/texture.c -+++ b/dlls/wined3d/texture.c -@@ -4585,6 +4585,129 @@ void CDECL wined3d_access_gl_texture(struct wined3d_texture *texture, - wined3d_cs_emit_gl_texture_callback(device->cs, texture, callback, depth_texture, data, size); - } - -+static const struct wined3d_gl_info *wined3d_prepare_vr_gl_context(struct wined3d_device *device) -+{ -+ const struct wined3d_adapter *adapter = device->adapter; -+ const struct wined3d_gl_info *gl_info = &adapter->gl_info; -+ struct wined3d_vr_gl_context *ctx = &device->vr_context; -+ PIXELFORMATDESCRIPTOR pfd; -+ int pixel_format; -+ HGLRC share_ctx; -+ -+ if (ctx->gl_info) -+ return gl_info; -+ -+ TRACE("Creating GL context.\n"); -+ -+ if (!gl_info->p_wglCreateContextAttribsARB) -+ { -+ ERR("wglCreateContextAttribsARB is not supported.\n"); -+ return NULL; -+ } -+ -+ if (!gl_info->supported[ARB_SYNC]) -+ { -+ FIXME("ARB_sync is not supported.\n"); -+ return NULL; -+ } -+ -+ ctx->window = CreateWindowA(WINED3D_OPENGL_WINDOW_CLASS_NAME, "WineD3D VR window", -+ WS_OVERLAPPEDWINDOW, 10, 10, 10, 10, NULL, NULL, NULL, NULL); -+ if (!ctx->window) -+ { -+ ERR("Failed to create a window.\n"); -+ return NULL; -+ } -+ -+ ctx->dc = GetDC(ctx->window); -+ if (!ctx->dc) -+ { -+ ERR("Failed to get a DC.\n"); -+ goto fail; -+ } -+ -+ memset(&pfd, 0, sizeof(pfd)); -+ pfd.nSize = sizeof(pfd); -+ pfd.nVersion = 1; -+ pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW; -+ pfd.iPixelType = PFD_TYPE_RGBA; -+ pfd.cColorBits = 32; -+ pfd.iLayerType = PFD_MAIN_PLANE; -+ -+ if (!(pixel_format = ChoosePixelFormat(ctx->dc, &pfd))) -+ { -+ ERR("Failed to find a suitable pixel format.\n"); -+ goto fail; -+ } -+ DescribePixelFormat(ctx->dc, pixel_format, sizeof(pfd), &pfd); -+ SetPixelFormat(ctx->dc, pixel_format, &pfd); -+ -+ share_ctx = device->context_count ? wined3d_context_gl(device->contexts[0])->gl_ctx : NULL; -+ if (!(ctx->gl_ctx = context_create_wgl_attribs(gl_info, ctx->dc, share_ctx))) -+ { -+ WARN("Failed to create GL context for VR.\n"); -+ goto fail; -+ } -+ -+ if (!wglMakeCurrent(ctx->dc, ctx->gl_ctx)) -+ { -+ ERR("Failed to make GL context current.\n"); -+ goto fail; -+ } -+ -+ checkGLcall("create context"); -+ -+ ctx->gl_info = gl_info; -+ return gl_info; -+ -+fail: -+ if (ctx->gl_ctx) -+ wglDeleteContext(ctx->gl_ctx); -+ ctx->gl_ctx = NULL; -+ if (ctx->dc) -+ ReleaseDC(ctx->window, ctx->dc); -+ ctx->dc = NULL; -+ if (ctx->window) -+ DestroyWindow(ctx->window); -+ ctx->window = NULL; -+ return NULL; -+} -+ -+void wined3d_destroy_gl_vr_context(struct wined3d_vr_gl_context *ctx) -+{ -+ if (!ctx->gl_info) -+ return; -+ -+ TRACE("Destroying GL context.\n"); -+ -+ wglMakeCurrent(NULL, NULL); -+ wglDeleteContext(ctx->gl_ctx); -+ ReleaseDC(ctx->window, ctx->dc); -+ DestroyWindow(ctx->window); -+} -+ -+unsigned int CDECL wined3d_get_gl_texture(struct wined3d_texture *texture) -+{ -+ struct wined3d_device *device = texture->resource.device; -+ const struct wined3d_gl_info *gl_info; -+ struct wined3d_texture_gl *gl_texture; -+ GLsync fence; -+ -+ TRACE("texture %p.\n", texture); -+ -+ if (!(gl_info = wined3d_prepare_vr_gl_context(device))) -+ return 0; -+ -+ fence = wined3d_cs_synchronize(device->cs); -+ GL_EXTCALL(glWaitSync(fence, 0, GL_TIMEOUT_IGNORED)); -+ GL_EXTCALL(glDeleteSync(fence)); -+ -+ checkGLcall("synchronize CS"); -+ -+ gl_texture = wined3d_texture_gl(texture); -+ return gl_texture->texture_rgb.name; -+} -+ - static void wined3d_texture_no3d_upload_data(struct wined3d_context *context, - const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format, - const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch, -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 0a18d909c5e..4bd32d95cda 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -3774,6 +3774,14 @@ struct wined3d_so_desc_entry - struct wined3d_stream_output_element elements[1]; - }; - -+struct wined3d_vr_gl_context -+{ -+ HWND window; -+ HDC dc; -+ HGLRC gl_ctx; -+ const struct wined3d_gl_info *gl_info; -+}; -+ - struct wined3d_device - { - LONG ref; -@@ -4000,6 +4000,7 @@ struct wined3d_device - struct wined3d_context **contexts; - UINT context_count; - -+ struct wined3d_vr_gl_context vr_context; - CRITICAL_SECTION bo_map_lock; - }; - -@@ -4768,6 +4778,11 @@ void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_t - void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, - wined3d_cs_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; - -+GLsync wined3d_cs_synchronize(struct wined3d_cs *cs) DECLSPEC_HIDDEN; -+ -+void wined3d_destroy_gl_vr_context(struct wined3d_vr_gl_context *ctx) DECLSPEC_HIDDEN; -+ -+ - static inline void wined3d_device_context_push_constants(struct wined3d_device_context *context, - enum wined3d_push_constants p, unsigned int start_idx, unsigned int count, const void *constants) - { -diff --git a/include/wine/wined3d-interop.idl b/include/wine/wined3d-interop.idl -index c5395ccc0ed..b1bda8ada76 100644 ---- a/include/wine/wined3d-interop.idl -+++ b/include/wine/wined3d-interop.idl -@@ -28,6 +28,8 @@ import "d3d11.idl"; - interface IWineD3D11Texture2D : ID3D11Texture2D - { - void access_gl_texture(gl_texture_callback callback, IUnknown *depth_texture, const void *data, unsigned int data_size); -+ -+ unsigned int get_gl_texture(); - } - - typedef void (__cdecl *user_cs_callback)(const void *data, unsigned int data_size); -diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h -index 81235a7677c..d63c54ca593 100644 ---- a/include/wine/wined3d.h -+++ b/include/wine/wined3d.h -@@ -2974,6 +2974,8 @@ typedef void (__cdecl *wined3d_gl_texture_callback)(unsigned int gl_texture, uns - void __cdecl wined3d_access_gl_texture(struct wined3d_texture *texture, - wined3d_gl_texture_callback callback, struct wined3d_texture *depth_texture, const void *data, unsigned int size); - -+unsigned int __cdecl wined3d_get_gl_texture(struct wined3d_texture *texture); -+ - typedef void (__cdecl *wined3d_cs_callback)(const void *data, unsigned int size); - - void __cdecl wined3d_device_run_cs_callback(struct wined3d_device *device, --- -2.30.2 - -From cc1f77d00ee61e8620029c08110015543682acb8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Fri, 21 Sep 2018 12:04:07 +0200 -Subject: [PATCH 09/12] wined3d: Load TEXTURE_RGB location for synchronous - texture access. - ---- - dlls/wined3d/cs.c | 10 +++++++--- - dlls/wined3d/texture.c | 2 +- - dlls/wined3d/wined3d_private.h | 2 +- - 3 files changed, 9 insertions(+), 5 deletions(-) - -diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c -index 511883924a1..6242651dd72 100644 ---- a/dlls/wined3d/cs.c -+++ b/dlls/wined3d/cs.c -@@ -486,6 +486,7 @@ struct wined3d_cs_wait_idle - struct wined3d_cs_fence - { - enum wined3d_cs_op opcode; -+ struct wined3d_texture *texture; - GLsync *fence; - }; - -@@ -2820,6 +2821,8 @@ static void wined3d_cs_exec_fence(struct wined3d_cs *cs, const void *data) - context = context_acquire(cs->c.device, NULL, 0); - gl_info = wined3d_context_gl(context)->gl_info; - -+ wined3d_texture_load_location(op->texture, 0, context, WINED3D_LOCATION_TEXTURE_RGB); -+ - fence = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)); - wined3d_context_gl(context)->gl_info->gl_ops.gl.p_glFlush(); - -@@ -2830,13 +2833,14 @@ static void wined3d_cs_exec_fence(struct wined3d_cs *cs, const void *data) - context_release(context); - } - --static GLsync wined3d_cs_emit_fence(struct wined3d_cs *cs) -+static GLsync wined3d_cs_emit_fence(struct wined3d_cs *cs, struct wined3d_texture *texture) - { - struct wined3d_cs_fence *op; - GLsync fence; - - op = cs->c.ops->require_space(cs, sizeof(*op), WINED3D_CS_QUEUE_DEFAULT); - op->opcode = WINED3D_CS_OP_FENCE; -+ op->texture = texture; - op->fence = &fence; - - cs->c.ops->submit(cs, WINED3D_CS_QUEUE_DEFAULT); -@@ -2845,9 +2849,9 @@ static GLsync wined3d_cs_emit_fence(struct wined3d_cs *cs) - return fence; - } - --GLsync wined3d_cs_synchronize(struct wined3d_cs *cs) -+GLsync wined3d_cs_synchronize(struct wined3d_cs *cs, struct wined3d_texture *texture) - { -- return wined3d_cs_emit_fence(cs); -+ return wined3d_cs_emit_fence(cs, texture); - } - - static void wined3d_cs_emit_stop(struct wined3d_cs *cs) -diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c -index 25c5e57fca0..72a64889ca9 100644 ---- a/dlls/wined3d/texture.c -+++ b/dlls/wined3d/texture.c -@@ -4698,7 +4698,7 @@ unsigned int CDECL wined3d_get_gl_texture(struct wined3d_texture *texture) - if (!(gl_info = wined3d_prepare_vr_gl_context(device))) - return 0; - -- fence = wined3d_cs_synchronize(device->cs); -+ fence = wined3d_cs_synchronize(device->cs, texture); - GL_EXTCALL(glWaitSync(fence, 0, GL_TIMEOUT_IGNORED)); - GL_EXTCALL(glDeleteSync(fence)); - -diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h -index 4bd32d95cda..2a9b2c08877 100644 ---- a/dlls/wined3d/wined3d_private.h -+++ b/dlls/wined3d/wined3d_private.h -@@ -4778,7 +4778,7 @@ void wined3d_cs_emit_gl_texture_callback(struct wined3d_cs *cs, struct wined3d_t - void wined3d_cs_emit_user_callback(struct wined3d_cs *cs, - wined3d_cs_callback callback, const void *data, unsigned int size) DECLSPEC_HIDDEN; - --GLsync wined3d_cs_synchronize(struct wined3d_cs *cs) DECLSPEC_HIDDEN; -+GLsync wined3d_cs_synchronize(struct wined3d_cs *cs, struct wined3d_texture *texture) DECLSPEC_HIDDEN; - - void wined3d_destroy_gl_vr_context(struct wined3d_vr_gl_context *ctx) DECLSPEC_HIDDEN; - --- -2.30.2 - -From 29f4110ef25083ad84d3f441986345abf79f3eaf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Fri, 21 Sep 2018 12:17:15 +0200 -Subject: [PATCH 10/12] d3d11: Pass IWineD3D11Texture2D to access_gl_texture(). - ---- - dlls/d3d11/texture.c | 21 +++++++-------------- - include/wine/wined3d-interop.idl | 3 ++- - 2 files changed, 9 insertions(+), 15 deletions(-) - -diff --git a/dlls/d3d11/texture.c b/dlls/d3d11/texture.c -index 7f7e8254225..32bf3c3c9cc 100644 ---- a/dlls/d3d11/texture.c -+++ b/dlls/d3d11/texture.c -@@ -716,27 +716,20 @@ static void STDMETHODCALLTYPE d3d11_texture2d_GetDesc(IWineD3D11Texture2D *iface - } - - static void STDMETHODCALLTYPE d3d11_texture2d_access_gl_texture(IWineD3D11Texture2D *iface, -- gl_texture_callback callback, IUnknown *depth_unk, const void *data, unsigned int size) -+ gl_texture_callback callback, IWineD3D11Texture2D *depth_texture, const void *data, unsigned int size) - { - struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface), *depth_tex = NULL; -- IWineD3D11Texture2D *depth_d3d11 = NULL; -+ struct wined3d_texture *wined3d_depth_texture = NULL; - -- TRACE("iface %p, callback %p, data %p, size %u.\n", iface, callback, data, size); -+ TRACE("iface %p, callback %p, depth_texture %p, data %p, size %u.\n", -+ iface, callback, depth_texture, data, size); - - wined3d_mutex_lock(); - -- if (depth_unk) -- { -- HRESULT hr; -- hr = IUnknown_QueryInterface(depth_unk, &IID_IWineD3D11Texture2D, (void**)&depth_d3d11); -- if(hr == S_OK) -- depth_tex = impl_from_IWineD3D11Texture2D(depth_d3d11); -- } -- -- wined3d_access_gl_texture(texture->wined3d_texture, callback, depth_tex ? depth_tex->wined3d_texture : NULL, data, size); -+ if (depth_texture) -+ wined3d_depth_texture = impl_from_IWineD3D11Texture2D(depth_texture)->wined3d_texture; - -- if (depth_d3d11) -- IWineD3D11Texture2D_Release(depth_d3d11); -+ wined3d_access_gl_texture(texture->wined3d_texture, callback, wined3d_depth_texture, data, size); - - wined3d_mutex_unlock(); - } -diff --git a/include/wine/wined3d-interop.idl b/include/wine/wined3d-interop.idl -index b1bda8ada76..f960e2f6d9d 100644 ---- a/include/wine/wined3d-interop.idl -+++ b/include/wine/wined3d-interop.idl -@@ -27,7 +27,8 @@ import "d3d11.idl"; - ] - interface IWineD3D11Texture2D : ID3D11Texture2D - { -- void access_gl_texture(gl_texture_callback callback, IUnknown *depth_texture, const void *data, unsigned int data_size); -+ void access_gl_texture(gl_texture_callback callback, -+ IWineD3D11Texture2D *depth_texture, const void *data, unsigned int data_size); - - unsigned int get_gl_texture(); - } --- -2.30.2 - -From 9a97a24ad5001cc4d25b9b8236fbf13b76d9eaef Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Thu, 11 Oct 2018 11:31:43 +0200 -Subject: [PATCH 11/12] d3d11: Remove unused 'depth_tex' variable. - ---- - dlls/d3d11/texture.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/d3d11/texture.c b/dlls/d3d11/texture.c -index 32bf3c3c9cc..f6e7d474d99 100644 ---- a/dlls/d3d11/texture.c -+++ b/dlls/d3d11/texture.c -@@ -718,7 +718,7 @@ static void STDMETHODCALLTYPE d3d11_texture2d_GetDesc(IWineD3D11Texture2D *iface - static void STDMETHODCALLTYPE d3d11_texture2d_access_gl_texture(IWineD3D11Texture2D *iface, - gl_texture_callback callback, IWineD3D11Texture2D *depth_texture, const void *data, unsigned int size) - { -- struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface), *depth_tex = NULL; -+ struct d3d_texture2d *texture = impl_from_IWineD3D11Texture2D(iface); - struct wined3d_texture *wined3d_depth_texture = NULL; - - TRACE("iface %p, callback %p, depth_texture %p, data %p, size %u.\n", --- -2.30.2 - -From b476c31f53be82ad3b8a3ec9d7987f75e8040cfe Mon Sep 17 00:00:00 2001 -From: GloriousEggroll -Date: Sun, 18 Aug 2019 19:05:52 -0600 -Subject: [PATCH 12/12] wined3d - ---- - dlls/wined3d/wined3d.spec | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec -index 2879e1653d3..bbc9ce7b99c 100644 ---- a/dlls/wined3d/wined3d.spec -+++ b/dlls/wined3d/wined3d.spec -@@ -367,3 +367,8 @@ - @ cdecl wined3d_vertex_declaration_incref(ptr) - - @ cdecl wined3d_extract_shader_input_signature_from_dxbc(ptr ptr long) -+ -+@ cdecl wined3d_access_gl_texture(ptr ptr ptr long) -+@ cdecl wined3d_device_run_cs_callback(ptr ptr ptr long) -+@ cdecl wined3d_device_wait_idle(ptr) -+@ cdecl wined3d_get_gl_texture(ptr) --- -2.30.2 - diff --git a/patches/proton/18-proton-amd_ags.patch b/patches/proton/18-proton-amd_ags.patch deleted file mode 100755 index 4fa0418d6..000000000 --- a/patches/proton/18-proton-amd_ags.patch +++ /dev/null @@ -1,5784 +0,0 @@ -From afaf271f5ae5a74ddc3914301c0103f1a67c0bb2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Mon, 23 Jul 2018 19:53:20 +0200 -Subject: [PATCH] amd_ags_x64: Import v5.1.1 amd_ags.h. - -Imported from https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK. ---- - dlls/amd_ags_x64/amd_ags.h | 944 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 944 insertions(+) - create mode 100644 dlls/amd_ags_x64/amd_ags.h - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -new file mode 100644 -index 00000000000..9c3e37e52e5 ---- /dev/null -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -0,0 +1,944 @@ -+// -+// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. -+// -+// Permission is hereby granted, free of charge, to any person obtaining a copy -+// of this software and associated documentation files (the "Software"), to deal -+// in the Software without restriction, including without limitation the rights -+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+// copies of the Software, and to permit persons to whom the Software is -+// furnished to do so, subject to the following conditions: -+// -+// The above copyright notice and this permission notice shall be included in -+// all copies or substantial portions of the Software. -+// -+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -+// THE SOFTWARE. -+// -+ -+/// \file -+/// \mainpage -+/// AGS Library Overview -+/// -------------------- -+/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query -+/// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs. -+/// -+/// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/. -+/// It is also worth checking http://gpuopen.com/gaming-product/amd-gpu-services-ags-library/ for any updates and articles on AGS. -+/// \internal -+/// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ -+/// \endinternal -+/// -+/// What's new in AGS 5.1.1 since version 5.0.6 -+/// --------------------------------------- -+/// AGS 5.1.1 includes the following updates: -+/// * An API change for DX11 extensions -+/// - It is now mandatory to call agsDriverExtensionsDX11_CreateDevice() when creating a device if the user wants to access any DX11 AMD extensions. -+/// - The corresponding agsDriverExtensionsDX11_DestroyDevice() call must be called to release the device and free up the internal resources allocated by the create call. -+/// * App registration extension for DX11. -+/// * Freesync 2 HDR support. -+/// * Wave reduce and wave scan shader extensions. -+/// * AMD user markers for DX12. -+/// * Eyefinity bug fixes. -+/// * MultiDrawIndexedInstancedIndirectCountIndirect parameter bug fix. -+/// * Static lib versions of the binary. -+/// * VS2017 support for the samples. -+/// -+/// What's new in AGS 5.x since version 4.x -+/// --------------------------------------- -+/// Version 5.x is a major overhaul of the library designed to provide a much clearer view of the GPUs in the system and the displays attached to them. -+/// It also exposes the ability to query each display for HDR capabilities and put those HDR capable displays into various HDR modes. -+/// Some functions such as agsGetGPUMemorySize and agsGetEyefinityConfigInfo have been removed in favor of including this information in the device & display enumeration. -+/// Features include: -+/// * Full GPU enumeration with adapter string, device id, revision id and vendor id. -+/// * Per GPU display enumeration including information on display name, resolution and HDR capabilities. -+/// * Optional user supplied memory allocator. -+/// * Function to set displays into HDR mode. -+/// * A Microsoft WACK compliant version of the library. -+/// * DirectX11 shader compiler controls. -+/// * DirectX11 multiview extension enabling MultiView and MultiRes rendering. -+/// * DirectX11 Crossfire API now supports using the API without needing a driver profile. Can also specify the transfer engine. -+/// -+/// Using the AGS library -+/// --------------------- -+/// It is recommended to take a look at the source code for the samples that come with the AGS SDK: -+/// * AGSSample -+/// * CrossfireSample -+/// * EyefinitySample -+/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state. -+/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more -+/// extensive example of Eyefinity setup than the basic example provided in AGSSample. -+/// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples. -+/// -+/// To add AGS support to an existing project, follow these steps: -+/// * Link your project against the correct import library. Choose from either the 32 bit or 64 bit version. -+/// * Copy the AGS dll into the same directory as your game executable. -+/// * Include the amd_ags.h header file from your source code. -+/// * Include the AGS hlsl files if you are using the shader intrinsics. -+/// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS. -+/// * On game initialization, call agsInit() passing in the address of the context. On success, this function will return a valid context pointer. -+/// * The agsInit() function should be called before the D3D device is created if the Crossfire mode is specified. -+/// -+/// Don't forget to cleanup AGS by calling agsDeInit() when the app exits, after the device has been destroyed. -+ -+#ifndef AMD_AGS_H -+#define AMD_AGS_H -+ -+#define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version -+#define AMD_AGS_VERSION_MINOR 1 ///< AGS minor version -+#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+ -+#define AMD_AGS_API __declspec(dllexport) ///< AGS calling convention -+ -+// Forward declaration of D3D11 types -+struct IDXGIAdapter; -+enum D3D_DRIVER_TYPE; -+enum D3D_FEATURE_LEVEL; -+struct DXGI_SWAP_CHAIN_DESC; -+struct ID3D11Device; -+struct ID3D11DeviceContext; -+struct IDXGISwapChain; -+struct ID3D11Resource; -+struct ID3D11Buffer; -+struct ID3D11Texture1D; -+struct ID3D11Texture2D; -+struct ID3D11Texture3D; -+struct D3D11_BUFFER_DESC; -+struct D3D11_TEXTURE1D_DESC; -+struct D3D11_TEXTURE2D_DESC; -+struct D3D11_TEXTURE3D_DESC; -+struct D3D11_SUBRESOURCE_DATA; -+struct tagRECT; -+typedef tagRECT D3D11_RECT; ///< typedef this ourselves so we don't have to drag d3d11.h in -+ -+// Forward declaration of D3D12 types -+struct ID3D12Device; -+struct ID3D12GraphicsCommandList; -+ -+ -+/// The return codes -+enum AGSReturnCode -+{ -+ AGS_SUCCESS, ///< Successful function call -+ AGS_FAILURE, ///< Failed to complete call for some unspecified reason -+ AGS_INVALID_ARGS, ///< Invalid arguments into the function -+ AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally -+ AGS_ERROR_MISSING_DLL, ///< Returned when a driver dll fails to load - most likely due to not being present in legacy driver installation -+ AGS_ERROR_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver -+ AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension -+ AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) -+}; -+ -+/// The DirectX11 extension support bits -+enum AGSDriverExtensionDX11 -+{ -+ AGS_DX11_EXTENSION_QUADLIST = 1 << 0, -+ AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, -+ AGS_DX11_EXTENSION_UAV_OVERLAP = 1 << 2, -+ AGS_DX11_EXTENSION_DEPTH_BOUNDS_TEST = 1 << 3, -+ AGS_DX11_EXTENSION_MULTIDRAWINDIRECT = 1 << 4, -+ AGS_DX11_EXTENSION_MULTIDRAWINDIRECT_COUNTINDIRECT = 1 << 5, -+ AGS_DX11_EXTENSION_CROSSFIRE_API = 1 << 6, -+ AGS_DX11_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 7, -+ AGS_DX11_EXTENSION_INTRINSIC_READLANE = 1 << 8, -+ AGS_DX11_EXTENSION_INTRINSIC_LANEID = 1 << 9, -+ AGS_DX11_EXTENSION_INTRINSIC_SWIZZLE = 1 << 10, -+ AGS_DX11_EXTENSION_INTRINSIC_BALLOT = 1 << 11, -+ AGS_DX11_EXTENSION_INTRINSIC_MBCOUNT = 1 << 12, -+ AGS_DX11_EXTENSION_INTRINSIC_COMPARE3 = 1 << 13, -+ AGS_DX11_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 14, -+ AGS_DX11_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 15, ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 16, ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, -+ AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, -+ AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19 ///< Supported in Radeon Software Version 17.9.1 onwards. -+}; -+ -+/// The DirectX12 extension support bits -+enum AGSDriverExtensionDX12 -+{ -+ AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_LANEID = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_SWIZZLE = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_BALLOT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_MBCOUNT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_COMPARE3 = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10 ///< Supported in Radeon Software Version 17.9.1 onwards. -+}; -+ -+/// The space id for DirectX12 intrinsic support -+const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 -+ -+ -+/// Additional topologies supported via extensions -+enum AGSPrimitiveTopology -+{ -+ AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, -+ AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 -+}; -+ -+/// The different modes to control Crossfire behavior. -+enum AGSCrossfireMode -+{ -+ AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering -+ AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile -+ AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering -+}; -+ -+ -+/// The Crossfire API transfer types -+enum AGSAfrTransferType -+{ -+ AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking -+ AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking -+ AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer -+ AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory -+ AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory -+}; -+ -+/// The Crossfire API transfer engines -+enum AGSAfrTransferEngine -+{ -+ AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers -+ AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers -+ AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers -+}; -+ -+/// The display flags describing various properties of the display. -+enum AGSDisplayFlags -+{ -+ AGS_DISPLAYFLAG_PRIMARY_DISPLAY = 1 << 0, ///< Whether this display is marked as the primary display. Not set on the WACK version. -+ AGS_DISPLAYFLAG_HDR10 = 1 << 1, ///< HDR10 is supported on this display -+ AGS_DISPLAYFLAG_DOLBYVISION = 1 << 2, ///< Dolby Vision is supported on this display -+ AGS_DISPLAYFLAG_FREESYNC = 1 << 3, ///< Freesync is supported on this display -+ AGS_DISPLAYFLAG_FREESYNC_2 = 1 << 4, ///< Freesync 2 is supported on this display -+ AGS_DISPLAYFLAG_EYEFINITY_IN_GROUP = 1 << 5, ///< The display is part of the Eyefinity group -+ AGS_DISPLAYFLAG_EYEFINITY_PREFERRED_DISPLAY = 1 << 6, ///< The display is the preferred display in the Eyefinity group for displaying the UI -+ AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode -+}; -+ -+struct AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit -+ -+/// The rectangle struct used by AGS. -+struct AGSRect -+{ -+ int offsetX; ///< Offset on X axis -+ int offsetY; ///< Offset on Y axis -+ int width; ///< Width of rectangle -+ int height; ///< Height of rectangle -+}; -+ -+/// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects -+struct AGSClipRect -+{ -+ /// The inclusion mode for the rect -+ enum Mode -+ { -+ ClipRectIncluded = 0, ///< Include the rect -+ ClipRectExcluded = 1 ///< Exclude the rect -+ }; -+ -+ Mode mode; ///< Include/exclude rect region -+ AGSRect rect; ///< The rect to include/exclude -+}; -+ -+/// The display info struct used to describe a display enumerated by AGS -+struct AGSDisplayInfo -+{ -+ char name[ 256 ]; ///< The name of the display -+ char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName -+ -+ unsigned int displayFlags; ///< Bitfield of ::AGSDisplayFlags -+ -+ int maxResolutionX; ///< The maximum supported resolution of the unrotated display -+ int maxResolutionY; ///< The maximum supported resolution of the unrotated display -+ float maxRefreshRate; ///< The maximum supported refresh rate of the display -+ -+ AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation -+ AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will -+ ///< be the sub region in the Eyefinity single large surface (SLS) -+ float currentRefreshRate; ///< The current refresh rate -+ -+ int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group -+ int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group -+ -+ double chromaticityRedX; ///< Red display primary X coord -+ double chromaticityRedY; ///< Red display primary Y coord -+ -+ double chromaticityGreenX; ///< Green display primary X coord -+ double chromaticityGreenY; ///< Green display primary Y coord -+ -+ double chromaticityBlueX; ///< Blue display primary X coord -+ double chromaticityBlueY; ///< Blue display primary Y coord -+ -+ double chromaticityWhitePointX; ///< White point X coord -+ double chromaticityWhitePointY; ///< White point Y coord -+ -+ double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1 -+ double screenSpecularReflectance; ///< Percentage expressed between 0 - 1 -+ -+ double minLuminance; ///< The minimum luminance of the display in nits -+ double maxLuminance; ///< The maximum luminance of the display in nits -+ double avgLuminance; ///< The average luminance of the display in nits -+ -+ int logicalDisplayIndex; ///< The internally used index of this display -+ int adlAdapterIndex; ///< The internally used ADL adapter index -+}; -+ -+/// The device info struct used to describe a physical GPU enumerated by AGS -+struct AGSDeviceInfo -+{ -+ /// The architecture version -+ enum ArchitectureVersion -+ { -+ ArchitectureVersion_Unknown, ///< Unknown architecture, potentially from another IHV. Check AGSDeviceInfo::vendorId -+ ArchitectureVersion_PreGCN, ///< AMD architecture, pre-GCN -+ ArchitectureVersion_GCN ///< AMD GCN architecture -+ }; -+ -+ ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware -+ const char* adapterString; ///< The adapter name string -+ int vendorId; ///< The vendor id -+ int deviceId; ///< The device id -+ int revisionId; ///< The revision id -+ -+ int numCUs; ///< Number of GCN compute units. Zero if not GCN -+ int coreClock; ///< Core clock speed at 100% power in MHz -+ int memoryClock; ///< Memory clock speed at 100% power in MHz -+ float teraFlops; ///< Teraflops of GPU. Zero if not GCN. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD -+ -+ int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. -+ long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. -+ -+ int numDisplays; ///< The number of active displays found to be attached to this adapter. -+ AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ -+ int eyefinityEnabled; ///< Indicates if Eyefinity is active -+ int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. -+ int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. -+ int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. -+ -+ int adlAdapterIndex; ///< Internally used index into the ADL list of adapters -+}; -+ -+/// \defgroup general General API functions -+/// API for initialization, cleanup, HDR display modes and Crossfire GPU count -+/// @{ -+ -+typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( int allocationSize ); ///< AGS user defined allocation prototype -+typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype -+ -+ /// The configuration options that can be passed in to \ref agsInit -+struct AGSConfiguration -+{ -+ AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used -+ AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used -+ AGSCrossfireMode crossfireMode; ///< Desired Crossfire mode -+}; -+ -+/// The top level GPU information returned from \ref agsInit -+struct AGSGPUInfo -+{ -+ int agsVersionMajor; ///< Major field of Major.Minor.Patch AGS version number -+ int agsVersionMinor; ///< Minor field of Major.Minor.Patch AGS version number -+ int agsVersionPatch; ///< Patch field of Major.Minor.Patch AGS version number -+ int isWACKCompliant; ///< 1 if WACK compliant. -+ -+ const char* driverVersion; ///< The AMD driver package version -+ const char* radeonSoftwareVersion; ///< The Radeon Software Version -+ -+ int numDevices; ///< Number of GPUs in the system -+ AGSDeviceInfo* devices; ///< List of GPUs in the system -+}; -+ -+/// The struct to specify the display settings to the driver. -+struct AGSDisplaySettings -+{ -+ /// The display mode -+ enum Mode -+ { -+ Mode_SDR, ///< SDR mode -+ Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. -+ Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. -+ Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. Values in the range of 0.0 to 125.0 where 125.0 == AGSDisplayInfo::maxLuminance. -+ Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain -+ }; -+ -+ Mode mode; ///< The display mode to set the display into -+ -+ double chromaticityRedX; ///< Red display primary X coord -+ double chromaticityRedY; ///< Red display primary Y coord -+ -+ double chromaticityGreenX; ///< Green display primary X coord -+ double chromaticityGreenY; ///< Green display primary Y coord -+ -+ double chromaticityBlueX; ///< Blue display primary X coord -+ double chromaticityBlueY; ///< Blue display primary Y coord -+ -+ double chromaticityWhitePointX; ///< White point X coord -+ double chromaticityWhitePointY; ///< White point Y coord -+ -+ double minLuminance; ///< The minimum scene luminance in nits -+ double maxLuminance; ///< The maximum scene luminance in nits -+ -+ double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) -+ double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) -+}; -+ -+/// -+/// Function used to initialize the AGS library. -+/// Must be called prior to any of the subsequent AGS API calls. -+/// Must be called prior to ID3D11Device or ID3D12Device creation. -+/// \note This function will fail with AGS_ERROR_LEGACY_DRIVER in Catalyst versions before 12.20. -+/// \note It is good practice to check the AGS version returned from AGSGPUInfo against the version defined in the header in case a mismatch between the dll and header has occurred. -+/// -+/// \param [in, out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. -+/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration. -+/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system. -+/// -+AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* config, AGSGPUInfo* gpuInfo ); -+ -+/// -+/// Function used to clean up the AGS library. -+/// -+/// \param [in] context Pointer to a context. This function will deallocate the context from the heap. -+/// -+AMD_AGS_API AGSReturnCode agsDeInit( AGSContext* context ); -+ -+/// -+/// Function used to query the number of GPUs used for Crossfire acceleration. -+/// This may be different from the total number of GPUs present in the system. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [out] numGPUs Number of GPUs used for Crossfire acceleration -+/// -+AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* numGPUs ); -+ -+/// -+/// Function used to set a specific display into HDR mode -+/// \note Setting all of the values apart from color space and transfer function to zero will cause the display to use defaults. -+/// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc). -+/// \note HDR10 PQ mode requires a 1010102 swapchain. -+/// \note HDR10 scRGB mode requires an FP16 swapchain. -+/// \note Freesync2 Gamma mode requires a 1010102 swapchain. -+/// \note Freesync2 scRGB mode requires an FP16 swapchain. -+/// \note Dolby Vision requires a 8888 UNORM swapchain. -+/// -+/// \param [in] context Pointer to a context. This is generated by \ref agsInit -+/// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices. -+/// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays. -+/// \param [in] settings Pointer to the display settings to use. -+/// -+AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceIndex, int displayIndex, const AGSDisplaySettings* settings ); -+ -+/// @} -+ -+/// \defgroup dx12 DirectX12 Extensions -+/// DirectX12 driver extensions -+/// @{ -+ -+/// \defgroup dx12init Initialization and Cleanup -+/// @{ -+ -+/// -+/// Function used to initialize the AMD-specific driver extensions for D3D12. -+/// Extensions require support in the driver, therefore it is important to check the extensionsSupported bitfield. -+/// -+/// When using the HLSL shader extensions please note: -+/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION option, otherwise it will not work. -+/// * The intrinsic instructions require a 5.1 shader model. -+/// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. -+/// -+/// \param [in] context Pointer to a context. This is generated by \ref agsInit -+/// \param [in] device The D3D12 device. -+/// \param [out] extensionsSupported Pointer to a bit mask that this function will fill in to indicate which extensions are supported. See ::AGSDriverExtensionDX12 -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_Init( AGSContext* context, ID3D12Device* device, unsigned int* extensionsSupported ); -+ -+/// -+/// Function used to cleanup any AMD-specific driver extensions for D3D12 -+/// -+/// \param [in] context Pointer to a context. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); -+ -+/// @} -+ -+/// \defgroup dx12usermarkers User Markers -+/// @{ -+ -+/// -+/// Function used to push an AMD user marker onto the command list. -+/// This is only has an effect if AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of agsDriverExtensionsDX12_Init() -+/// Supported in Radeon Software Version 17.9.1 onwards. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] commandList Pointer to the command list. -+/// \param [in] data The marker string. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_PushMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList, const char* data ); -+ -+/// -+/// Function used to pop an AMD user marker on the command list. -+/// Supported in Radeon Software Version 17.9.1 onwards. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] commandList Pointer to the command list. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_PopMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList ); -+ -+/// -+/// Function used to insert an single event AMD user marker onto the command list. -+/// Supported in Radeon Software Version 17.9.1 onwards. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] commandList Pointer to the command list. -+/// \param [in] data The marker string. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context, ID3D12GraphicsCommandList* commandList, const char* data ); -+ -+/// @} -+ -+/// @} -+ -+/// \defgroup dx11 DirectX11 Extensions -+/// DirectX11 driver extensions -+/// @{ -+ -+/// \defgroup dx11init Device creation and cleanup -+/// It is now mandatory to call agsDriverExtensionsDX11_CreateDevice() when creating a device if the user wants to access any DX11 AMD extensions. -+/// The corresponding agsDriverExtensionsDX11_DestroyDevice() call must be called to release the device and free up the internal resources allocated by the create call. -+/// @{ -+ -+/// The struct to specify the existing DX11 device creation parameters -+struct AGSDX11DeviceCreationParams -+{ -+ IDXGIAdapter* pAdapter; ///< Consult the DX documentation on D3D11CreateDevice for this parameter -+ D3D_DRIVER_TYPE DriverType; ///< Consult the DX documentation on D3D11CreateDevice for this parameter -+ HMODULE Software; ///< Consult the DX documentation on D3D11CreateDevice for this parameter -+ UINT Flags; ///< Consult the DX documentation on D3D11CreateDevice for this parameter -+ const D3D_FEATURE_LEVEL* pFeatureLevels; ///< Consult the DX documentation on D3D11CreateDevice for this parameter -+ UINT FeatureLevels; ///< Consult the DX documentation on D3D11CreateDevice for this parameter -+ UINT SDKVersion; ///< Consult the DX documentation on D3D11CreateDevice for this parameter -+ const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc; ///< Optional swapchain description. Specify this to invoke D3D11CreateDeviceAndSwapChain instead of D3D11CreateDevice. This must be null on the WACK compliant version -+}; -+ -+#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX11ExtensionParams -+#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version -+ -+/// The struct to specify DX11 additional device creation parameters -+struct AGSDX11ExtensionParams -+{ -+ unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. #define AmdDxExtShaderIntrinsicsUAVSlot. -+ /// The default slot is 7, but the caller is free to use an alternative slot. -+ const WCHAR* pAppName; ///< Application name -+ UINT appVersion; ///< Application version -+ const WCHAR* pEngineName; ///< Engine name -+ UINT engineVersion; ///< Engine version -+}; -+ -+/// The struct to hold all the returned parameters from the device creation call -+struct AGSDX11ReturnedParams -+{ -+ ID3D11Device* pDevice; ///< The newly created device -+ D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device -+ ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context -+ IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version -+ unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See AGSDriverExtensionDX11 -+}; -+ -+/// -+/// Function used to create a D3D11 device with additional AMD-specific initialization parameters. -+/// -+/// When using the HLSL shader extensions please note: -+/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION option, otherwise it will not work. -+/// -+/// \param [in] context Pointer to a context. This is generated by \ref agsInit -+/// \param [in] creationParams Pointer to the struct to specify the existing DX11 device creation parameters. -+/// \param [in] extensionParams Optional pointer to the struct to specify DX11 additional device creation parameters. -+/// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* context, AGSDX11DeviceCreationParams* creationParams, AGSDX11ExtensionParams* extensionParams, AGSDX11ReturnedParams* returnedParams ); -+ -+/// -+/// Function to destroy the D3D11 device. -+/// This call will also cleanup any AMD-specific driver extensions for D3D11. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] device Pointer to the D3D11 device. -+/// \param [out] references Optional pointer to an unsigned int that will be set to the value returned from device->Release(). -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice( AGSContext* context, ID3D11Device* device, unsigned int* references ); -+ -+/// @} -+ -+ -+/// \defgroup dx11appreg App Registration -+/// @{ -+/// This extension allows an apllication to voluntarily register itself with the driver, providing a more robust app detection solution and avoid the issue of the driver -+/// relying on exe names to match the app to a driver profile. -+/// This feature is supported in Radeon Software Version 17.9.2 onwards. -+/// Rules: -+/// * AppName or EngineName must be set, but both are not required. Engine profiles will be used only if app specific profiles do not exist. -+/// * In an engine, the EngineName should be set, so a default profile can be built. If an app modifies the engine, the AppName should be set, to allow a profile for the specific app. -+/// * Version number is not mandatory, but heavily suggested. The use of which can prevent the use of profiles for incompatible versions (for instance engine versions that introduce or change features), and can help prevent older profiles from being used (and introducing new bugs) before the profile is tested with new app builds. -+/// * If Version numbers are used and a new version is introduced, a new profile will not be enabled until an AMD engineer has been able to update a previous profile, or make a new one. -+/// -+/// The cases for profile selection are as follows: -+/// -+/// |Case|Profile Applied| -+/// |----|---------------| -+/// | App or Engine Version has profile | The profile is used. | -+/// | App or Engine Version num < profile version num | The closest profile > the version number is used. | -+/// | App or Engine Version num > profile version num | No profile selected/The previous method is used. | -+/// | App and Engine Version have profile | The App's profile is used. | -+/// | App and Engine Version num < profile version | The closest App profile > the version number is used. | -+/// | App and Engine Version, no App profile found | The Engine profile will be used. | -+/// | App/Engine name but no Version, has profile | The latest profile is used. | -+/// | No name or version, or no profile | The previous app detection method is used. | -+/// -+/// As shown above, if an App name is given, and a profile is found for that app, that will be prioritized. The Engine name and profile will be used only if no app name is given, or no viable profile is found for the app name. -+/// In the case that App nor Engine have a profile, the previous app detection methods will be used. If given a version number that is larger than any profile version number, no profile will be selected. -+/// This is specifically to prevent cases where an update to an engine or app will cause catastrophic breaks in the profile, allowing an engineer to test the profile before clearing it for public use with the new engine/app update. -+/// -+/// @} -+ -+/// \defgroup dx11misc Misc Extensions -+/// API for depth bounds test, UAV overlap and prim topologies -+/// @{ -+ -+/// -+/// Function used to set the primitive topology. If you are using any of the extended topology types, then this function should -+/// be called to set ALL topology types. -+/// -+/// The Quad List extension is a convenient way to submit quads without using an index buffer. Note that this still submits two triangles at the driver level. -+/// In order to use this function, AGS must already be initialized and agsDriverExtensionsDX11_Init must have been called successfully. -+/// -+/// The Screen Rect extension, which is only available on GCN hardware, allows the user to pass in three of the four corners of a rectangle. -+/// The hardware then uses the bounding box of the vertices to rasterize the rectangle primitive (i.e. as a rectangle rather than two triangles). -+/// \note Note that this will not return valid interpolated values, only valid SV_Position values. -+/// \note If either the Quad List or Screen Rect extension are used, then agsDriverExtensionsDX11_IASetPrimitiveTopology should be called in place of the native DirectX11 equivalent all the time. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] topology The topology to set on the D3D11 device. This can be either an AGS-defined topology such as AGS_PRIMITIVE_TOPOLOGY_QUAD_LIST -+/// or a standard D3D-defined topology such as D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP. -+/// NB. the AGS-defined types will require casting to a D3D_PRIMITIVE_TOPOLOGY type. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSContext* context, enum D3D_PRIMITIVE_TOPOLOGY topology ); -+ -+/// -+/// Function used indicate to the driver it can overlap the subsequent batch of back-to-back dispatches. -+/// When calling back-to-back draw calls or dispatch calls that write to the same UAV, the AMD DX11 driver will automatically insert a barrier to ensure there are no write after write (WAW) hazards. -+/// If the app can guarantee there is no overlap between the writes between these calls, then this extension will remove those barriers allowing the work to run in parallel on the GPU. -+/// -+/// Usage would be as follows: -+/// \code{.cpp} -+/// // Disable automatic WAW syncs -+/// agsDriverExtensionsDX11_BeginUAVOverlap( m_agsContext ); -+/// -+/// // Submit back-to-back dispatches that write to the same UAV -+/// m_device->Dispatch( ... ); // First half of UAV -+/// m_device->Dispatch( ... ); // Second half of UAV -+/// -+/// // Reenable automatic WAW syncs -+/// agsDriverExtensionsDX11_EndUAVOverlap( m_agsContext ); -+/// \endcode -+/// -+/// \param [in] context Pointer to a context. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap( AGSContext* context ); -+ -+/// -+/// Function used indicate to the driver it can no longer overlap the batch of back-to-back dispatches that has been submitted. -+/// -+/// \param [in] context Pointer to a context. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* context ); -+ -+/// -+/// Function used to set the depth bounds test extension -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] enabled Whether to enable or disable the depth bounds testing. If disabled, the next two args are ignored. -+/// \param [in] minDepth The near depth range to clip against. -+/// \param [in] maxDepth The far depth range to clip against. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* context, bool enabled, float minDepth, float maxDepth ); -+ -+/// @} -+ -+/// \defgroup mdi Multi Draw Indirect (MDI) -+/// API for dispatching multiple instanced draw commands. -+/// The multi draw indirect extensions allow multiple sets of DrawInstancedIndirect to be submitted in one API call. -+/// The draw calls are issued on the GPU's command processor (CP), potentially saving the significant CPU overheads incurred by submitting the equivalent draw calls on the CPU. -+/// -+/// The extension allows the following code: -+/// \code{.cpp} -+/// // Submit n batches of DrawIndirect calls -+/// for ( int i = 0; i < n; i++ ) -+/// DrawIndexedInstancedIndirect( buffer, i * sizeof( cmd ) ); -+/// \endcode -+/// To be replaced by the following call: -+/// \code{.cpp} -+/// // Submit all n batches in one call -+/// agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( m_agsContext, n, buffer, 0, sizeof( cmd ) ); -+/// \endcode -+/// -+/// The buffer used for the indirect args must be of the following formats: -+/// \code{.cpp} -+/// // Buffer layout for agsDriverExtensions_MultiDrawInstancedIndirect -+/// struct DrawInstancedIndirectArgs -+/// { -+/// UINT VertexCountPerInstance; -+/// UINT InstanceCount; -+/// UINT StartVertexLocation; -+/// UINT StartInstanceLocation; -+/// }; -+/// -+/// // Buffer layout for agsDriverExtensions_MultiDrawIndexedInstancedIndirect -+/// struct DrawIndexedInstancedIndirectArgs -+/// { -+/// UINT IndexCountPerInstance; -+/// UINT InstanceCount; -+/// UINT StartIndexLocation; -+/// UINT BaseVertexLocation; -+/// UINT StartInstanceLocation; -+/// }; -+/// \endcode -+/// -+/// @{ -+ -+/// -+/// Function used to submit a batch of draws via MultiDrawIndirect -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] drawCount The number of draws. -+/// \param [in] pBufferForArgs The args buffer. -+/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. -+/// \param [in] byteStrideForArgs The per element stride of the args buffer. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+ -+/// -+/// Function used to submit a batch of draws via MultiDrawIndirect -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] drawCount The number of draws. -+/// \param [in] pBufferForArgs The args buffer. -+/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. -+/// \param [in] byteStrideForArgs The per element stride of the args buffer. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+ -+/// -+/// Function used to submit a batch of draws via MultiDrawIndirect -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] pBufferForDrawCount The draw count buffer. -+/// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. -+/// \param [in] pBufferForArgs The args buffer. -+/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. -+/// \param [in] byteStrideForArgs The per element stride of the args buffer. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+ -+/// -+/// Function used to submit a batch of draws via MultiDrawIndirect -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] pBufferForDrawCount The draw count buffer. -+/// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. -+/// \param [in] pBufferForArgs The args buffer. -+/// \param [in] alignedByteOffsetForArgs The offset into the args buffer. -+/// \param [in] byteStrideForArgs The per element stride of the args buffer. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+ -+/// @} -+ -+/// \defgroup shadercompiler Shader Compiler Controls -+/// API for controlling DirectX11 shader compilation. -+/// Check support for this feature using the AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS bit. -+/// Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+/// @{ -+ -+/// -+/// This method can be used to limit the maximum number of threads the driver uses for asynchronous shader compilation. -+/// Setting it to 0 will disable asynchronous compilation completely and force the shaders to be compiled "inline" on the threads that call Create*Shader. -+/// -+/// This method can only be called before any shaders are created and being compiled by the driver. -+/// If this method is called after shaders have been created the function will return AGS_FAILURE. -+/// This function only sets an upper limit.The driver may create fewer threads than allowed by this function. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] numberOfThreads The maximum number of threads to use. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount( AGSContext* context, unsigned int numberOfThreads ); -+ -+/// -+/// This method can be used to determine the total number of asynchronous shader compile jobs that are either -+/// queued for waiting for compilation or being compiled by the driver?s asynchronous compilation threads. -+/// This method can be called at any during the lifetime of the driver. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [out] numberOfJobs Pointer to the number of jobs in flight currently. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NumPendingAsyncCompileJobs( AGSContext* context, unsigned int* numberOfJobs ); -+ -+/// -+/// This method can be used to enable or disable the disk based shader cache. -+/// Enabling/disabling the disk cache is not supported if is it disabled explicitly via Radeon Settings or by an app profile. -+/// Calling this method under these conditions will result in AGS_FAILURE being returned. -+/// It is recommended that this method be called before any shaders are created by the application and being compiled by the driver. -+/// Doing so at any other time may result in the cache being left in an inconsistent state. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] enable Whether to enable the disk cache. 0 to disable, 1 to enable. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDiskShaderCacheEnabled( AGSContext* context, int enable ); -+ -+/// @} -+ -+/// \defgroup multiview Multiview -+/// API for multiview broadcasting. -+/// Check support for this feature using the AGS_DX11_EXTENSION_MULTIVIEW bit. -+/// Supported in Radeon Software Version 16.12.1 (driver version 16.50.2001) onwards. -+/// @{ -+ -+/// -+/// Function to control draw calls replication to multiple viewports and RT slices. -+/// Setting any mask to 0 disables draw replication. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] vpMask Viewport control bit mask. -+/// \param [in] rtSliceMask RT slice control bit mask. -+/// \param [in] vpMaskPerRtSliceEnabled If 0, 16 lower bits of vpMask apply to all RT slices; if 1 each 16 bits of 64-bit mask apply to corresponding 4 RT slices. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetViewBroadcastMasks( AGSContext* context, unsigned long long vpMask, unsigned long long rtSliceMask, int vpMaskPerRtSliceEnabled ); -+ -+/// -+/// Function returns max number of supported clip rectangles. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [out] maxRectCount Returned max number of clip rectangles. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_GetMaxClipRects( AGSContext* context, unsigned int* maxRectCount ); -+ -+/// -+/// Function sets clip rectangles. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] clipRectCount Number of specified clip rectangles. Use 0 to disable clip rectangles. -+/// \param [in] clipRects Array of clip rectangles. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetClipRects( AGSContext* context, unsigned int clipRectCount, const AGSClipRect* clipRects ); -+ -+/// @} -+ -+/// \defgroup cfxapi Explicit Crossfire API -+/// API for explicit control over Crossfire -+/// @{ -+ -+/// -+/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] desc Pointer to the D3D11 resource description. -+/// \param [in] initialData Optional pointer to the initializing data for the resource. -+/// \param [out] buffer Returned pointer to the resource. -+/// \param [in] transferType The transfer behavior. -+/// \param [in] transferEngine The transfer engine to use. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateBuffer( AGSContext* context, const D3D11_BUFFER_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Buffer** buffer, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); -+ -+/// -+/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] desc Pointer to the D3D11 resource description. -+/// \param [in] initialData Optional pointer to the initializing data for the resource. -+/// \param [out] texture1D Returned pointer to the resource. -+/// \param [in] transferType The transfer behavior. -+/// \param [in] transferEngine The transfer engine to use. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture1D( AGSContext* context, const D3D11_TEXTURE1D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture1D** texture1D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); -+ -+/// -+/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] desc Pointer to the D3D11 resource description. -+/// \param [in] initialData Optional pointer to the initializing data for the resource. -+/// \param [out] texture2D Returned pointer to the resource. -+/// \param [in] transferType The transfer behavior. -+/// \param [in] transferEngine The transfer engine to use. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture2D( AGSContext* context, const D3D11_TEXTURE2D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture2D** texture2D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); -+ -+/// -+/// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] desc Pointer to the D3D11 resource description. -+/// \param [in] initialData Optional pointer to the initializing data for the resource. -+/// \param [out] texture3D Returned pointer to the resource. -+/// \param [in] transferType The transfer behavior. -+/// \param [in] transferEngine The transfer engine to use. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateTexture3D( AGSContext* context, const D3D11_TEXTURE3D_DESC* desc, const D3D11_SUBRESOURCE_DATA* initialData, ID3D11Texture3D** texture3D, AGSAfrTransferType transferType, AGSAfrTransferEngine transferEngine ); -+ -+/// -+/// Function to notify the driver that we have finished writing to the resource this frame. -+/// This will initiate a transfer for AGS_AFR_TRANSFER_1STEP_P2P, -+/// AGS_AFR_TRANSFER_2STEP_NO_BROADCAST, and AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] resource Pointer to the resource. -+/// \param [in] transferRegions An array of transfer regions (can be null to specify the whole area). -+/// \param [in] subresourceArray An array of subresource indices (can be null to specify all subresources). -+/// \param [in] numSubresources The number of subresources in subresourceArray OR number of transferRegions. Use 0 to specify ALL subresources and one transferRegion (which may be null if specifying the whole area). -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndWrites( AGSContext* context, ID3D11Resource* resource, const D3D11_RECT* transferRegions, const unsigned int* subresourceArray, unsigned int numSubresources ); -+ -+/// -+/// This will notify the driver that the app will begin read/write access to the resource. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] resource Pointer to the resource. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceBeginAllAccess( AGSContext* context, ID3D11Resource* resource ); -+ -+/// -+/// This is used for AGS_AFR_TRANSFER_1STEP_P2P to notify when it is safe to initiate a transfer. -+/// This call in frame N-(NumGpus-1) allows a 1 step P2P in frame N to start. -+/// This should be called after agsDriverExtensionsDX11_NotifyResourceEndWrites. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] resource Pointer to the resource. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndAllAccess( AGSContext* context, ID3D11Resource* resource ); -+ -+/// @} -+ -+/// @} -+ -+#ifdef __cplusplus -+} // extern "C" -+#endif -+ -+#endif // AMD_AGS_H - -From e10f7f83b4d7c4269b93b79912cb3ee4ba58187e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Mon, 23 Jul 2018 19:53:20 +0200 -Subject: [PATCH] amd_ags_x64: Make amd_ags.h usable with gcc. - ---- - dlls/amd_ags_x64/amd_ags.h | 110 +++++++++++++++++-------------------- - 1 file changed, 51 insertions(+), 59 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index 9c3e37e52e5..a83a1f88692 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -96,8 +96,7 @@ - extern "C" { - #endif - -- --#define AMD_AGS_API __declspec(dllexport) ///< AGS calling convention -+#define AMD_AGS_API WINAPI - - // Forward declaration of D3D11 types - struct IDXGIAdapter; -@@ -117,8 +116,6 @@ struct D3D11_TEXTURE1D_DESC; - struct D3D11_TEXTURE2D_DESC; - struct D3D11_TEXTURE3D_DESC; - struct D3D11_SUBRESOURCE_DATA; --struct tagRECT; --typedef tagRECT D3D11_RECT; ///< typedef this ourselves so we don't have to drag d3d11.h in - - // Forward declaration of D3D12 types - struct ID3D12Device; -@@ -126,7 +123,7 @@ struct ID3D12GraphicsCommandList; - - - /// The return codes --enum AGSReturnCode -+typedef enum AGSReturnCode - { - AGS_SUCCESS, ///< Successful function call - AGS_FAILURE, ///< Failed to complete call for some unspecified reason -@@ -136,10 +133,10 @@ enum AGSReturnCode - AGS_ERROR_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver - AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension - AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) --}; -+} AGSReturnCode; - - /// The DirectX11 extension support bits --enum AGSDriverExtensionDX11 -+typedef enum AGSDriverExtensionDX11 - { - AGS_DX11_EXTENSION_QUADLIST = 1 << 0, - AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, -@@ -161,10 +158,10 @@ enum AGSDriverExtensionDX11 - AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, - AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, - AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19 ///< Supported in Radeon Software Version 17.9.1 onwards. --}; -+} AGSDriverExtensionDX11; - - /// The DirectX12 extension support bits --enum AGSDriverExtensionDX12 -+typedef enum AGSDriverExtensionDX12 - { - AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. - AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -@@ -177,48 +174,48 @@ enum AGSDriverExtensionDX12 - AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10 ///< Supported in Radeon Software Version 17.9.1 onwards. --}; -+} AGSDriverExtensionDX12; - - /// The space id for DirectX12 intrinsic support - const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 - - - /// Additional topologies supported via extensions --enum AGSPrimitiveTopology -+typedef enum AGSPrimitiveTopology - { - AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, - AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 --}; -+} AGSPrimitiveTopology; - - /// The different modes to control Crossfire behavior. --enum AGSCrossfireMode -+typedef enum AGSCrossfireMode - { - AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering - AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile - AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering --}; -+} AGSCrossfireMode; - - - /// The Crossfire API transfer types --enum AGSAfrTransferType -+typedef enum AGSAfrTransferType - { - AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking - AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking - AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer - AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory - AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory --}; -+} AGSAfrTransferType; - - /// The Crossfire API transfer engines --enum AGSAfrTransferEngine -+typedef enum AGSAfrTransferEngine - { - AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers - AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers - AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers --}; -+} AGSAfrTransferEngine; - - /// The display flags describing various properties of the display. --enum AGSDisplayFlags -+typedef enum AGSDisplayFlags - { - AGS_DISPLAYFLAG_PRIMARY_DISPLAY = 1 << 0, ///< Whether this display is marked as the primary display. Not set on the WACK version. - AGS_DISPLAYFLAG_HDR10 = 1 << 1, ///< HDR10 is supported on this display -@@ -228,35 +225,33 @@ enum AGSDisplayFlags - AGS_DISPLAYFLAG_EYEFINITY_IN_GROUP = 1 << 5, ///< The display is part of the Eyefinity group - AGS_DISPLAYFLAG_EYEFINITY_PREFERRED_DISPLAY = 1 << 6, ///< The display is the preferred display in the Eyefinity group for displaying the UI - AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode --}; -+} AGSDisplayFlags; - --struct AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit -+typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit - - /// The rectangle struct used by AGS. --struct AGSRect -+typedef struct AGSRect - { - int offsetX; ///< Offset on X axis - int offsetY; ///< Offset on Y axis - int width; ///< Width of rectangle - int height; ///< Height of rectangle --}; -+} AGSRect; - - /// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects --struct AGSClipRect -+typedef struct AGSClipRect - { - /// The inclusion mode for the rect -- enum Mode -+ enum - { - ClipRectIncluded = 0, ///< Include the rect - ClipRectExcluded = 1 ///< Exclude the rect -- }; -- -- Mode mode; ///< Include/exclude rect region -+ } mode; ; ///< Include/exclude rect region - AGSRect rect; ///< The rect to include/exclude --}; -+} AGSClipRect; - - /// The display info struct used to describe a display enumerated by AGS --struct AGSDisplayInfo -+typedef struct AGSDisplayInfo - { - char name[ 256 ]; ///< The name of the display - char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName -@@ -296,19 +291,19 @@ struct AGSDisplayInfo - - int logicalDisplayIndex; ///< The internally used index of this display - int adlAdapterIndex; ///< The internally used ADL adapter index --}; -+} AGSDisplayInfo; - --/// The device info struct used to describe a physical GPU enumerated by AGS --struct AGSDeviceInfo -+/// The architecture version -+typedef enum ArchitectureVersion - { -- /// The architecture version -- enum ArchitectureVersion -- { -- ArchitectureVersion_Unknown, ///< Unknown architecture, potentially from another IHV. Check AGSDeviceInfo::vendorId -- ArchitectureVersion_PreGCN, ///< AMD architecture, pre-GCN -- ArchitectureVersion_GCN ///< AMD GCN architecture -- }; -+ ArchitectureVersion_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId -+ ArchitectureVersion_PreGCN, ///< AMD architecture, pre-GCN -+ ArchitectureVersion_GCN ///< AMD GCN architecture -+} ArchitectureVersion; - -+/// The device info struct used to describe a physical GPU enumerated by AGS -+typedef struct AGSDeviceInfo -+{ - ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware - const char* adapterString; ///< The adapter name string - int vendorId; ///< The vendor id -@@ -334,7 +329,7 @@ struct AGSDeviceInfo - int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. - - int adlAdapterIndex; ///< Internally used index into the ADL list of adapters --}; -+} AGSDeviceInfo; - - /// \defgroup general General API functions - /// API for initialization, cleanup, HDR display modes and Crossfire GPU count -@@ -343,16 +338,15 @@ struct AGSDeviceInfo - typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( int allocationSize ); ///< AGS user defined allocation prototype - typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype - -- /// The configuration options that can be passed in to \ref agsInit --struct AGSConfiguration -+/// The configuration options that can be passed in to \ref agsInit -+typedef struct AGSConfiguration - { - AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used - AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used -- AGSCrossfireMode crossfireMode; ///< Desired Crossfire mode --}; -+} AGSConfiguration; - - /// The top level GPU information returned from \ref agsInit --struct AGSGPUInfo -+typedef struct AGSGPUInfo - { - int agsVersionMajor; ///< Major field of Major.Minor.Patch AGS version number - int agsVersionMinor; ///< Minor field of Major.Minor.Patch AGS version number -@@ -364,22 +358,20 @@ struct AGSGPUInfo - - int numDevices; ///< Number of GPUs in the system - AGSDeviceInfo* devices; ///< List of GPUs in the system --}; -+} AGSGPUInfo; - - /// The struct to specify the display settings to the driver. --struct AGSDisplaySettings -+typedef struct AGSDisplaySettings - { - /// The display mode -- enum Mode -+ enum - { - Mode_SDR, ///< SDR mode - Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. - Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. - Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. Values in the range of 0.0 to 125.0 where 125.0 == AGSDisplayInfo::maxLuminance. - Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain -- }; -- -- Mode mode; ///< The display mode to set the display into -+ } mode; ///< The display mode to set the display into - - double chromaticityRedX; ///< Red display primary X coord - double chromaticityRedY; ///< Red display primary Y coord -@@ -398,7 +390,7 @@ struct AGSDisplaySettings - - double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) - double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) --}; -+} AGSDisplaySettings; - - /// - /// Function used to initialize the AGS library. -@@ -526,7 +518,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context - /// @{ - - /// The struct to specify the existing DX11 device creation parameters --struct AGSDX11DeviceCreationParams -+typedef struct AGSDX11DeviceCreationParams - { - IDXGIAdapter* pAdapter; ///< Consult the DX documentation on D3D11CreateDevice for this parameter - D3D_DRIVER_TYPE DriverType; ///< Consult the DX documentation on D3D11CreateDevice for this parameter -@@ -536,13 +528,13 @@ struct AGSDX11DeviceCreationParams - UINT FeatureLevels; ///< Consult the DX documentation on D3D11CreateDevice for this parameter - UINT SDKVersion; ///< Consult the DX documentation on D3D11CreateDevice for this parameter - const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc; ///< Optional swapchain description. Specify this to invoke D3D11CreateDeviceAndSwapChain instead of D3D11CreateDevice. This must be null on the WACK compliant version --}; -+} AGSDX11DeviceCreationParams; - - #define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX11ExtensionParams - #define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version - - /// The struct to specify DX11 additional device creation parameters --struct AGSDX11ExtensionParams -+typedef struct AGSDX11ExtensionParams - { - unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. #define AmdDxExtShaderIntrinsicsUAVSlot. - /// The default slot is 7, but the caller is free to use an alternative slot. -@@ -550,17 +542,17 @@ struct AGSDX11ExtensionParams - UINT appVersion; ///< Application version - const WCHAR* pEngineName; ///< Engine name - UINT engineVersion; ///< Engine version --}; -+} AGSDX11ExtensionParams; - - /// The struct to hold all the returned parameters from the device creation call --struct AGSDX11ReturnedParams -+typedef struct AGSDX11ReturnedParams - { - ID3D11Device* pDevice; ///< The newly created device - D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device - ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context - IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version - unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See AGSDriverExtensionDX11 --}; -+} AGSDX11ReturnedParams; - - /// - /// Function used to create a D3D11 device with additional AMD-specific initialization parameters. - - -From e0c31d82fb16f5a5b4346bf4c0729613244cfbd1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?J=C3=B3zef=20Kucia?= -Date: Mon, 23 Jul 2018 19:53:20 +0200 -Subject: [PATCH] amd_ags_x64: Add dll. - -This is needed to avoid Wolfenstein 2 showing a driver warning dialog on -AMD hardware. ---- - configure | 2 + - configure.ac | 1 + - dlls/amd_ags_x64/Makefile.in | 6 + - dlls/amd_ags_x64/amd_ags_x64.spec | 29 +++++ - dlls/amd_ags_x64/amd_ags_x64_main.c | 193 ++++++++++++++++++++++++++++ - 5 files changed, 231 insertions(+) - create mode 100644 dlls/amd_ags_x64/Makefile.in - create mode 100644 dlls/amd_ags_x64/amd_ags_x64.spec - create mode 100644 dlls/amd_ags_x64/amd_ags_x64_main.c - -diff --git a/configure b/configure -index 089a87b863b..1e1b06a61dc 100755 ---- a/configure -+++ b/configure -@@ -904,6 +904,7 @@ enable_adsldp - enable_adsldpc - enable_advapi32 - enable_advpack -+enable_amd_ags_x64 - enable_amsi - enable_amstream - enable_api_ms_win_appmodel_identity_l1_1_0 -@@ -19271,6 +19272,7 @@ wine_fn_config_makefile dlls/advapi32 enable_advapi32 - wine_fn_config_makefile dlls/advapi32/tests enable_tests - wine_fn_config_makefile dlls/advpack enable_advpack - wine_fn_config_makefile dlls/advpack/tests enable_tests -+wine_fn_config_makefile dlls/amd_ags_x64 enable_amd_ags_x64 - wine_fn_config_makefile dlls/amsi enable_amsi - wine_fn_config_makefile dlls/amstream enable_amstream - wine_fn_config_makefile dlls/amstream/tests enable_tests -diff --git a/configure.ac b/configure.ac -index 224bc2e7030..49c37fabe0c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -2896,6 +2896,7 @@ WINE_CONFIG_MAKEFILE(dlls/advapi32) - WINE_CONFIG_MAKEFILE(dlls/advapi32/tests) - WINE_CONFIG_MAKEFILE(dlls/advpack) - WINE_CONFIG_MAKEFILE(dlls/advpack/tests) -+WINE_CONFIG_MAKEFILE(dlls/amd_ags_x64) - WINE_CONFIG_MAKEFILE(dlls/amsi) - WINE_CONFIG_MAKEFILE(dlls/amstream) - WINE_CONFIG_MAKEFILE(dlls/amstream/tests) -diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in -new file mode 100644 -index 00000000000..7545260d1de ---- /dev/null -+++ b/dlls/amd_ags_x64/Makefile.in -@@ -0,0 +1,6 @@ -+MODULE = amd_ags_x64.dll -+IMPORTS = vulkan-1 -+IMPORTLIB = amd_ags_x64 -+ -+C_SRCS = \ -+ amd_ags_x64_main.c -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -new file mode 100644 -index 00000000000..b4da6136a64 ---- /dev/null -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -0,0 +1,29 @@ -+1 stdcall agsDeInit(ptr) -+2 stub agsDriverExtensionsDX11_BeginUAVOverlap -+3 stub agsDriverExtensionsDX11_CreateBuffer -+4 stub agsDriverExtensionsDX11_CreateTexture1D -+5 stub agsDriverExtensionsDX11_CreateTexture2D -+6 stub agsDriverExtensionsDX11_CreateTexture3D -+7 stub agsDriverExtensionsDX11_DeInit -+8 stub agsDriverExtensionsDX11_EndUAVOverlap -+9 stub agsDriverExtensionsDX11_GetMaxClipRects -+10 stub agsDriverExtensionsDX11_IASetPrimitiveTopology -+11 stub agsDriverExtensionsDX11_Init -+12 stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect -+13 stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect -+14 stub agsDriverExtensionsDX11_MultiDrawInstancedIndirect -+15 stub agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect -+16 stub agsDriverExtensionsDX11_NotifyResourceBeginAllAccess -+17 stub agsDriverExtensionsDX11_NotifyResourceEndAllAccess -+18 stub agsDriverExtensionsDX11_NotifyResourceEndWrites -+19 stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs -+20 stub agsDriverExtensionsDX11_SetClipRects -+21 stub agsDriverExtensionsDX11_SetDepthBounds -+22 stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled -+23 stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount -+24 stub agsDriverExtensionsDX11_SetViewBroadcastMasks -+25 stub agsDriverExtensionsDX12_DeInit -+26 stub agsDriverExtensionsDX12_Init -+27 stub agsGetCrossfireGPUCount -+28 stdcall agsInit(ptr ptr ptr) -+29 stub agsSetDisplayMode -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -new file mode 100644 -index 00000000000..382447089bc ---- /dev/null -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -0,0 +1,191 @@ -+#include "config.h" -+ -+#include -+#include -+ -+#include "windef.h" -+#include "winbase.h" -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+#include "wine/vulkan.h" -+ -+#include "d3d11.h" -+#include "d3d12.h" -+ -+#include "amd_ags.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); -+ -+struct AGSContext -+{ -+ unsigned int device_count; -+ AGSDeviceInfo *devices; -+ VkPhysicalDeviceProperties *properties; -+}; -+ -+static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, -+ VkPhysicalDeviceProperties **out) -+{ -+ VkPhysicalDeviceProperties *properties = NULL; -+ VkPhysicalDevice *vk_physical_devices = NULL; -+ VkInstance vk_instance = VK_NULL_HANDLE; -+ VkInstanceCreateInfo create_info; -+ AGSReturnCode ret = AGS_SUCCESS; -+ uint32_t count, i; -+ VkResult vr; -+ -+ *out = NULL; -+ *out_count = 0; -+ -+ memset(&create_info, 0, sizeof(create_info)); -+ create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; -+ if ((vr = vkCreateInstance(&create_info, NULL, &vk_instance) < 0)) -+ { -+ WARN("Failed to create Vulkan instance, vr %d.\n", vr); -+ goto done; -+ } -+ -+ if ((vr = vkEnumeratePhysicalDevices(vk_instance, &count, NULL)) < 0) -+ { -+ WARN("Failed to enumerate devices, vr %d.\n", vr); -+ goto done; -+ } -+ -+ if (!(vk_physical_devices = heap_calloc(count, sizeof(*vk_physical_devices)))) -+ { -+ WARN("Failed to allocate memory.\n"); -+ ret = AGS_OUT_OF_MEMORY; -+ goto done; -+ } -+ -+ if ((vr = vkEnumeratePhysicalDevices(vk_instance, &count, vk_physical_devices)) < 0) -+ { -+ WARN("Failed to enumerate devices, vr %d.\n", vr); -+ goto done; -+ } -+ -+ if (!(properties = heap_calloc(count, sizeof(*properties)))) -+ { -+ WARN("Failed to allocate memory.\n"); -+ ret = AGS_OUT_OF_MEMORY; -+ goto done; -+ } -+ -+ for (i = 0; i < count; ++i) -+ vkGetPhysicalDeviceProperties(vk_physical_devices[i], &properties[i]); -+ -+ *out_count = count; -+ *out = properties; -+ -+done: -+ heap_free(vk_physical_devices); -+ if (vk_instance) -+ vkDestroyInstance(vk_instance, NULL); -+ return ret; -+} -+ -+static AGSReturnCode init_ags_context(AGSContext *context) -+{ -+ AGSReturnCode ret; -+ unsigned int i; -+ -+ context->device_count = 0; -+ context->devices = NULL; -+ context->properties = NULL; -+ -+ ret = vk_get_physical_device_properties(&context->device_count, &context->properties); -+ if (ret != AGS_SUCCESS || !context->device_count) -+ return ret; -+ -+ if (!(context->devices = heap_calloc(context->device_count, sizeof(*context->devices)))) -+ { -+ WARN("Failed to allocate memory.\n"); -+ heap_free(context->properties); -+ return AGS_OUT_OF_MEMORY; -+ } -+ -+ for (i = 0; i < context->device_count; ++i) -+ { -+ const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; -+ AGSDeviceInfo *device = &context->devices[i]; -+ -+ device->adapterString = vk_properties->deviceName; -+ device->vendorId = vk_properties->vendorID; -+ device->deviceId = vk_properties->deviceID; -+ -+ if (device->vendorId == 0x1002) -+ device->architectureVersion = ArchitectureVersion_GCN; -+ -+ if (!i) -+ device->isPrimaryDevice = 1; -+ } -+ -+ return AGS_SUCCESS; -+} -+ -+AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *config, AGSGPUInfo *gpu_info) -+{ -+ struct AGSContext *object; -+ AGSReturnCode ret; -+ -+ TRACE("context %p, config %p, gpu_info %p.\n", context, config, gpu_info); -+ -+ if (!context || !gpu_info) -+ return AGS_INVALID_ARGS; -+ -+ if (config) -+ FIXME("Ignoring config %p.\n", config); -+ -+ if (!(object = heap_alloc(sizeof(*object)))) -+ return AGS_OUT_OF_MEMORY; -+ -+ if ((ret = init_ags_context(object)) != AGS_SUCCESS) -+ { -+ heap_free(object); -+ return ret; -+ } -+ -+ memset(gpu_info, 0, sizeof(*gpu_info)); -+ gpu_info->agsVersionMajor = AMD_AGS_VERSION_MAJOR; -+ gpu_info->agsVersionMinor = AMD_AGS_VERSION_MINOR; -+ gpu_info->agsVersionPatch = AMD_AGS_VERSION_PATCH; -+ gpu_info->driverVersion = "18.10.16-180516a-328911C-RadeonSoftwareAdrenalin"; -+ gpu_info->radeonSoftwareVersion = "18.5.1"; -+ gpu_info->numDevices = object->device_count; -+ gpu_info->devices = object->devices; -+ -+ TRACE("Created context %p.\n", object); -+ -+ *context = object; -+ -+ return AGS_SUCCESS; -+} -+ -+AGSReturnCode WINAPI agsDeInit(AGSContext *context) -+{ -+ TRACE("context %p.\n", context); -+ -+ if (context) -+ { -+ heap_free(context->properties); -+ heap_free(context->devices); -+ heap_free(context); -+ } -+ -+ return AGS_SUCCESS; -+} -+ -+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) -+{ -+ TRACE("%p, %u, %p.\n", instance, reason, reserved); -+ -+ switch (reason) -+ { -+ case DLL_PROCESS_ATTACH: -+ DisableThreadLibraryCalls(instance); -+ break; -+ } -+ -+ return TRUE; -+} -From 6c1f7e489f1cf1726e9e818e24a1d45398acf81c Mon Sep 17 00:00:00 2001 -From: Zhiyi Zhang -Date: Tue, 1 Oct 2019 09:28:29 +0800 -Subject: [PATCH] amd_args_x64: Add agsGetCrossfireGPUCount stub. - -Signed-off-by: Zhiyi Zhang ---- - dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- - dlls/amd_ags_x64/amd_ags_x64_main.c | 11 +++++++++++ - 2 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -index b4da6136a64..a302d2fc657 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64.spec -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -24,6 +24,6 @@ - 24 stub agsDriverExtensionsDX11_SetViewBroadcastMasks - 25 stub agsDriverExtensionsDX12_DeInit - 26 stub agsDriverExtensionsDX12_Init --27 stub agsGetCrossfireGPUCount -+27 stdcall agsGetCrossfireGPUCount(ptr ptr) - 28 stdcall agsInit(ptr ptr ptr) - 29 stub agsSetDisplayMode -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 382447089bc..26b39991525 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -176,6 +176,17 @@ AGSReturnCode WINAPI agsDeInit(AGSContext *context) - return AGS_SUCCESS; - } - -+AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count) -+{ -+ TRACE("context %p gpu_count %p stub!\n", context, gpu_count); -+ -+ if (!context || !gpu_count) -+ return AGS_INVALID_ARGS; -+ -+ *gpu_count = 1; -+ return AGS_SUCCESS; -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - TRACE("%p, %u, %p.\n", instance, reason, reserved); -From 64bebf345ed6bb4620938753f7668a85c6bf1410 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Thu, 11 Jun 2020 15:39:32 -0700 -Subject: [PATCH] amd_ags_x64: Build with msvcrt. - -Signed-off-by: Brendan Shanks ---- - dlls/amd_ags_x64/Makefile.in | 2 ++ - dlls/amd_ags_x64/amd_ags_x64_main.c | 2 -- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in -index 7545260d1de..aa7127e2ede 100644 ---- a/dlls/amd_ags_x64/Makefile.in -+++ b/dlls/amd_ags_x64/Makefile.in -@@ -2,5 +2,7 @@ MODULE = amd_ags_x64.dll - IMPORTS = vulkan-1 - IMPORTLIB = amd_ags_x64 - -+EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native -+ - C_SRCS = \ - amd_ags_x64_main.c -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 26b39991525..c6554a17b6f 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -1,5 +1,3 @@ --#include "config.h" -- - #include - #include - -From b0941df623aad8d30fdfe9328cffdb3a1a2e66b1 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Thu, 11 Jun 2020 17:33:56 -0700 -Subject: [PATCH] amd_ags_x64: Update to 5.2.0. - ---- - dlls/amd_ags_x64/amd_ags.h | 577 +++++++++++++++++++++++----- - dlls/amd_ags_x64/amd_ags_x64_main.c | 60 ++- - 2 files changed, 531 insertions(+), 106 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index a83a1f88692..b647f912aa7 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -1,5 +1,5 @@ - // --// Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved. -+// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved. - // - // Permission is hereby granted, free of charge, to any person obtaining a copy - // of this software and associated documentation files (the "Software"), to deal -@@ -24,7 +24,7 @@ - /// \mainpage - /// AGS Library Overview - /// -------------------- --/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query -+/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query - /// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs. - /// - /// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/. -@@ -33,6 +33,15 @@ - /// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ - /// \endinternal - /// -+/// What's new in AGS 5.2.0 since version 5.1 -+/// --------------------------------------- -+/// AGS 5.2 includes the following updates: -+/// * DX12 app registration API -+/// * DX11 breadcrumb marker API for tracking down GPU hangs:\ref agsDriverExtensionsDX11_WriteBreadcrumb -+/// * DX12 extensions now require the creation of the device via \ref agsDriverExtensionsDX12_CreateDevice -+/// * agsGetCrossfireGPUCount has been removed in favor of retrieving the value from \ref agsDriverExtensionsDX11_CreateDevice -+/// * API change that fixes a reference leak in \ref agsDriverExtensionsDX11_DestroyDevice -+/// - /// What's new in AGS 5.1.1 since version 5.0.6 - /// --------------------------------------- - /// AGS 5.1.1 includes the following updates: -@@ -50,7 +59,7 @@ - /// - /// What's new in AGS 5.x since version 4.x - /// --------------------------------------- --/// Version 5.x is a major overhaul of the library designed to provide a much clearer view of the GPUs in the system and the displays attached to them. -+/// Version 5.x is a major overhaul of the library designed to provide a much clearer view of the GPUs in the system and the displays attached to them. - /// It also exposes the ability to query each display for HDR capabilities and put those HDR capable displays into various HDR modes. - /// Some functions such as agsGetGPUMemorySize and agsGetEyefinityConfigInfo have been removed in favor of including this information in the device & display enumeration. - /// Features include: -@@ -69,8 +78,8 @@ - /// * AGSSample - /// * CrossfireSample - /// * EyefinitySample --/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state. --/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more -+/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state. -+/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more - /// extensive example of Eyefinity setup than the basic example provided in AGSSample. - /// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples. - /// -@@ -80,17 +89,16 @@ - /// * Include the amd_ags.h header file from your source code. - /// * Include the AGS hlsl files if you are using the shader intrinsics. - /// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS. --/// * On game initialization, call agsInit() passing in the address of the context. On success, this function will return a valid context pointer. --/// * The agsInit() function should be called before the D3D device is created if the Crossfire mode is specified. -+/// * On game initialization, call \ref agsInit passing in the address of the context. On success, this function will return a valid context pointer. - /// --/// Don't forget to cleanup AGS by calling agsDeInit() when the app exits, after the device has been destroyed. -+/// Don't forget to cleanup AGS by calling \ref agsDeInit when the app exits, after the device has been destroyed. - - #ifndef AMD_AGS_H - #define AMD_AGS_H - - #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version --#define AMD_AGS_VERSION_MINOR 1 ///< AGS minor version --#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version -+#define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version -+#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version - - #ifdef __cplusplus - extern "C" { -@@ -138,42 +146,44 @@ typedef enum AGSReturnCode - /// The DirectX11 extension support bits - typedef enum AGSDriverExtensionDX11 - { -- AGS_DX11_EXTENSION_QUADLIST = 1 << 0, -- AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, -- AGS_DX11_EXTENSION_UAV_OVERLAP = 1 << 2, -- AGS_DX11_EXTENSION_DEPTH_BOUNDS_TEST = 1 << 3, -- AGS_DX11_EXTENSION_MULTIDRAWINDIRECT = 1 << 4, -- AGS_DX11_EXTENSION_MULTIDRAWINDIRECT_COUNTINDIRECT = 1 << 5, -- AGS_DX11_EXTENSION_CROSSFIRE_API = 1 << 6, -- AGS_DX11_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 7, -- AGS_DX11_EXTENSION_INTRINSIC_READLANE = 1 << 8, -- AGS_DX11_EXTENSION_INTRINSIC_LANEID = 1 << 9, -- AGS_DX11_EXTENSION_INTRINSIC_SWIZZLE = 1 << 10, -- AGS_DX11_EXTENSION_INTRINSIC_BALLOT = 1 << 11, -- AGS_DX11_EXTENSION_INTRINSIC_MBCOUNT = 1 << 12, -- AGS_DX11_EXTENSION_INTRINSIC_COMPARE3 = 1 << 13, -- AGS_DX11_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 14, -+ AGS_DX11_EXTENSION_QUADLIST = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_SCREENRECTLIST = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_UAV_OVERLAP = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_DEPTH_BOUNDS_TEST = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_MULTIDRAWINDIRECT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_MULTIDRAWINDIRECT_COUNTINDIRECT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_CROSSFIRE_API = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_READLANE = 1 << 8, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_LANEID = 1 << 9, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_SWIZZLE = 1 << 10, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_BALLOT = 1 << 11, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_MBCOUNT = 1 << 12, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_MED3 = 1 << 13, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 14, ///< Supported in Radeon Software Version 16.9.2 onwards. - AGS_DX11_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 15, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX11_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 16, ///< Supported in Radeon Software Version 17.9.1 onwards. -- AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, -- AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, -- AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19 ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX11_EXTENSION_CREATE_SHADER_CONTROLS = 1 << 17, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, ///< Supported in Radeon Software Version 16.12.1 onwards. -+ AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19, ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX11_EXTENSION_BREADCRUMB_MARKERS = 1 << 20, ///< Supported in Radeon Software Version 17.11.1 onwards. - } AGSDriverExtensionDX11; - - /// The DirectX12 extension support bits - typedef enum AGSDriverExtensionDX12 - { -- AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -- AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -- AGS_DX12_EXTENSION_INTRINSIC_LANEID = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -- AGS_DX12_EXTENSION_INTRINSIC_SWIZZLE = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -- AGS_DX12_EXTENSION_INTRINSIC_BALLOT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -- AGS_DX12_EXTENSION_INTRINSIC_MBCOUNT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -- AGS_DX12_EXTENSION_INTRINSIC_COMPARE3 = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -- AGS_DX12_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 (driver version 16.40.2311) onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_READFIRSTLANE = 1 << 0, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_READLANE = 1 << 1, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_LANEID = 1 << 2, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_SWIZZLE = 1 << 3, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_BALLOT = 1 << 4, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_MBCOUNT = 1 << 5, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_MED3 = 1 << 6, ///< Supported in Radeon Software Version 16.9.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_BARYCENTRICS = 1 << 7, ///< Supported in Radeon Software Version 16.9.2 onwards. - AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. -- AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10 ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10, ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11 ///< Supported in Radeon Software Version 17.9.1 onwards. - } AGSDriverExtensionDX12; - - /// The space id for DirectX12 intrinsic support -@@ -183,37 +193,10 @@ const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420 - /// Additional topologies supported via extensions - typedef enum AGSPrimitiveTopology - { -- AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, -- AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 -+ AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, ///< Quad list -+ AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 ///< Screen rect list - } AGSPrimitiveTopology; - --/// The different modes to control Crossfire behavior. --typedef enum AGSCrossfireMode --{ -- AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering -- AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile -- AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering --} AGSCrossfireMode; -- -- --/// The Crossfire API transfer types --typedef enum AGSAfrTransferType --{ -- AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking -- AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking -- AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer -- AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory -- AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory --} AGSAfrTransferType; -- --/// The Crossfire API transfer engines --typedef enum AGSAfrTransferEngine --{ -- AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers -- AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers -- AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers --} AGSAfrTransferEngine; -- - /// The display flags describing various properties of the display. - typedef enum AGSDisplayFlags - { -@@ -227,6 +210,13 @@ typedef enum AGSDisplayFlags - AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode - } AGSDisplayFlags; - -+/// The display settings flags. -+typedef enum AGSDisplaySettingsFlags -+{ -+ AGS_DISPLAYSETTINGSFLAG_DISABLE_LOCAL_DIMMING = 1 << 0, ///< Disables local dimming if possible -+} AGSDisplaySettingsFlags; -+ -+ - typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit - - /// The rectangle struct used by AGS. -@@ -302,7 +292,7 @@ typedef enum ArchitectureVersion - } ArchitectureVersion; - - /// The device info struct used to describe a physical GPU enumerated by AGS --typedef struct AGSDeviceInfo -+typedef struct AGSDeviceInfo_511 - { - ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware - const char* adapterString; ///< The adapter name string -@@ -329,20 +319,71 @@ typedef struct AGSDeviceInfo - int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. - - int adlAdapterIndex; ///< Internally used index into the ADL list of adapters -+} AGSDeviceInfo_511; -+ -+/// The device info struct used to describe a physical GPU enumerated by AGS -+typedef struct AGSDeviceInfo_520 -+{ -+ const char* adapterString; ///< The adapter name string -+ ArchitectureVersion architectureVersion; ///< Set to Unknown if not AMD hardware -+ int vendorId; ///< The vendor id -+ int deviceId; ///< The device id -+ int revisionId; ///< The revision id -+ -+ int numCUs; ///< Number of compute units. Zero if not GCN onwards -+ int numROPs; ///< Number of ROPs -+ int coreClock; ///< Core clock speed at 100% power in MHz -+ int memoryClock; ///< Memory clock speed at 100% power in MHz -+ int memoryBandwidth; ///< Memory bandwidth in MB/s -+ float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD -+ -+ int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. -+ long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. -+ -+ int numDisplays; ///< The number of active displays found to be attached to this adapter. -+ AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ -+ int eyefinityEnabled; ///< Indicates if Eyefinity is active -+ int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. -+ int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. -+ int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. -+ -+ int adlAdapterIndex; ///< Internally used index into the ADL list of adapters -+} AGSDeviceInfo_520; -+ -+typedef union AGSDeviceInfo -+{ -+ AGSDeviceInfo_511 agsDeviceInfo511; -+ AGSDeviceInfo_520 agsDeviceInfo520; - } AGSDeviceInfo; - - /// \defgroup general General API functions - /// API for initialization, cleanup, HDR display modes and Crossfire GPU count - /// @{ - --typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( int allocationSize ); ///< AGS user defined allocation prototype --typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype -+typedef void* (__stdcall *AGS_ALLOC_CALLBACK_511)( int allocationSize ); ///< AGS user defined allocation prototype -+typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype -+typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype - - /// The configuration options that can be passed in to \ref agsInit --typedef struct AGSConfiguration -+typedef struct AGSConfiguration_511 -+{ -+ AGS_ALLOC_CALLBACK_511 allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used -+ AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used -+} AGSConfiguration_511; -+ -+typedef struct AGSConfiguration_520 - { - AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used - AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used -+} AGSConfiguration_520; -+ -+typedef union AGSConfiguration -+{ -+ AGSConfiguration_511 agsConfiguration511; -+ AGSConfiguration_520 agsConfiguration520; - } AGSConfiguration; - - /// The top level GPU information returned from \ref agsInit -@@ -369,7 +410,7 @@ typedef struct AGSDisplaySettings - Mode_SDR, ///< SDR mode - Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. - Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. -- Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. Values in the range of 0.0 to 125.0 where 125.0 == AGSDisplayInfo::maxLuminance. -+ Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. 1.0 == 80 nits. Tonemap your scene to the range of 0.0 to AGSDisplayInfo::maxLuminance. - Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain - } mode; ///< The display mode to set the display into - -@@ -390,13 +431,16 @@ typedef struct AGSDisplaySettings - - double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) - double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) -+ -+ // ADDED IN 5.2.0 -+ int flags; ///< Bitfield of ::AGSDisplaySettingsFlags - } AGSDisplaySettings; - - /// - /// Function used to initialize the AGS library. - /// Must be called prior to any of the subsequent AGS API calls. - /// Must be called prior to ID3D11Device or ID3D12Device creation. --/// \note This function will fail with AGS_ERROR_LEGACY_DRIVER in Catalyst versions before 12.20. -+/// \note This function will fail with \ref AGS_ERROR_LEGACY_DRIVER in Catalyst versions before 12.20. - /// \note It is good practice to check the AGS version returned from AGSGPUInfo against the version defined in the header in case a mismatch between the dll and header has occurred. - /// - /// \param [in, out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. -@@ -419,6 +463,7 @@ AMD_AGS_API AGSReturnCode agsDeInit( AGSContext* context ); - /// \param [in] context Pointer to a context. - /// \param [out] numGPUs Number of GPUs used for Crossfire acceleration - /// -+/// REMOVED IN 5.2.0 - AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* numGPUs ); - - /// -@@ -427,7 +472,6 @@ AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* num - /// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc). - /// \note HDR10 PQ mode requires a 1010102 swapchain. - /// \note HDR10 scRGB mode requires an FP16 swapchain. --/// \note Freesync2 Gamma mode requires a 1010102 swapchain. - /// \note Freesync2 scRGB mode requires an FP16 swapchain. - /// \note Dolby Vision requires a 8888 UNORM swapchain. - /// -@@ -444,9 +488,65 @@ AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceInde - /// DirectX12 driver extensions - /// @{ - --/// \defgroup dx12init Initialization and Cleanup -+/// \defgroup dx12init Device creation and cleanup -+/// It is now mandatory to call \ref agsDriverExtensionsDX12_CreateDevice when creating a device if the user wants to access any future DX12 AMD extensions. -+/// The corresponding \ref agsDriverExtensionsDX12_DestroyDevice call must be called to release the device and free up the internal resources allocated by the create call. - /// @{ - -+/// The struct to specify the DX12 device creation parameters -+typedef struct AGSDX12DeviceCreationParams -+{ -+ IDXGIAdapter* pAdapter; ///< Pointer to the adapter to use when creating the device. This may be null. -+ IID iid; ///< The interface ID for the type of device to be created. -+ D3D_FEATURE_LEVEL FeatureLevel; ///< The minimum feature level to create the device with. -+} AGSDX12DeviceCreationParams; -+ -+#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams -+#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version -+ -+/// The struct to specify DX12 additional device creation parameters -+typedef struct AGSDX12ExtensionParams -+{ -+ const WCHAR* pAppName; ///< Application name -+ const WCHAR* pEngineName; ///< Engine name -+ unsigned int appVersion; ///< Application version -+ unsigned int engineVersion; ///< Engine version -+} AGSDX12ExtensionParams; -+ -+/// The struct to hold all the returned parameters from the device creation call -+typedef struct AGSDX12ReturnedParams -+{ -+ ID3D12Device* pDevice; ///< The newly created device -+ unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX12_CreateDevice will fill in to indicate which extensions are supported. See \ref AGSDriverExtensionDX12 -+} AGSDX12ReturnedParams; -+ -+ -+/// -+/// Function used to create a D3D12 device with additional AMD-specific initialization parameters. -+/// -+/// When using the HLSL shader extensions please note: -+/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. -+/// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. -+/// * The intrinsic instructions require a 5.1 shader model. -+/// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. -+/// -+/// \param [in] context Pointer to a context. This is generated by \ref agsInit -+/// \param [in] creationParams Pointer to the struct to specify the existing DX12 device creation parameters. -+/// \param [in] extensionParams Optional pointer to the struct to specify DX12 additional device creation parameters. -+/// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_CreateDevice( AGSContext* context, const AGSDX12DeviceCreationParams* creationParams, const AGSDX12ExtensionParams* extensionParams, AGSDX12ReturnedParams* returnedParams ); -+ -+/// -+/// Function to destroy the D3D12 device. -+/// This call will also cleanup any AMD-specific driver extensions for D3D12. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] device Pointer to the D3D12 device. -+/// \param [out] deviceReferences Optional pointer to an unsigned int that will be set to the value returned from device->Release(). -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DestroyDevice( AGSContext* context, ID3D12Device* device, unsigned int* deviceReferences ); -+ - /// - /// Function used to initialize the AMD-specific driver extensions for D3D12. - /// Extensions require support in the driver, therefore it is important to check the extensionsSupported bitfield. -@@ -460,6 +560,7 @@ AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceInde - /// \param [in] device The D3D12 device. - /// \param [out] extensionsSupported Pointer to a bit mask that this function will fill in to indicate which extensions are supported. See ::AGSDriverExtensionDX12 - /// -+/// REMOVED IN 5.2.0 - AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_Init( AGSContext* context, ID3D12Device* device, unsigned int* extensionsSupported ); - - /// -@@ -467,6 +568,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_Init( AGSContext* context, ID3 - /// - /// \param [in] context Pointer to a context. - /// -+/// REMOVED IN 5.2.0 - AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); - - /// @} -@@ -476,7 +578,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); - - /// - /// Function used to push an AMD user marker onto the command list. --/// This is only has an effect if AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of agsDriverExtensionsDX12_Init() -+/// This is only has an effect if AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of \ref agsDriverExtensionsDX12_CreateDevice - /// Supported in Radeon Software Version 17.9.1 onwards. - /// - /// \param [in] context Pointer to a context. -@@ -513,10 +615,18 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context - /// @{ - - /// \defgroup dx11init Device creation and cleanup --/// It is now mandatory to call agsDriverExtensionsDX11_CreateDevice() when creating a device if the user wants to access any DX11 AMD extensions. --/// The corresponding agsDriverExtensionsDX11_DestroyDevice() call must be called to release the device and free up the internal resources allocated by the create call. -+/// It is now mandatory to call \ref agsDriverExtensionsDX11_CreateDevice when creating a device if the user wants to access any DX11 AMD extensions. -+/// The corresponding \ref agsDriverExtensionsDX11_DestroyDevice call must be called to release the device and free up the internal resources allocated by the create call. - /// @{ - -+/// The different modes to control Crossfire behavior. -+typedef enum AGSCrossfireMode -+{ -+ AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering -+ AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile -+ AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering -+} AGSCrossfireMode; -+ - /// The struct to specify the existing DX11 device creation parameters - typedef struct AGSDX11DeviceCreationParams - { -@@ -530,11 +640,8 @@ typedef struct AGSDX11DeviceCreationParams - const DXGI_SWAP_CHAIN_DESC* pSwapChainDesc; ///< Optional swapchain description. Specify this to invoke D3D11CreateDeviceAndSwapChain instead of D3D11CreateDevice. This must be null on the WACK compliant version - } AGSDX11DeviceCreationParams; - --#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX11ExtensionParams --#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version -- - /// The struct to specify DX11 additional device creation parameters --typedef struct AGSDX11ExtensionParams -+typedef struct AGSDX11ExtensionParams_511 - { - unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. #define AmdDxExtShaderIntrinsicsUAVSlot. - /// The default slot is 7, but the caller is free to use an alternative slot. -@@ -542,30 +649,80 @@ typedef struct AGSDX11ExtensionParams - UINT appVersion; ///< Application version - const WCHAR* pEngineName; ///< Engine name - UINT engineVersion; ///< Engine version -+} AGSDX11ExtensionParams_511; -+ -+typedef struct AGSDX11ExtensionParams_520 -+{ -+ const WCHAR* pAppName; ///< Application name -+ const WCHAR* pEngineName; ///< Engine name -+ unsigned int appVersion; ///< Application version -+ unsigned int engineVersion; ///< Engine version -+ unsigned int numBreadcrumbMarkers; ///< The number of breadcrumb markers to allocate. Each marker is a uint64 (ie 8 bytes). If 0, the system is disabled. -+ unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. This must match the slot defined in the HLSL, i.e. "#define AmdDxExtShaderIntrinsicsUAVSlot". -+ /// The default slot is 7, but the caller is free to use an alternative slot. -+ /// If 0 is specified, then the default of 7 will be used. -+ AGSCrossfireMode crossfireMode; ///< Desired Crossfire mode -+} AGSDX11ExtensionParams_520; -+ -+typedef union AGSDX11ExtensionParams -+{ -+ AGSDX11ExtensionParams_511 agsDX11ExtensionParams511; -+ AGSDX11ExtensionParams_520 agsDX11ExtensionParams520; - } AGSDX11ExtensionParams; - - /// The struct to hold all the returned parameters from the device creation call --typedef struct AGSDX11ReturnedParams -+typedef struct AGSDX11ReturnedParams_511 - { - ID3D11Device* pDevice; ///< The newly created device - D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device - ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context - IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version - unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See AGSDriverExtensionDX11 -+} AGSDX11ReturnedParams_511; -+ -+typedef struct AGSDX11ReturnedParams_520 -+{ -+ ID3D11Device* pDevice; ///< The newly created device -+ ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context -+ IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. This is not supported on the WACK compliant version -+ D3D_FEATURE_LEVEL FeatureLevel; ///< The feature level supported by the newly created device -+ unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX11_CreateDevice will fill in to indicate which extensions are supported. See \ref AGSDriverExtensionDX11 -+ unsigned int crossfireGPUCount; ///< The number of GPUs that are active for this app -+ void* breadcrumbBuffer; ///< The CPU buffer returned if the initialization of the breadcrumb was successful. -+} AGSDX11ReturnedParams_520; -+ -+typedef union AGSDX11ReturnedParams -+{ -+ AGSDX11ReturnedParams_511 agsDX11ReturnedParams511; -+ AGSDX11ReturnedParams_520 agsDX11ReturnedParams520; - } AGSDX11ReturnedParams; - - /// - /// Function used to create a D3D11 device with additional AMD-specific initialization parameters. - /// - /// When using the HLSL shader extensions please note: --/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION option, otherwise it will not work. -+/// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. -+/// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. - /// - /// \param [in] context Pointer to a context. This is generated by \ref agsInit - /// \param [in] creationParams Pointer to the struct to specify the existing DX11 device creation parameters. - /// \param [in] extensionParams Optional pointer to the struct to specify DX11 additional device creation parameters. - /// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* context, AGSDX11DeviceCreationParams* creationParams, AGSDX11ExtensionParams* extensionParams, AGSDX11ReturnedParams* returnedParams ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* context, const AGSDX11DeviceCreationParams* creationParams, const AGSDX11ExtensionParams* extensionParams, AGSDX11ReturnedParams* returnedParams ); -+ -+/// -+/// Function to destroy the D3D11 device and its immediate context. -+/// This call will also cleanup any AMD-specific driver extensions for D3D11. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] device Pointer to the D3D11 device. -+/// \param [out] deviceReferences Optional pointer to an unsigned int that will be set to the value returned from device->Release(). -+/// \param [in] immediateContext Pointer to the D3D11 immediate device context. -+/// \param [out] immediateContextReferences Optional pointer to an unsigned int that will be set to the value returned from immediateContext->Release(). -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_520( AGSContext* context, ID3D11Device* device, unsigned int* deviceReferences, ID3D11DeviceContext* immediateContext, unsigned int* immediateContextReferences ); -+ - - /// - /// Function to destroy the D3D11 device. -@@ -575,7 +732,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_CreateDevice( AGSContext* cont - /// \param [in] device Pointer to the D3D11 device. - /// \param [out] references Optional pointer to an unsigned int that will be set to the value returned from device->Release(). - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice( AGSContext* context, ID3D11Device* device, unsigned int* references ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_511( AGSContext* context, ID3D11Device* device, unsigned int* references ); - - /// @} - -@@ -610,6 +767,211 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice( AGSContext* con - /// - /// @} - -+/// \defgroup breadcrumbs Breadcrumb API -+/// API for writing top-of-pipe and bottom-of-pipe markers to help track down GPU hangs. -+/// -+/// The API is available if the \ref AGS_DX11_EXTENSION_BREADCRUMB_MARKERS is present in \ref AGSDX11ReturnedParams::extensionsSupported. -+/// -+/// To use the API, a non zero value needs to be specificed in \ref AGSDX11ExtensionParams::numBreadcrumbMarkers. This enables the API (if available) and allocates a system memory buffer -+/// which is returned to the user in \ref AGSDX11ReturnedParams::breadcrumbBuffer. -+/// -+/// The user can now write markers before and after draw calls using \ref agsDriverExtensionsDX11_WriteBreadcrumb. -+/// -+/// \section background Background -+/// -+/// A top-of-pipe (TOP) command is scheduled for execution as soon as the command processor (CP) reaches the command. -+/// A bottom-of-pipe (BOP) command is scheduled for execution once the previous rendering commands (draw and dispatch) finish execution. -+/// TOP and BOP commands do not block CP. i.e. the CP schedules the command for execution then proceeds to the next command without waiting. -+/// To effectively use TOP and BOP commands, it is important to understand how they interact with rendering commands: -+/// -+/// When the CP encounters a rendering command it queues it for execution and moves to the next command. The queued rendering commands are issued in order. -+/// There can be multiple rendering commands running in parallel. When a rendering command is issued we say it is at the top of the pipe. When a rendering command -+/// finishes execution we say it has reached the bottom of the pipe. -+/// -+/// A BOP command remains in a waiting queue and is executed once prior rendering commands finish. The queue of BOP commands is limited to 64 entries in GCN generation 1, 2, 3, 4 and 5. -+/// If the 64 limit is reached the CP will stop queueing BOP commands and also rendering commands. Developers should limit the number of BOP commands that write markers to avoid contention. -+/// In general, developers should limit both TOP and BOP commands to avoid stalling the CP. -+/// -+/// \subsection eg1 Example 1: -+/// -+/// \code{.cpp} -+/// // Start of a command buffer -+/// WriteMarker(TopOfPipe, 1) -+/// WriteMarker(BottomOfPipe, 2) -+/// WriteMarker(BottomOfPipe, 3) -+/// DrawX -+/// WriteMarker(BottomOfPipe, 4) -+/// WriteMarker(BottomOfPipe, 5) -+/// WriteMarker(TopOfPipe, 6) -+/// // End of command buffer -+/// \endcode -+/// -+/// In the above example, the CP writes markers 1, 2 and 3 without waiting: -+/// Marker 1 is TOP so it's independent from other commands -+/// There's no wait for marker 2 and 3 because there are no draws preceding the BOP commands -+/// Marker 4 is only written once DrawX finishes execution -+/// Marker 5 doesn't wait for additional draws so it is written right after marker 4 -+/// Marker 6 can be written as soon as the CP reaches the command. For instance, it is very possible that CP writes marker 6 while DrawX -+/// is running and therefore marker 6 gets written before markers 4 and 5 -+/// -+/// \subsection eg2 Example 2: -+/// -+/// \code{.cpp} -+/// WriteMarker(TopOfPipe, 1) -+/// DrawX -+/// WriteMarker(BottomOfPipe, 2) -+/// WriteMarker(TopOfPipe, 3) -+/// DrawY -+/// WriteMarker(BottomOfPipe, 4) -+/// \endcode -+/// -+/// In this example marker 1 is written before the start of DrawX -+/// Marker 2 is written once DrawX finishes execution -+/// Similarly marker 3 is written before the start of DrawY -+/// Marker 4 is written once DrawY finishes execution -+/// In case of a GPU hang, if markers 1 and 3 are written but markers 2 and 4 are missing we can conclude that: -+/// The CP has reached both DrawX and DrawY commands since marker 1 and 3 are present -+/// The fact that marker 2 and 4 are missing means that either DrawX is hanging while DrawY is at the top of the pipe or both DrawX and DrawY -+/// started and both are simultaneously hanging -+/// -+/// \subsection eg3 Example 3: -+/// -+/// \code{.cpp} -+/// // Start of a command buffer -+/// WriteMarker(BottomOfPipe, 1) -+/// DrawX -+/// WriteMarker(BottomOfPipe, 2) -+/// DrawY -+/// WriteMarker(BottomOfPipe, 3) -+/// DrawZ -+/// WriteMarker(BottomOfPipe, 4) -+/// // End of command buffer -+/// \endcode -+/// -+/// In this example marker 1 is written before the start of DrawX -+/// Marker 2 is written once DrawX finishes -+/// Marker 3 is written once DrawY finishes -+/// Marker 4 is written once DrawZ finishes -+/// If the GPU hangs and only marker 1 is written we can conclude that the hang is happening in either DrawX, DrawY or DrawZ -+/// If the GPU hangs and only marker 1 and 2 are written we can conclude that the hang is happening in DrawY or DrawZ -+/// If the GPU hangs and only marker 4 is missing we can conclude that the hang is happening in DrawZ -+/// -+/// \subsection eg4 Example 4: -+/// -+/// \code{.cpp} -+/// Start of a command buffer -+/// WriteMarker(TopOfPipe, 1) -+/// DrawX -+/// WriteMarker(TopOfPipe, 2) -+/// DrawY -+/// WriteMarker(TopOfPipe, 3) -+/// DrawZ -+/// // End of command buffer -+/// \endcode -+/// -+/// In this example, in case the GPU hangs and only marker 1 is written we can conclude that the hang is happening in DrawX -+/// In case the GPU hangs and only marker 1 and 2 are written we can conclude that the hang is happening in DrawX or DrawY -+/// In case the GPU hangs and all 3 markers are written we can conclude that the hang is happening in any of DrawX, DrawY or DrawZ -+/// -+/// \subsection eg5 Example 5: -+/// -+/// \code{.cpp} -+/// DrawX -+/// WriteMarker(TopOfPipe, 1) -+/// WriteMarker(BottomOfPipe, 2) -+/// DrawY -+/// WriteMarker(TopOfPipe, 3) -+/// WriteMarker(BottomOfPipe, 4) -+/// \endcode -+/// -+/// Marker 1 is written right after DrawX is queued for execution. -+/// Marker 2 is only written once DrawX finishes execution. -+/// Marker 3 is written right after DrawY is queued for execution. -+/// Marker 4 is only written once DrawY finishes execution -+/// If marker 1 is written we would know that the CP has reached the command DrawX (DrawX at the top of the pipe). -+/// If marker 2 is written we can say that DrawX has finished execution (DrawX at the bottom of the pipe). -+/// In case the GPU hangs and only marker 1 and 3 are written we can conclude that the hang is happening in DrawX or DrawY -+/// In case the GPU hangs and only marker 1 is written we can conclude that the hang is happening in DrawX -+/// In case the GPU hangs and only marker 4 is missing we can conclude that the hang is happening in DrawY -+/// -+/// \section data Retrieving GPU Data -+/// -+/// In the event of a GPU hang, the user can inspect the system memory buffer to determine which draw has caused the hang. -+/// For example: -+/// \code{.cpp} -+/// // Force the work to be flushed to prevent CPU ahead of GPU -+/// g_pImmediateContext->Flush(); -+/// -+/// // Present the information rendered to the back buffer to the front buffer (the screen) -+/// HRESULT hr = g_pSwapChain->Present( 0, 0 ); -+/// -+/// // Read the marker data buffer once detect device lost -+/// if ( hr != S_OK ) -+/// { -+/// for (UINT i = 0; i < g_NumMarkerWritten; i++) -+/// { -+/// UINT64* pTempData; -+/// pTempData = static_cast(pMarkerBuffer); -+/// -+/// // Write the marker data to file -+/// ofs << i << "\r\n"; -+/// ofs << std::hex << *(pTempData + i * 2) << "\r\n"; -+/// ofs << std::hex << *(pTempData + (i * 2 + 1)) << "\r\n"; -+/// -+/// WCHAR s1[256]; -+/// setlocale(LC_NUMERIC, "en_US.iso88591"); -+/// -+/// // Output the marker data to console -+/// swprintf(s1, 256, L" The Draw count is %d; The Top maker is % 016llX and the Bottom marker is % 016llX \r\n", i, *(pTempData + i * 2), *(pTempData + (i * 2 + 1))); -+/// -+/// OutputDebugStringW(s1); -+/// } -+/// } -+/// \endcode -+/// -+/// The console output would resemble something like: -+/// \code{.cpp} -+/// D3D11: Removing Device. -+/// D3D11 ERROR: ID3D11Device::RemoveDevice: Device removal has been triggered for the following reason (DXGI_ERROR_DEVICE_HUNG: The Device took an unreasonable amount of time to execute its commands, or the hardware crashed/hung. As a result, the TDR (Timeout Detection and Recovery) mechanism has been triggered. The current Device Context was executing commands when the hang occurred. The application may want to respawn and fallback to less aggressive use of the display hardware). [ EXECUTION ERROR #378: DEVICE_REMOVAL_PROCESS_AT_FAULT] -+/// The Draw count is 0; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF -+/// The Draw count is 1; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF -+/// The Draw count is 2; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF -+/// The Draw count is 3; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF -+/// The Draw count is 4; The Top maker is 00000000DEADCAFE and the Bottom marker is 00000000DEADBEEF -+/// The Draw count is 5; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD -+/// The Draw count is 6; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD -+/// The Draw count is 7; The Top maker is CDCDCDCDCDCDCDCD and the Bottom marker is CDCDCDCDCDCDCDCD -+/// \endcode -+/// -+/// @{ -+ -+/// The breadcrumb marker struct used by \ref agsDriverExtensionsDX11_WriteBreadcrumb -+typedef struct AGSBreadcrumbMarker -+{ -+ unsigned long long markerData; ///< The user data to write. -+ enum -+ { -+ TopOfPipe = 0, ///< Top-of-pipe marker -+ BottomOfPipe = 1 ///< Bottom-of-pipe marker -+ } type; ///< Whether this marker is top or bottom of pipe. -+ unsigned int index; ///< The index of the marker. This should be less than the value specified in \ref AGSDX11ExtensionParams::numBreadcrumbMarkers -+} AGSBreadcrumbMarker; -+ -+/// -+/// Function to write a breadcrumb marker. -+/// -+/// This method inserts a write marker operation in the GPU command stream. In the case where the GPU is hanging the write -+/// command will never be reached and the marker will never get written to memory. -+/// -+/// In order to use this function, \ref AGSDX11ExtensionParams::numBreadcrumbMarkers must be set to a non zero value. -+/// -+/// \param [in] context Pointer to a context. -+/// \param [in] marker Pointer to a marker. -+/// -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* context, const AGSBreadcrumbMarker* marker ); -+ -+/// @} -+ - /// \defgroup dx11misc Misc Extensions - /// API for depth bounds test, UAV overlap and prim topologies - /// @{ -@@ -618,34 +980,37 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice( AGSContext* con - /// Function used to set the primitive topology. If you are using any of the extended topology types, then this function should - /// be called to set ALL topology types. - /// --/// The Quad List extension is a convenient way to submit quads without using an index buffer. Note that this still submits two triangles at the driver level. -+/// The Quad List extension is a convenient way to submit quads without using an index buffer. Note that this still submits two triangles at the driver level. - /// In order to use this function, AGS must already be initialized and agsDriverExtensionsDX11_Init must have been called successfully. - /// --/// The Screen Rect extension, which is only available on GCN hardware, allows the user to pass in three of the four corners of a rectangle. --/// The hardware then uses the bounding box of the vertices to rasterize the rectangle primitive (i.e. as a rectangle rather than two triangles). -+/// The Screen Rect extension, which is only available on GCN hardware, allows the user to pass in three of the four corners of a rectangle. -+/// The hardware then uses the bounding box of the vertices to rasterize the rectangle primitive (i.e. as a rectangle rather than two triangles). - /// \note Note that this will not return valid interpolated values, only valid SV_Position values. - /// \note If either the Quad List or Screen Rect extension are used, then agsDriverExtensionsDX11_IASetPrimitiveTopology should be called in place of the native DirectX11 equivalent all the time. - /// - /// \param [in] context Pointer to a context. --/// \param [in] topology The topology to set on the D3D11 device. This can be either an AGS-defined topology such as AGS_PRIMITIVE_TOPOLOGY_QUAD_LIST -+/// \param [in] topology The topology to set on the D3D11 device. This can be either an AGS-defined topology such as AGS_PRIMITIVE_TOPOLOGY_QUADLIST - /// or a standard D3D-defined topology such as D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP. - /// NB. the AGS-defined types will require casting to a D3D_PRIMITIVE_TOPOLOGY type. - /// - AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSContext* context, enum D3D_PRIMITIVE_TOPOLOGY topology ); - - /// --/// Function used indicate to the driver it can overlap the subsequent batch of back-to-back dispatches. -+/// Function used indicate to the driver that it doesn't need to sync the UAVs bound for the subsequent set of back-to-back dispatches. - /// When calling back-to-back draw calls or dispatch calls that write to the same UAV, the AMD DX11 driver will automatically insert a barrier to ensure there are no write after write (WAW) hazards. - /// If the app can guarantee there is no overlap between the writes between these calls, then this extension will remove those barriers allowing the work to run in parallel on the GPU. - /// - /// Usage would be as follows: - /// \code{.cpp} -+/// m_device->Dispatch( ... ); // First call that writes to the UAV -+/// - /// // Disable automatic WAW syncs - /// agsDriverExtensionsDX11_BeginUAVOverlap( m_agsContext ); - /// --/// // Submit back-to-back dispatches that write to the same UAV --/// m_device->Dispatch( ... ); // First half of UAV --/// m_device->Dispatch( ... ); // Second half of UAV -+/// // Submit other dispatches that write to the same UAV concurrently -+/// m_device->Dispatch( ... ); -+/// m_device->Dispatch( ... ); -+/// m_device->Dispatch( ... ); - /// - /// // Reenable automatic WAW syncs - /// agsDriverExtensionsDX11_EndUAVOverlap( m_agsContext ); -@@ -713,6 +1078,8 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* co - /// }; - /// \endcode - /// -+/// Example usage can be seen in AMD's GeometryFX (https://github.com/GPUOpen-Effects/GeometryFX). In particular, in this file: https://github.com/GPUOpen-Effects/GeometryFX/blob/master/amd_geometryfx/src/AMD_GeometryFX_Filtering.cpp -+/// - /// @{ - - /// -@@ -846,6 +1213,24 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetClipRects( AGSContext* cont - /// API for explicit control over Crossfire - /// @{ - -+/// The Crossfire API transfer types -+typedef enum AGSAfrTransferType -+{ -+ AGS_AFR_TRANSFER_DEFAULT = 0, ///< Default Crossfire driver resource tracking -+ AGS_AFR_TRANSFER_DISABLE = 1, ///< Turn off driver resource tracking -+ AGS_AFR_TRANSFER_1STEP_P2P = 2, ///< App controlled GPU to next GPU transfer -+ AGS_AFR_TRANSFER_2STEP_NO_BROADCAST = 3, ///< App controlled GPU to next GPU transfer using intermediate system memory -+ AGS_AFR_TRANSFER_2STEP_WITH_BROADCAST = 4, ///< App controlled GPU to all render GPUs transfer using intermediate system memory -+} AGSAfrTransferType; -+ -+/// The Crossfire API transfer engines -+typedef enum AGSAfrTransferEngine -+{ -+ AGS_AFR_TRANSFERENGINE_DEFAULT = 0, ///< Use default engine for Crossfire API transfers -+ AGS_AFR_TRANSFERENGINE_3D_ENGINE = 1, ///< Use 3D engine for Crossfire API transfers -+ AGS_AFR_TRANSFERENGINE_COPY_ENGINE = 2, ///< Use Copy engine for Crossfire API transfers -+} AGSAfrTransferEngine; -+ - /// - /// Function to create a Direct3D11 resource with the specified AFR transfer type and specified transfer engine. - /// -@@ -916,9 +1301,9 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndWrites( AGSCo - AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceBeginAllAccess( AGSContext* context, ID3D11Resource* resource ); - - /// --/// This is used for AGS_AFR_TRANSFER_1STEP_P2P to notify when it is safe to initiate a transfer. --/// This call in frame N-(NumGpus-1) allows a 1 step P2P in frame N to start. --/// This should be called after agsDriverExtensionsDX11_NotifyResourceEndWrites. -+/// This is used for AGS_AFR_TRANSFER_1STEP_P2P to notify when it is safe to initiate a transfer. -+/// This call in frame N-(NumGpus-1) allows a 1 step P2P in frame N to start. -+/// This should be called after agsDriverExtensionsDX11_NotifyResourceEndWrites. - /// - /// \param [in] context Pointer to a context. - /// \param [in] resource Pointer to the resource. -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index c6554a17b6f..5ba3d680f43 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -15,8 +15,29 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(amd_ags); - -+enum amd_ags_version -+{ -+ AMD_AGS_VERSION_5_1_1, -+ AMD_AGS_VERSION_5_2_0, -+ -+ AMD_AGS_VERSION_COUNT -+}; -+ -+struct -+{ -+ int major; -+ int minor; -+ int patch; -+} -+static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = -+{ -+ {5, 1, 1}, -+ {5, 2, 0}, -+}; -+ - struct AGSContext - { -+ enum amd_ags_version version; - unsigned int device_count; - AGSDeviceInfo *devices; - VkPhysicalDeviceProperties *properties; -@@ -88,6 +109,8 @@ static AGSReturnCode init_ags_context(AGSContext *context) - AGSReturnCode ret; - unsigned int i; - -+ // TODO: version check -+ context->version = AMD_AGS_VERSION_5_1_1; - context->device_count = 0; - context->devices = NULL; - context->properties = NULL; -@@ -108,15 +131,32 @@ static AGSReturnCode init_ags_context(AGSContext *context) - const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; - AGSDeviceInfo *device = &context->devices[i]; - -- device->adapterString = vk_properties->deviceName; -- device->vendorId = vk_properties->vendorID; -- device->deviceId = vk_properties->deviceID; -+ switch (context->version) -+ { -+ case AMD_AGS_VERSION_5_1_1: -+ device->agsDeviceInfo511.adapterString = vk_properties->deviceName; -+ device->agsDeviceInfo511.vendorId = vk_properties->vendorID; -+ device->agsDeviceInfo511.deviceId = vk_properties->deviceID; -+ -+ if (device->agsDeviceInfo511.vendorId == 0x1002) -+ device->agsDeviceInfo511.architectureVersion = ArchitectureVersion_GCN; - -- if (device->vendorId == 0x1002) -- device->architectureVersion = ArchitectureVersion_GCN; -+ if (!i) -+ device->agsDeviceInfo511.isPrimaryDevice = 1; -+ break; -+ case AMD_AGS_VERSION_5_2_0: -+ default: -+ device->agsDeviceInfo520.adapterString = vk_properties->deviceName; -+ device->agsDeviceInfo520.vendorId = vk_properties->vendorID; -+ device->agsDeviceInfo520.deviceId = vk_properties->deviceID; -+ -+ if (device->agsDeviceInfo520.vendorId == 0x1002) -+ device->agsDeviceInfo520.architectureVersion = ArchitectureVersion_GCN; - -- if (!i) -- device->isPrimaryDevice = 1; -+ if (!i) -+ device->agsDeviceInfo520.isPrimaryDevice = 1; -+ break; -+ } - } - - return AGS_SUCCESS; -@@ -145,9 +185,9 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi - } - - memset(gpu_info, 0, sizeof(*gpu_info)); -- gpu_info->agsVersionMajor = AMD_AGS_VERSION_MAJOR; -- gpu_info->agsVersionMinor = AMD_AGS_VERSION_MINOR; -- gpu_info->agsVersionPatch = AMD_AGS_VERSION_PATCH; -+ gpu_info->agsVersionMajor = amd_ags_versions[object->version].major; -+ gpu_info->agsVersionMinor = amd_ags_versions[object->version].minor; -+ gpu_info->agsVersionPatch = amd_ags_versions[object->version].patch; - gpu_info->driverVersion = "18.10.16-180516a-328911C-RadeonSoftwareAdrenalin"; - gpu_info->radeonSoftwareVersion = "18.5.1"; - gpu_info->numDevices = object->device_count; -From fd152d5e4d3edcfd283b6b2c430ea466fb47e5de Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Wed, 17 Jun 2020 14:32:18 -0700 -Subject: [PATCH] amd_ags_x64: Update to 5.2.1. - ---- - dlls/amd_ags_x64/amd_ags.h | 14 ++++++++++---- - dlls/amd_ags_x64/amd_ags_x64_main.c | 3 +++ - 2 files changed, 13 insertions(+), 4 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index b647f912aa7..c39adb53678 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -33,6 +33,12 @@ - /// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ - /// \endinternal - /// -+/// What's new in AGS 5.2.1 since version 5.2.0 -+/// --------------------------------------- -+/// * Fix for crash when using Eyefinity -+/// * Fix for DX12 app registration in the UWP version -+/// -+/// - /// What's new in AGS 5.2.0 since version 5.1 - /// --------------------------------------- - /// AGS 5.2 includes the following updates: -@@ -98,7 +104,7 @@ - - #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version - #define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version --#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version -+#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version - - #ifdef __cplusplus - extern "C" { -@@ -622,7 +628,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context - /// The different modes to control Crossfire behavior. - typedef enum AGSCrossfireMode - { -- AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering -+ AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering. If this mode is specified, do NOT use the agsDriverExtensionsDX11_Create*() APIs to create resources - AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile - AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering - } AGSCrossfireMode; -@@ -739,7 +745,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_511( AGSContext* - - /// \defgroup dx11appreg App Registration - /// @{ --/// This extension allows an apllication to voluntarily register itself with the driver, providing a more robust app detection solution and avoid the issue of the driver -+/// This extension allows an apllication to voluntarily register itself with the driver, providing a more robust app detection solution and avoid the issue of the driver - /// relying on exe names to match the app to a driver profile. - /// This feature is supported in Radeon Software Version 17.9.2 onwards. - /// Rules: -@@ -1151,7 +1157,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount( - - /// - /// This method can be used to determine the total number of asynchronous shader compile jobs that are either --/// queued for waiting for compilation or being compiled by the driver?s asynchronous compilation threads. -+/// queued for waiting for compilation or being compiled by the driverÂ?s asynchronous compilation threads. - /// This method can be called at any during the lifetime of the driver. - /// - /// \param [in] context Pointer to a context. -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 5ba3d680f43..6ed627a67d6 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -19,6 +19,7 @@ enum amd_ags_version - { - AMD_AGS_VERSION_5_1_1, - AMD_AGS_VERSION_5_2_0, -+ AMD_AGS_VERSION_5_2_1, - - AMD_AGS_VERSION_COUNT - }; -@@ -33,6 +34,7 @@ static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = - { - {5, 1, 1}, - {5, 2, 0}, -+ {5, 2, 1}, - }; - - struct AGSContext -@@ -145,6 +147,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) - device->agsDeviceInfo511.isPrimaryDevice = 1; - break; - case AMD_AGS_VERSION_5_2_0: -+ case AMD_AGS_VERSION_5_2_1: - default: - device->agsDeviceInfo520.adapterString = vk_properties->deviceName; - device->agsDeviceInfo520.vendorId = vk_properties->vendorID; -From 54feee8728b0f5ae35ff2db4d62fc617bc9ac917 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Wed, 17 Jun 2020 14:44:25 -0700 -Subject: [PATCH] amd_ags_x64: Update to 5.3.0. - ---- - dlls/amd_ags_x64/amd_ags.h | 98 +++++++++++++++++++++++------ - dlls/amd_ags_x64/amd_ags_x64_main.c | 3 + - 2 files changed, 82 insertions(+), 19 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index c39adb53678..58f7bb84e37 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -33,6 +33,14 @@ - /// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/ - /// \endinternal - /// -+/// --------------------------------------- -+/// What's new in AGS 5.3 since version 5.2 -+/// --------------------------------------- -+/// AGS 5.3 includes the following updates: -+/// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions. -+/// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements. -+/// * Freesync2 Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync2 scRGB. -+/// - /// What's new in AGS 5.2.1 since version 5.2.0 - /// --------------------------------------- - /// * Fix for crash when using Eyefinity -@@ -103,8 +111,8 @@ - #define AMD_AGS_H - - #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version --#define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version --#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version -+#define AMD_AGS_VERSION_MINOR 3 ///< AGS minor version -+#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version - - #ifdef __cplusplus - extern "C" { -@@ -112,6 +120,9 @@ extern "C" { - - #define AMD_AGS_API WINAPI - -+#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version -+#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version -+ - // Forward declaration of D3D11 types - struct IDXGIAdapter; - enum D3D_DRIVER_TYPE; -@@ -147,6 +158,7 @@ typedef enum AGSReturnCode - AGS_ERROR_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver - AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension - AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) -+ AGS_DX_FAILURE ///< Failure from DirectX runtime - } AGSReturnCode; - - /// The DirectX11 extension support bits -@@ -173,6 +185,9 @@ typedef enum AGSDriverExtensionDX11 - AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, ///< Supported in Radeon Software Version 16.12.1 onwards. - AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX11_EXTENSION_BREADCRUMB_MARKERS = 1 << 20, ///< Supported in Radeon Software Version 17.11.1 onwards. -+ AGS_DX11_EXTENSION_MDI_DEFERRED_CONTEXTS = 1 << 21, ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. -+ AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. -+ AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23 ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. - } AGSDriverExtensionDX11; - - /// The DirectX12 extension support bits -@@ -417,6 +432,8 @@ typedef struct AGSDisplaySettings - Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. - Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. - Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. 1.0 == 80 nits. Tonemap your scene to the range of 0.0 to AGSDisplayInfo::maxLuminance. -+ // Mode_Freesync2_Gamma22 ADDED IN 5.3.0 -+ Mode_Freesync2_Gamma22, ///< Freesync2 Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. - Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain - } mode; ///< The display mode to set the display into - -@@ -442,6 +459,24 @@ typedef struct AGSDisplaySettings - int flags; ///< Bitfield of ::AGSDisplaySettingsFlags - } AGSDisplaySettings; - -+/// The result returned from \ref agsCheckDriverVersion -+typedef enum AGSDriverVersionResult -+{ -+ AGS_SOFTWAREVERSIONCHECK_OK, ///< The reported Radeon Software Version is newer or the same as the required version -+ AGS_SOFTWAREVERSIONCHECK_OLDER, ///< The reported Radeon Software Version is older than the required version -+ AGS_SOFTWAREVERSIONCHECK_UNDEFINED ///< The check could not determine as result. This could be because it is a private or custom driver or just invalid arguments. -+} AGSDriverVersionResult; -+ -+/// -+/// Helper function to check the installed software version against the required software version. -+/// -+/// \param [in] radeonSoftwareVersionReported The Radeon Software Version returned from \ref AGSGPUInfo::radeonSoftwareVersion. -+/// \param [in] radeonSoftwareVersionRequired The Radeon Software Version to check against. This is specificed using \ref AGS_MAKE_VERSION. -+/// \return The result of the check. -+/// -+AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired ); -+ -+ - /// - /// Function used to initialize the AGS library. - /// Must be called prior to any of the subsequent AGS API calls. -@@ -494,7 +529,7 @@ AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceInde - /// DirectX12 driver extensions - /// @{ - --/// \defgroup dx12init Device creation and cleanup -+/// \defgroup dx12init Device and device object creation and cleanup - /// It is now mandatory to call \ref agsDriverExtensionsDX12_CreateDevice when creating a device if the user wants to access any future DX12 AMD extensions. - /// The corresponding \ref agsDriverExtensionsDX12_DestroyDevice call must be called to release the device and free up the internal resources allocated by the create call. - /// @{ -@@ -507,9 +542,6 @@ typedef struct AGSDX12DeviceCreationParams - D3D_FEATURE_LEVEL FeatureLevel; ///< The minimum feature level to create the device with. - } AGSDX12DeviceCreationParams; - --#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams --#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version -- - /// The struct to specify DX12 additional device creation parameters - typedef struct AGSDX12ExtensionParams - { -@@ -628,7 +660,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_SetMarker( AGSContext* context - /// The different modes to control Crossfire behavior. - typedef enum AGSCrossfireMode - { -- AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering. If this mode is specified, do NOT use the agsDriverExtensionsDX11_Create*() APIs to create resources -+ AGS_CROSSFIRE_MODE_DRIVER_AFR = 0, ///< Use the default driver-based AFR rendering. If this mode is specified, do NOT use the agsDriverExtensionsDX11_Create*() APIs to create resources - AGS_CROSSFIRE_MODE_EXPLICIT_AFR, ///< Use the AGS Crossfire API functions to perform explicit AFR rendering without requiring a CF driver profile - AGS_CROSSFIRE_MODE_DISABLE ///< Completely disable AFR rendering - } AGSCrossfireMode; -@@ -978,8 +1010,8 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* c - - /// @} - --/// \defgroup dx11misc Misc Extensions --/// API for depth bounds test, UAV overlap and prim topologies -+/// \defgroup dx11Topology Extended Topology -+/// API for primitive topologies - /// @{ - - /// -@@ -1001,6 +1033,12 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* c - /// - AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSContext* context, enum D3D_PRIMITIVE_TOPOLOGY topology ); - -+/// @} -+ -+/// \defgroup dx11UAVOverlap UAV Overlap -+/// API for enabling overlapping UAV writes -+/// @{ -+ - /// - /// Function used indicate to the driver that it doesn't need to sync the UAVs bound for the subsequent set of back-to-back dispatches. - /// When calling back-to-back draw calls or dispatch calls that write to the same UAV, the AMD DX11 driver will automatically insert a barrier to ensure there are no write after write (WAW) hazards. -@@ -1023,25 +1061,39 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_IASetPrimitiveTopology( AGSCon - /// \endcode - /// - /// \param [in] context Pointer to a context. -+/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. -+/// with the AGS_DX11_EXTENSION_DEFERRED_CONTEXTS bit. - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap( AGSContext* context ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap_520( AGSContext* context ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_BeginUAVOverlap( AGSContext* context, ID3D11DeviceContext* dxContext ); - - /// - /// Function used indicate to the driver it can no longer overlap the batch of back-to-back dispatches that has been submitted. - /// - /// \param [in] context Pointer to a context. -+/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. -+/// with the AGS_DX11_EXTENSION_DEFERRED_CONTEXTS bit. - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* context ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap_520( AGSContext* context ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_EndUAVOverlap( AGSContext* context, ID3D11DeviceContext* dxContext ); -+ -+/// @} -+ -+/// \defgroup dx11DepthBoundsTest Depth Bounds Test -+/// API for enabling depth bounds testing -+/// @{ - - /// - /// Function used to set the depth bounds test extension - /// --/// \param [in] context Pointer to a context. -+/// \param [in] context Pointer to a context -+/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. - /// \param [in] enabled Whether to enable or disable the depth bounds testing. If disabled, the next two args are ignored. - /// \param [in] minDepth The near depth range to clip against. - /// \param [in] maxDepth The far depth range to clip against. - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* context, bool enabled, float minDepth, float maxDepth ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds_520( AGSContext* context, bool enabled, float minDepth, float maxDepth ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* context, ID3D11DeviceContext* dxContext, bool enabled, float minDepth, float maxDepth ); - - /// @} - -@@ -1054,12 +1106,12 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* co - /// \code{.cpp} - /// // Submit n batches of DrawIndirect calls - /// for ( int i = 0; i < n; i++ ) --/// DrawIndexedInstancedIndirect( buffer, i * sizeof( cmd ) ); -+/// deviceContext->DrawIndexedInstancedIndirect( buffer, i * sizeof( cmd ) ); - /// \endcode - /// To be replaced by the following call: - /// \code{.cpp} - /// // Submit all n batches in one call --/// agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( m_agsContext, n, buffer, 0, sizeof( cmd ) ); -+/// agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( m_agsContext, deviceContext, n, buffer, 0, sizeof( cmd ) ); - /// \endcode - /// - /// The buffer used for the indirect args must be of the following formats: -@@ -1092,47 +1144,55 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetDepthBounds( AGSContext* co - /// Function used to submit a batch of draws via MultiDrawIndirect - /// - /// \param [in] context Pointer to a context. -+/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. - /// \param [in] drawCount The number of draws. - /// \param [in] pBufferForArgs The args buffer. - /// \param [in] alignedByteOffsetForArgs The offset into the args buffer. - /// \param [in] byteStrideForArgs The per element stride of the args buffer. - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect_520( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); - - /// - /// Function used to submit a batch of draws via MultiDrawIndirect - /// - /// \param [in] context Pointer to a context. -+/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. - /// \param [in] drawCount The number of draws. - /// \param [in] pBufferForArgs The args buffer. - /// \param [in] alignedByteOffsetForArgs The offset into the args buffer. - /// \param [in] byteStrideForArgs The per element stride of the args buffer. - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect_520( AGSContext* context, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, unsigned int drawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); - - /// - /// Function used to submit a batch of draws via MultiDrawIndirect - /// - /// \param [in] context Pointer to a context. -+/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. - /// \param [in] pBufferForDrawCount The draw count buffer. - /// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. - /// \param [in] pBufferForArgs The args buffer. - /// \param [in] alignedByteOffsetForArgs The offset into the args buffer. - /// \param [in] byteStrideForArgs The per element stride of the args buffer. - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect_520( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); - - /// - /// Function used to submit a batch of draws via MultiDrawIndirect - /// - /// \param [in] context Pointer to a context. -+/// \param [in] dxContext Pointer to the DirectX device context. If this is to work using the non-immediate context, then you need to check support. If nullptr is specified, then the immediate context is assumed. - /// \param [in] pBufferForDrawCount The draw count buffer. - /// \param [in] alignedByteOffsetForDrawCount The offset into the draw count buffer. - /// \param [in] pBufferForArgs The args buffer. - /// \param [in] alignedByteOffsetForArgs The offset into the args buffer. - /// \param [in] byteStrideForArgs The per element stride of the args buffer. - /// --AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect_520( AGSContext* context, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); -+AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect( AGSContext* context, ID3D11DeviceContext* dxContext, ID3D11Buffer* pBufferForDrawCount, unsigned int alignedByteOffsetForDrawCount, ID3D11Buffer* pBufferForArgs, unsigned int alignedByteOffsetForArgs, unsigned int byteStrideForArgs ); - - /// @} - -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 6ed627a67d6..021a28bf2dc 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -20,6 +20,7 @@ enum amd_ags_version - AMD_AGS_VERSION_5_1_1, - AMD_AGS_VERSION_5_2_0, - AMD_AGS_VERSION_5_2_1, -+ AMD_AGS_VERSION_5_3_0, - - AMD_AGS_VERSION_COUNT - }; -@@ -35,6 +36,7 @@ static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = - {5, 1, 1}, - {5, 2, 0}, - {5, 2, 1}, -+ {5, 3, 0}, - }; - - struct AGSContext -@@ -148,6 +150,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) - break; - case AMD_AGS_VERSION_5_2_0: - case AMD_AGS_VERSION_5_2_1: -+ case AMD_AGS_VERSION_5_3_0: - default: - device->agsDeviceInfo520.adapterString = vk_properties->deviceName; - device->agsDeviceInfo520.vendorId = vk_properties->vendorID; -From 0db523b1dd8b193f50d09133c7ef0bfbe63827b2 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Wed, 17 Jun 2020 15:03:02 -0700 -Subject: [PATCH] amd_ags_x64: Update to 5.4.0. - ---- - dlls/amd_ags_x64/amd_ags.h | 92 ++++++++++++++++++++++++++--- - dlls/amd_ags_x64/amd_ags_x64_main.c | 15 ++++- - 2 files changed, 99 insertions(+), 8 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index 58f7bb84e37..c615ba4c203 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -34,6 +34,14 @@ - /// \endinternal - /// - /// --------------------------------------- -+/// What's new in AGS 5.4 since version 5.3 -+/// --------------------------------------- -+/// AGS 5.4 includes the following updates: -+/// * A more detailed description of the GPU architecture, now including RDNA GPUs. -+/// * Navi 10, Navi 14 and Radeon 7 core and memory speeds returned. -+/// * Draw index and Atomic U64 intrinsics for both DX11 and DX12. -+/// -+/// --------------------------------------- - /// What's new in AGS 5.3 since version 5.2 - /// --------------------------------------- - /// AGS 5.3 includes the following updates: -@@ -111,7 +119,7 @@ - #define AMD_AGS_H - - #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version --#define AMD_AGS_VERSION_MINOR 3 ///< AGS minor version -+#define AMD_AGS_VERSION_MINOR 4 ///< AGS minor version - #define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version - - #ifdef __cplusplus -@@ -185,9 +193,11 @@ typedef enum AGSDriverExtensionDX11 - AGS_DX11_EXTENSION_MULTIVIEW = 1 << 18, ///< Supported in Radeon Software Version 16.12.1 onwards. - AGS_DX11_EXTENSION_APP_REGISTRATION = 1 << 19, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX11_EXTENSION_BREADCRUMB_MARKERS = 1 << 20, ///< Supported in Radeon Software Version 17.11.1 onwards. -- AGS_DX11_EXTENSION_MDI_DEFERRED_CONTEXTS = 1 << 21, ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. -- AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. -- AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23 ///< Supported in Radeon Software Version XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX onwards. -+ AGS_DX11_EXTENSION_MDI_DEFERRED_CONTEXTS = 1 << 21, ///< Supported in Radeon Software Version 18.8.1 onwards. -+ AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version 18.8.1 onwards. -+ AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23, ///< Supported in Radeon Software Version 18.8.1 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 24, ///< Supported in Radeon Software Version 19.12.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 25 ///< Supported in Radeon Software Version 19.12.2 onwards. - } AGSDriverExtensionDX11; - - /// The DirectX12 extension support bits -@@ -204,7 +214,10 @@ typedef enum AGSDriverExtensionDX12 - AGS_DX12_EXTENSION_INTRINSIC_WAVE_REDUCE = 1 << 8, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX12_EXTENSION_INTRINSIC_WAVE_SCAN = 1 << 9, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX12_EXTENSION_USER_MARKERS = 1 << 10, ///< Supported in Radeon Software Version 17.9.1 onwards. -- AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11 ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11, ///< Supported in Radeon Software Version 17.9.1 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT = 1 << 12, ///< Supported in Radeon Software Version 19.5.1 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 13, ///< Supported in Radeon Software Version 19.12.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 14 ///< Supported in Radeon Software Version 19.12.2 onwards. - } AGSDriverExtensionDX12; - - /// The space id for DirectX12 intrinsic support -@@ -312,6 +325,19 @@ typedef enum ArchitectureVersion - ArchitectureVersion_GCN ///< AMD GCN architecture - } ArchitectureVersion; - -+/// The ASIC family -+typedef enum AsicFamily -+{ -+ AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId -+ AsicFamily_PreGCN, ///< Pre GCN architecture. -+ AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti. -+ AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo. -+ AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji. -+ AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. -+ AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). -+ AsicFamily_RDNA ///< AMD RDNA architecture -+} AsicFamily; -+ - /// The device info struct used to describe a physical GPU enumerated by AGS - typedef struct AGSDeviceInfo_511 - { -@@ -374,10 +400,48 @@ typedef struct AGSDeviceInfo_520 - int adlAdapterIndex; ///< Internally used index into the ADL list of adapters - } AGSDeviceInfo_520; - -+/// The device info struct used to describe a physical GPU enumerated by AGS -+typedef struct AGSDeviceInfo_540 -+{ -+ const char* adapterString; ///< The adapter name string -+ AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware -+ int isAPU; ///< Whether or not this is an APU -+ int vendorId; ///< The vendor id -+ int deviceId; ///< The device id -+ int revisionId; ///< The revision id -+ -+ int numCUs; ///< Number of compute units. -+ int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. -+ -+ int numROPs; ///< Number of ROPs -+ int coreClock; ///< Core clock speed at 100% power in MHz -+ int memoryClock; ///< Memory clock speed at 100% power in MHz -+ int memoryBandwidth; ///< Memory bandwidth in MB/s -+ float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD -+ -+ int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. -+ unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. -+ unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs -+ ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. -+ -+ int numDisplays; ///< The number of active displays found to be attached to this adapter. -+ AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ -+ int eyefinityEnabled; ///< Indicates if Eyefinity is active -+ int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. -+ int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. -+ int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. -+ -+ int adlAdapterIndex; ///< Internally used index into the ADL list of adapters -+} AGSDeviceInfo_540; -+ - typedef union AGSDeviceInfo - { - AGSDeviceInfo_511 agsDeviceInfo511; - AGSDeviceInfo_520 agsDeviceInfo520; -+ AGSDeviceInfo_540 agsDeviceInfo540; - } AGSDeviceInfo; - - /// \defgroup general General API functions -@@ -549,6 +613,8 @@ typedef struct AGSDX12ExtensionParams - const WCHAR* pEngineName; ///< Engine name - unsigned int appVersion; ///< Application version - unsigned int engineVersion; ///< Engine version -+ // ADDED IN 5.4.0 -+ unsigned int uavSlot; ///< The UAV slot reserved for intrinsic support. Refer to the \ref agsDriverExtensionsDX12_CreateDevice documentation for more details. - } AGSDX12ExtensionParams; - - /// The struct to hold all the returned parameters from the device creation call -@@ -566,7 +632,19 @@ typedef struct AGSDX12ReturnedParams - /// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. - /// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. - /// * The intrinsic instructions require a 5.1 shader model. --/// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. -+/// * The Root Signature will need to reserve an extra UAV resource slot. This is not a real resource that requires allocating, it is just used to encode the intrinsic instructions. -+/// -+/// The easiest way to set up the reserved UAV slot is to specify it at u0. The register space id will automatically be assumed to be \ref AGS_DX12_SHADER_INSTRINSICS_SPACE_ID. -+/// The HLSL expects this as default and the set up code would look similar to this: -+/// \code{.cpp} -+/// CD3DX12_DESCRIPTOR_RANGE range[]; -+/// ... -+/// range[ 0 ].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, AGS_DX12_SHADER_INSTRINSICS_SPACE_ID ); // u0 at driver-reserved space id -+/// \endcode -+/// -+/// Newer drivers also support a user-specified slot in which case the register space id is assumed to be 0. It is important that the \ref AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT bit is set -+/// to ensure the driver can support this. If not, then u0 and \ref AGS_DX12_SHADER_INSTRINSICS_SPACE_ID must be used. -+/// If the driver does support this feature and a non zero slot is required, then the HLSL must also define AMD_EXT_SHADER_INTRINSIC_UAV_OVERRIDE as the matching slot value. - /// - /// \param [in] context Pointer to a context. This is generated by \ref agsInit - /// \param [in] creationParams Pointer to the struct to specify the existing DX12 device creation parameters. -@@ -616,7 +694,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); - - /// - /// Function used to push an AMD user marker onto the command list. --/// This is only has an effect if AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of \ref agsDriverExtensionsDX12_CreateDevice -+/// This is only has an effect if \ref AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of \ref agsDriverExtensionsDX12_CreateDevice - /// Supported in Radeon Software Version 17.9.1 onwards. - /// - /// \param [in] context Pointer to a context. -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 021a28bf2dc..5f5eab01ebc 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -21,6 +21,7 @@ enum amd_ags_version - AMD_AGS_VERSION_5_2_0, - AMD_AGS_VERSION_5_2_1, - AMD_AGS_VERSION_5_3_0, -+ AMD_AGS_VERSION_5_4_0, - - AMD_AGS_VERSION_COUNT - }; -@@ -37,6 +38,7 @@ static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = - {5, 2, 0}, - {5, 2, 1}, - {5, 3, 0}, -+ {5, 4, 0}, - }; - - struct AGSContext -@@ -151,7 +153,6 @@ static AGSReturnCode init_ags_context(AGSContext *context) - case AMD_AGS_VERSION_5_2_0: - case AMD_AGS_VERSION_5_2_1: - case AMD_AGS_VERSION_5_3_0: -- default: - device->agsDeviceInfo520.adapterString = vk_properties->deviceName; - device->agsDeviceInfo520.vendorId = vk_properties->vendorID; - device->agsDeviceInfo520.deviceId = vk_properties->deviceID; -@@ -162,6 +163,18 @@ static AGSReturnCode init_ags_context(AGSContext *context) - if (!i) - device->agsDeviceInfo520.isPrimaryDevice = 1; - break; -+ case AMD_AGS_VERSION_5_4_0: -+ default: -+ device->agsDeviceInfo540.adapterString = vk_properties->deviceName; -+ device->agsDeviceInfo540.vendorId = vk_properties->vendorID; -+ device->agsDeviceInfo540.deviceId = vk_properties->deviceID; -+ -+ if (device->agsDeviceInfo540.vendorId == 0x1002) -+ device->agsDeviceInfo540.asicFamily = AsicFamily_GCN4; -+ -+ if (!i) -+ device->agsDeviceInfo540.isPrimaryDevice = 1; -+ break; - } - } - -From 247acfa3f0d40b136a066a854726b5fe6f7527a9 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Wed, 17 Jun 2020 15:16:44 -0700 -Subject: [PATCH] amd_ags_x64: Update to 5.4.1 - ---- - dlls/amd_ags_x64/amd_ags.h | 101 +++++++++++++++++++++++----- - dlls/amd_ags_x64/amd_ags_x64_main.c | 15 ++++- - 2 files changed, 98 insertions(+), 18 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index c615ba4c203..30f3735915c 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -1,5 +1,5 @@ - // --// Copyright (c) 2018 Advanced Micro Devices, Inc. All rights reserved. -+// Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. - // - // Permission is hereby granted, free of charge, to any person obtaining a copy - // of this software and associated documentation files (the "Software"), to deal -@@ -34,11 +34,21 @@ - /// \endinternal - /// - /// --------------------------------------- -+/// What's new in AGS 5.4.1 since version 5.4.0 -+/// --------------------------------------- -+/// AGS 5.4.1 includes the following updates: -+/// * AsicFamily_Count to help with code maintenance. -+/// * Visual Studio 2019 support. -+/// * x86 support -+/// * BaseInstance and BaseVertex intrinsics along with corresponding caps bits. -+/// * GetWaveSize intrinsic along with corresponding caps bits. -+/// -+/// --------------------------------------- - /// What's new in AGS 5.4 since version 5.3 - /// --------------------------------------- - /// AGS 5.4 includes the following updates: - /// * A more detailed description of the GPU architecture, now including RDNA GPUs. --/// * Navi 10, Navi 14 and Radeon 7 core and memory speeds returned. -+/// * Radeon 7 core and memory speeds returned. - /// * Draw index and Atomic U64 intrinsics for both DX11 and DX12. - /// - /// --------------------------------------- -@@ -47,7 +57,7 @@ - /// AGS 5.3 includes the following updates: - /// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions. - /// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements. --/// * Freesync2 Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync2 scRGB. -+/// * Freesync HDR Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync HDR scRGB. - /// - /// What's new in AGS 5.2.1 since version 5.2.0 - /// --------------------------------------- -@@ -120,16 +130,19 @@ - - #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version - #define AMD_AGS_VERSION_MINOR 4 ///< AGS minor version --#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version -+#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version - - #ifdef __cplusplus - extern "C" { - #endif - -+/// \defgroup Defines AGS defines -+/// @{ - #define AMD_AGS_API WINAPI - - #define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version - #define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version -+/// @} - - // Forward declaration of D3D11 types - struct IDXGIAdapter; -@@ -154,6 +167,8 @@ struct D3D11_SUBRESOURCE_DATA; - struct ID3D12Device; - struct ID3D12GraphicsCommandList; - -+/// \defgroup enums General enumerations -+/// @{ - - /// The return codes - typedef enum AGSReturnCode -@@ -162,8 +177,10 @@ typedef enum AGSReturnCode - AGS_FAILURE, ///< Failed to complete call for some unspecified reason - AGS_INVALID_ARGS, ///< Invalid arguments into the function - AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally -- AGS_ERROR_MISSING_DLL, ///< Returned when a driver dll fails to load - most likely due to not being present in legacy driver installation -- AGS_ERROR_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver -+ AGS_MISSING_D3D_DLL, ///< Returned when a D3D dll fails to load -+ AGS_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver -+ // AGS_NO_AMD_DRIVER_INSTALLED ADDED IN 5.4.1 -+ AGS_NO_AMD_DRIVER_INSTALLED, ///< Returned if the AMD GPU driver does not appear to be installed - AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension - AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library) - AGS_DX_FAILURE ///< Failure from DirectX runtime -@@ -197,7 +214,10 @@ typedef enum AGSDriverExtensionDX11 - AGS_DX11_EXTENSION_UAV_OVERLAP_DEFERRED_CONTEXTS = 1 << 22, ///< Supported in Radeon Software Version 18.8.1 onwards. - AGS_DX11_EXTENSION_DEPTH_BOUNDS_DEFERRED_CONTEXTS = 1 << 23, ///< Supported in Radeon Software Version 18.8.1 onwards. - AGS_DX11_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 24, ///< Supported in Radeon Software Version 19.12.2 onwards. -- AGS_DX11_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 25 ///< Supported in Radeon Software Version 19.12.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 25, ///< Supported in Radeon Software Version 19.12.2 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_GET_WAVE_SIZE = 1 << 26, ///< Supported in Radeon Software Version 20.2.1 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_BASE_VERTEX = 1 << 27, ///< Supported in Radeon Software Version 20.2.1 onwards. -+ AGS_DX11_EXTENSION_INTRINSIC_BASE_INSTANCE = 1 << 28 ///< Supported in Radeon Software Version 20.2.1 onwards. - } AGSDriverExtensionDX11; - - /// The DirectX12 extension support bits -@@ -217,7 +237,10 @@ typedef enum AGSDriverExtensionDX12 - AGS_DX12_EXTENSION_APP_REGISTRATION = 1 << 11, ///< Supported in Radeon Software Version 17.9.1 onwards. - AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT = 1 << 12, ///< Supported in Radeon Software Version 19.5.1 onwards. - AGS_DX12_EXTENSION_INTRINSIC_DRAW_INDEX = 1 << 13, ///< Supported in Radeon Software Version 19.12.2 onwards. -- AGS_DX12_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 14 ///< Supported in Radeon Software Version 19.12.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_ATOMIC_U64 = 1 << 14, ///< Supported in Radeon Software Version 19.12.2 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_BASE_VERTEX = 1 << 15, ///< Supported in Radeon Software Version 20.2.1 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_BASE_INSTANCE = 1 << 16, ///< Supported in Radeon Software Version 20.2.1 onwards. -+ AGS_DX12_EXTENSION_INTRINSIC_GET_WAVE_SIZE = 1 << 17 ///< Supported in Radeon Software Version 20.5.1 onwards. - } AGSDriverExtensionDX12; - - /// The space id for DirectX12 intrinsic support -@@ -238,7 +261,7 @@ typedef enum AGSDisplayFlags - AGS_DISPLAYFLAG_HDR10 = 1 << 1, ///< HDR10 is supported on this display - AGS_DISPLAYFLAG_DOLBYVISION = 1 << 2, ///< Dolby Vision is supported on this display - AGS_DISPLAYFLAG_FREESYNC = 1 << 3, ///< Freesync is supported on this display -- AGS_DISPLAYFLAG_FREESYNC_2 = 1 << 4, ///< Freesync 2 is supported on this display -+ AGS_DISPLAYFLAG_FREESYNC_HDR = 1 << 4, ///< Freesync HDR is supported on this display - AGS_DISPLAYFLAG_EYEFINITY_IN_GROUP = 1 << 5, ///< The display is part of the Eyefinity group - AGS_DISPLAYFLAG_EYEFINITY_PREFERRED_DISPLAY = 1 << 6, ///< The display is the preferred display in the Eyefinity group for displaying the UI - AGS_DISPLAYFLAG_EYEFINITY_IN_PORTRAIT_MODE = 1 << 7, ///< The display is in the Eyefinity group but in portrait mode -@@ -250,6 +273,7 @@ typedef enum AGSDisplaySettingsFlags - AGS_DISPLAYSETTINGSFLAG_DISABLE_LOCAL_DIMMING = 1 << 0, ///< Disables local dimming if possible - } AGSDisplaySettingsFlags; - -+/// @} - - typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit - -@@ -280,7 +304,7 @@ typedef struct AGSDisplayInfo - char name[ 256 ]; ///< The name of the display - char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName - -- unsigned int displayFlags; ///< Bitfield of ::AGSDisplayFlags -+ unsigned int displayFlags; ///< Bitfield of \ref AGSDisplayFlags - - int maxResolutionX; ///< The maximum supported resolution of the unrotated display - int maxResolutionY; ///< The maximum supported resolution of the unrotated display -@@ -335,7 +359,9 @@ typedef enum AsicFamily - AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji. - AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. - AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). -- AsicFamily_RDNA ///< AMD RDNA architecture -+ AsicFamily_RDNA, ///< AMD RDNA architecture -+ -+ AsicFamily_Count ///< Number of enumerated ASIC families - } AsicFamily; - - /// The device info struct used to describe a physical GPU enumerated by AGS -@@ -437,11 +463,47 @@ typedef struct AGSDeviceInfo_540 - int adlAdapterIndex; ///< Internally used index into the ADL list of adapters - } AGSDeviceInfo_540; - -+/// The device info struct used to describe a physical GPU enumerated by AGS -+typedef struct AGSDeviceInfo_541 -+{ -+ const char* adapterString; ///< The adapter name string -+ AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware -+ int isAPU; ///< Whether or not this is an APU -+ int vendorId; ///< The vendor id -+ int deviceId; ///< The device id -+ int revisionId; ///< The revision id -+ -+ int numCUs; ///< Number of compute units. -+ int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. -+ -+ int numROPs; ///< Number of ROPs -+ int coreClock; ///< Core clock speed at 100% power in MHz -+ int memoryClock; ///< Memory clock speed at 100% power in MHz -+ int memoryBandwidth; ///< Memory bandwidth in MB/s -+ float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD -+ -+ int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. -+ long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. -+ -+ int numDisplays; ///< The number of active displays found to be attached to this adapter. -+ AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ -+ int eyefinityEnabled; ///< Indicates if Eyefinity is active -+ int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. -+ int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. -+ int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. -+ -+ int adlAdapterIndex; ///< Internally used index into the ADL list of adapters -+} AGSDeviceInfo_541; -+ - typedef union AGSDeviceInfo - { - AGSDeviceInfo_511 agsDeviceInfo511; - AGSDeviceInfo_520 agsDeviceInfo520; - AGSDeviceInfo_540 agsDeviceInfo540; -+ AGSDeviceInfo_541 agsDeviceInfo541; - } AGSDeviceInfo; - - /// \defgroup general General API functions -@@ -495,10 +557,12 @@ typedef struct AGSDisplaySettings - Mode_SDR, ///< SDR mode - Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. - Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. -- Mode_Freesync2_scRGB, ///< Freesync2 scRGB, requiring an FP16 swapchain. 1.0 == 80 nits. Tonemap your scene to the range of 0.0 to AGSDisplayInfo::maxLuminance. -- // Mode_Freesync2_Gamma22 ADDED IN 5.3.0 -- Mode_Freesync2_Gamma22, ///< Freesync2 Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. -- Mode_DolbyVision ///< Dolby Vision, requiring an 8888 UNORM swapchain -+ Mode_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. -+ // Mode_FreesyncHDR_Gamma22 ADDED IN 5.3.0 -+ Mode_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. -+ Mode_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain -+ -+ Mode_Count ///< Number of enumerated display modes - } mode; ///< The display mode to set the display into - - double chromaticityRedX; ///< Red display primary X coord -@@ -545,7 +609,9 @@ AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoft - /// Function used to initialize the AGS library. - /// Must be called prior to any of the subsequent AGS API calls. - /// Must be called prior to ID3D11Device or ID3D12Device creation. --/// \note This function will fail with \ref AGS_ERROR_LEGACY_DRIVER in Catalyst versions before 12.20. -+/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInit if there is an AMD GPU present. -+/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system. -+/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20. - /// \note It is good practice to check the AGS version returned from AGSGPUInfo against the version defined in the header in case a mismatch between the dll and header has occurred. - /// - /// \param [in, out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. -@@ -577,7 +643,8 @@ AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* num - /// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc). - /// \note HDR10 PQ mode requires a 1010102 swapchain. - /// \note HDR10 scRGB mode requires an FP16 swapchain. --/// \note Freesync2 scRGB mode requires an FP16 swapchain. -+/// \note Freesync HDR scRGB mode requires an FP16 swapchain. -+/// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain. - /// \note Dolby Vision requires a 8888 UNORM swapchain. - /// - /// \param [in] context Pointer to a context. This is generated by \ref agsInit -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 5f5eab01ebc..8d76c326c26 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -22,6 +22,7 @@ enum amd_ags_version - AMD_AGS_VERSION_5_2_1, - AMD_AGS_VERSION_5_3_0, - AMD_AGS_VERSION_5_4_0, -+ AMD_AGS_VERSION_5_4_1, - - AMD_AGS_VERSION_COUNT - }; -@@ -39,6 +40,7 @@ static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = - {5, 2, 1}, - {5, 3, 0}, - {5, 4, 0}, -+ {5, 4, 1}, - }; - - struct AGSContext -@@ -164,7 +166,6 @@ static AGSReturnCode init_ags_context(AGSContext *context) - device->agsDeviceInfo520.isPrimaryDevice = 1; - break; - case AMD_AGS_VERSION_5_4_0: -- default: - device->agsDeviceInfo540.adapterString = vk_properties->deviceName; - device->agsDeviceInfo540.vendorId = vk_properties->vendorID; - device->agsDeviceInfo540.deviceId = vk_properties->deviceID; -@@ -175,6 +176,18 @@ static AGSReturnCode init_ags_context(AGSContext *context) - if (!i) - device->agsDeviceInfo540.isPrimaryDevice = 1; - break; -+ case AMD_AGS_VERSION_5_4_1: -+ default: -+ device->agsDeviceInfo541.adapterString = vk_properties->deviceName; -+ device->agsDeviceInfo541.vendorId = vk_properties->vendorID; -+ device->agsDeviceInfo541.deviceId = vk_properties->deviceID; -+ -+ if (device->agsDeviceInfo541.vendorId == 0x1002) -+ device->agsDeviceInfo541.asicFamily = AsicFamily_GCN4; -+ -+ if (!i) -+ device->agsDeviceInfo541.isPrimaryDevice = 1; -+ break; - } - } - -From 14d65e9ff5ab6f29a24ac4024b9ee302091c3400 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Wed, 17 Jun 2020 16:33:08 -0700 -Subject: [PATCH] amd_ags_x64: Fill in localMemoryInBytes. - ---- - dlls/amd_ags_x64/amd_ags_x64_main.c | 39 ++++++++++++++++++++++++++--- - 1 file changed, 36 insertions(+), 3 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 8d76c326c26..d1ea7a23ce7 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -49,12 +49,14 @@ struct AGSContext - unsigned int device_count; - AGSDeviceInfo *devices; - VkPhysicalDeviceProperties *properties; -+ VkPhysicalDeviceMemoryProperties *memory_properties; - }; - - static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, -- VkPhysicalDeviceProperties **out) -+ VkPhysicalDeviceProperties **out, VkPhysicalDeviceMemoryProperties **out_memory) - { - VkPhysicalDeviceProperties *properties = NULL; -+ VkPhysicalDeviceMemoryProperties *memory_properties = NULL; - VkPhysicalDevice *vk_physical_devices = NULL; - VkInstance vk_instance = VK_NULL_HANDLE; - VkInstanceCreateInfo create_info; -@@ -99,11 +101,23 @@ static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, - goto done; - } - -+ if (!(memory_properties = heap_calloc(count, sizeof(*memory_properties)))) -+ { -+ WARN("Failed to allocate memory.\n"); -+ heap_free(properties); -+ ret = AGS_OUT_OF_MEMORY; -+ goto done; -+ } -+ - for (i = 0; i < count; ++i) - vkGetPhysicalDeviceProperties(vk_physical_devices[i], &properties[i]); - -+ for (i = 0; i < count; ++i) -+ vkGetPhysicalDeviceMemoryProperties(vk_physical_devices[i], &memory_properties[i]); -+ - *out_count = count; - *out = properties; -+ *out_memory = memory_properties; - - done: - heap_free(vk_physical_devices); -@@ -115,15 +129,16 @@ static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, - static AGSReturnCode init_ags_context(AGSContext *context) - { - AGSReturnCode ret; -- unsigned int i; -+ unsigned int i, j; - - // TODO: version check - context->version = AMD_AGS_VERSION_5_1_1; - context->device_count = 0; - context->devices = NULL; - context->properties = NULL; -+ context->memory_properties = NULL; - -- ret = vk_get_physical_device_properties(&context->device_count, &context->properties); -+ ret = vk_get_physical_device_properties(&context->device_count, &context->properties, &context->memory_properties); - if (ret != AGS_SUCCESS || !context->device_count) - return ret; - -@@ -131,13 +146,26 @@ static AGSReturnCode init_ags_context(AGSContext *context) - { - WARN("Failed to allocate memory.\n"); - heap_free(context->properties); -+ heap_free(context->memory_properties); - return AGS_OUT_OF_MEMORY; - } - - for (i = 0; i < context->device_count; ++i) - { - const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; -+ const VkPhysicalDeviceMemoryProperties *vk_memory_properties = &context->memory_properties[i]; - AGSDeviceInfo *device = &context->devices[i]; -+ VkDeviceSize local_memory_size = 0; -+ -+ for (j = 0; j < vk_memory_properties->memoryHeapCount; j++) -+ { -+ if (vk_memory_properties->memoryHeaps[j].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) -+ { -+ local_memory_size = vk_memory_properties->memoryHeaps[j].size; -+ break; -+ } -+ } -+ TRACE("reporting local memory size 0x%s bytes\n", wine_dbgstr_longlong(local_memory_size)); - - switch (context->version) - { -@@ -145,6 +173,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) - device->agsDeviceInfo511.adapterString = vk_properties->deviceName; - device->agsDeviceInfo511.vendorId = vk_properties->vendorID; - device->agsDeviceInfo511.deviceId = vk_properties->deviceID; -+ device->agsDeviceInfo511.localMemoryInBytes = local_memory_size; - - if (device->agsDeviceInfo511.vendorId == 0x1002) - device->agsDeviceInfo511.architectureVersion = ArchitectureVersion_GCN; -@@ -158,6 +187,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) - device->agsDeviceInfo520.adapterString = vk_properties->deviceName; - device->agsDeviceInfo520.vendorId = vk_properties->vendorID; - device->agsDeviceInfo520.deviceId = vk_properties->deviceID; -+ device->agsDeviceInfo520.localMemoryInBytes = local_memory_size; - - if (device->agsDeviceInfo520.vendorId == 0x1002) - device->agsDeviceInfo520.architectureVersion = ArchitectureVersion_GCN; -@@ -169,6 +199,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) - device->agsDeviceInfo540.adapterString = vk_properties->deviceName; - device->agsDeviceInfo540.vendorId = vk_properties->vendorID; - device->agsDeviceInfo540.deviceId = vk_properties->deviceID; -+ device->agsDeviceInfo540.localMemoryInBytes = local_memory_size; - - if (device->agsDeviceInfo540.vendorId == 0x1002) - device->agsDeviceInfo540.asicFamily = AsicFamily_GCN4; -@@ -181,6 +212,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) - device->agsDeviceInfo541.adapterString = vk_properties->deviceName; - device->agsDeviceInfo541.vendorId = vk_properties->vendorID; - device->agsDeviceInfo541.deviceId = vk_properties->deviceID; -+ device->agsDeviceInfo541.localMemoryInBytes = local_memory_size; - - if (device->agsDeviceInfo541.vendorId == 0x1002) - device->agsDeviceInfo541.asicFamily = AsicFamily_GCN4; -@@ -238,6 +270,7 @@ AGSReturnCode WINAPI agsDeInit(AGSContext *context) - - if (context) - { -+ heap_free(context->memory_properties); - heap_free(context->properties); - heap_free(context->devices); - heap_free(context); -From 3f97cc0dc89c51a72346ae5680ea4860016e92c5 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Wed, 17 Jun 2020 16:36:24 -0700 -Subject: [PATCH] amd_ags_x64: Update reported driver version to 20.20.2. - -Needed to silence warnings in Red Dead Redemption 2. ---- - dlls/amd_ags_x64/amd_ags_x64_main.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index d1ea7a23ce7..e8420acd4d1 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -252,8 +252,8 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi - gpu_info->agsVersionMajor = amd_ags_versions[object->version].major; - gpu_info->agsVersionMinor = amd_ags_versions[object->version].minor; - gpu_info->agsVersionPatch = amd_ags_versions[object->version].patch; -- gpu_info->driverVersion = "18.10.16-180516a-328911C-RadeonSoftwareAdrenalin"; -- gpu_info->radeonSoftwareVersion = "18.5.1"; -+ gpu_info->driverVersion = "20.20.2-180516a-328911C-RadeonSoftwareAdrenalin"; -+ gpu_info->radeonSoftwareVersion = "20.20.2"; - gpu_info->numDevices = object->device_count; - gpu_info->devices = object->devices; - -From 1a2c35253ed092cad7d08779f8d1ccde00d16c08 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Thu, 25 Jun 2020 15:54:59 -0700 -Subject: [PATCH] amd_ags_x64: Detect library version from DLL included with - game. - ---- - dlls/amd_ags_x64/Makefile.in | 2 +- - dlls/amd_ags_x64/amd_ags_x64_main.c | 70 ++++++++++++++++++++++++++++- - 2 files changed, 69 insertions(+), 3 deletions(-) - -diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in -index aa7127e2ede..ec13c055a26 100644 ---- a/dlls/amd_ags_x64/Makefile.in -+++ b/dlls/amd_ags_x64/Makefile.in -@@ -1,5 +1,5 @@ - MODULE = amd_ags_x64.dll --IMPORTS = vulkan-1 -+IMPORTS = version vulkan-1 - IMPORTLIB = amd_ags_x64 - - EXTRADLLFLAGS = -mno-cygwin -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index e8420acd4d1..49fc7ab7403 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -126,13 +126,79 @@ static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, - return ret; - } - -+static enum amd_ags_version determine_ags_version(void) -+{ -+ /* AMD AGS is not binary compatible between versions (even minor versions), and the game -+ * does not request a specific version when calling agsInit(). -+ * Checking the version of amd_ags_x64.dll shipped with the game is the only way to -+ * determine what version the game was built against. -+ * -+ * An update to AGS 5.4.1 included an amd_ags_x64.dll with no file version info. -+ * In case of an error, assume it's that version. -+ */ -+ enum amd_ags_version ret = AMD_AGS_VERSION_5_4_1; -+ DWORD infosize; -+ void *infobuf = NULL; -+ void *val; -+ UINT vallen, i; -+ VS_FIXEDFILEINFO *info; -+ UINT16 major, minor, patch; -+ -+ infosize = GetFileVersionInfoSizeW(L"amd_ags_x64.dll", NULL); -+ if (!infosize) -+ { -+ WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); -+ goto done; -+ } -+ -+ if (!(infobuf = heap_alloc(infosize))) -+ { -+ WARN("Failed to allocate memory.\n"); -+ goto done; -+ } -+ -+ if (!GetFileVersionInfoW(L"amd_ags_x64.dll", 0, infosize, infobuf)) -+ { -+ WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); -+ goto done; -+ } -+ -+ if (!VerQueryValueW(infobuf, L"\\", &val, &vallen) || (vallen != sizeof(VS_FIXEDFILEINFO))) -+ { -+ WARN("Unable to determine desired version of amd_ags_x64.dll.\n"); -+ goto done; -+ } -+ -+ info = val; -+ major = info->dwFileVersionMS >> 16; -+ minor = info->dwFileVersionMS; -+ patch = info->dwFileVersionLS >> 16; -+ TRACE("Found amd_ags_x64.dll v%d.%d.%d\n", major, minor, patch); -+ -+ for (i = 0; i < ARRAY_SIZE(amd_ags_versions); i++) -+ { -+ if ((major == amd_ags_versions[i].major) && -+ (minor == amd_ags_versions[i].minor) && -+ (patch == amd_ags_versions[i].patch)) -+ { -+ ret = i; -+ break; -+ } -+ } -+ -+done: -+ heap_free(infobuf); -+ TRACE("Using AGS v%d.%d.%d interface\n", -+ amd_ags_versions[ret].major, amd_ags_versions[ret].minor, amd_ags_versions[ret].patch); -+ return ret; -+} -+ - static AGSReturnCode init_ags_context(AGSContext *context) - { - AGSReturnCode ret; - unsigned int i, j; - -- // TODO: version check -- context->version = AMD_AGS_VERSION_5_1_1; -+ context->version = determine_ags_version(); - context->device_count = 0; - context->devices = NULL; - context->properties = NULL; -From 3980ab91bb5cf975eacbba60f68c0d96af2da74b Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 16 Apr 2021 20:21:29 +0300 -Subject: [PATCH] amd_ags_x64: Don't use ordinals in spec file. - -For FH4. ---- - dlls/amd_ags_x64/amd_ags_x64.spec | 58 +++++++++++++++---------------- - 1 file changed, 29 insertions(+), 29 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -index a302d2fc657..c571dac2184 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64.spec -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -1,29 +1,29 @@ --1 stdcall agsDeInit(ptr) --2 stub agsDriverExtensionsDX11_BeginUAVOverlap --3 stub agsDriverExtensionsDX11_CreateBuffer --4 stub agsDriverExtensionsDX11_CreateTexture1D --5 stub agsDriverExtensionsDX11_CreateTexture2D --6 stub agsDriverExtensionsDX11_CreateTexture3D --7 stub agsDriverExtensionsDX11_DeInit --8 stub agsDriverExtensionsDX11_EndUAVOverlap --9 stub agsDriverExtensionsDX11_GetMaxClipRects --10 stub agsDriverExtensionsDX11_IASetPrimitiveTopology --11 stub agsDriverExtensionsDX11_Init --12 stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect --13 stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect --14 stub agsDriverExtensionsDX11_MultiDrawInstancedIndirect --15 stub agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect --16 stub agsDriverExtensionsDX11_NotifyResourceBeginAllAccess --17 stub agsDriverExtensionsDX11_NotifyResourceEndAllAccess --18 stub agsDriverExtensionsDX11_NotifyResourceEndWrites --19 stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs --20 stub agsDriverExtensionsDX11_SetClipRects --21 stub agsDriverExtensionsDX11_SetDepthBounds --22 stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled --23 stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount --24 stub agsDriverExtensionsDX11_SetViewBroadcastMasks --25 stub agsDriverExtensionsDX12_DeInit --26 stub agsDriverExtensionsDX12_Init --27 stdcall agsGetCrossfireGPUCount(ptr ptr) --28 stdcall agsInit(ptr ptr ptr) --29 stub agsSetDisplayMode -+@ stdcall agsDeInit(ptr) -+@ stub agsDriverExtensionsDX11_BeginUAVOverlap -+@ stub agsDriverExtensionsDX11_CreateBuffer -+@ stub agsDriverExtensionsDX11_CreateTexture1D -+@ stub agsDriverExtensionsDX11_CreateTexture2D -+@ stub agsDriverExtensionsDX11_CreateTexture3D -+@ stub agsDriverExtensionsDX11_DeInit -+@ stub agsDriverExtensionsDX11_EndUAVOverlap -+@ stub agsDriverExtensionsDX11_GetMaxClipRects -+@ stub agsDriverExtensionsDX11_IASetPrimitiveTopology -+@ stub agsDriverExtensionsDX11_Init -+@ stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect -+@ stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect -+@ stub agsDriverExtensionsDX11_MultiDrawInstancedIndirect -+@ stub agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect -+@ stub agsDriverExtensionsDX11_NotifyResourceBeginAllAccess -+@ stub agsDriverExtensionsDX11_NotifyResourceEndAllAccess -+@ stub agsDriverExtensionsDX11_NotifyResourceEndWrites -+@ stub agsDriverExtensionsDX11_NumPendingAsyncCompileJobs -+@ stub agsDriverExtensionsDX11_SetClipRects -+@ stub agsDriverExtensionsDX11_SetDepthBounds -+@ stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled -+@ stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount -+@ stub agsDriverExtensionsDX11_SetViewBroadcastMasks -+@ stub agsDriverExtensionsDX12_DeInit -+@ stub agsDriverExtensionsDX12_Init -+@ stdcall agsGetCrossfireGPUCount(ptr ptr) -+@ stdcall agsInit(ptr ptr ptr) -+@ stub agsSetDisplayMode -From b4f2009bb93926cc8f4144c7da950fbd94b7d36b Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 16 Apr 2021 20:07:28 +0300 -Subject: [PATCH] amd_ags_x64: Add more stubs to spec file. - -For FH4. ---- - dlls/amd_ags_x64/amd_ags_x64.spec | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -index c571dac2184..f483cc6380b 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64.spec -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -1,10 +1,15 @@ - @ stdcall agsDeInit(ptr) -+@ stub agsCheckDriverVersion - @ stub agsDriverExtensionsDX11_BeginUAVOverlap - @ stub agsDriverExtensionsDX11_CreateBuffer -+@ stub agsDriverExtensionsDX11_CreateDevice -+@ stub agsDriverExtensionsDX11_CreateFromDevice - @ stub agsDriverExtensionsDX11_CreateTexture1D - @ stub agsDriverExtensionsDX11_CreateTexture2D - @ stub agsDriverExtensionsDX11_CreateTexture3D - @ stub agsDriverExtensionsDX11_DeInit -+@ stub agsDriverExtensionsDX11_Destroy -+@ stub agsDriverExtensionsDX11_DestroyDevice - @ stub agsDriverExtensionsDX11_EndUAVOverlap - @ stub agsDriverExtensionsDX11_GetMaxClipRects - @ stub agsDriverExtensionsDX11_IASetPrimitiveTopology -@@ -22,8 +27,16 @@ - @ stub agsDriverExtensionsDX11_SetDiskShaderCacheEnabled - @ stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount - @ stub agsDriverExtensionsDX11_SetViewBroadcastMasks -+@ stub agsDriverExtensionsDX11_WriteBreadcrumb -+@ stub agsDriverExtensionsDX12_CreateDevice -+@ stub agsDriverExtensionsDX12_CreateFromDevice - @ stub agsDriverExtensionsDX12_DeInit -+@ stub agsDriverExtensionsDX12_Destroy -+@ stub agsDriverExtensionsDX12_DestroyDevice - @ stub agsDriverExtensionsDX12_Init -+@ stub agsDriverExtensionsDX12_PopMarker -+@ stub agsDriverExtensionsDX12_PushMarker -+@ stub agsDriverExtensionsDX12_SetMarker - @ stdcall agsGetCrossfireGPUCount(ptr ptr) - @ stdcall agsInit(ptr ptr ptr) - @ stub agsSetDisplayMode -From 51848a361897a35c6cd657b786f127883c294b9f Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 16 Apr 2021 20:30:22 +0300 -Subject: [PATCH] amd_ags_x64: Add partial stub for agsCheckDriverVersion(). - -For FH4. ---- - dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- - dlls/amd_ags_x64/amd_ags_x64_main.c | 7 +++++++ - 2 files changed, 8 insertions(+), 1 deletion(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -index f483cc6380b..6806b145751 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64.spec -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -1,5 +1,5 @@ - @ stdcall agsDeInit(ptr) --@ stub agsCheckDriverVersion -+@ stdcall agsCheckDriverVersion(ptr long) - @ stub agsDriverExtensionsDX11_BeginUAVOverlap - @ stub agsDriverExtensionsDX11_CreateBuffer - @ stub agsDriverExtensionsDX11_CreateDevice -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 49fc7ab7403..6e2c22c80d9 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -356,6 +356,13 @@ AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count - return AGS_SUCCESS; - } - -+AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported, unsigned int version_required) -+{ -+ FIXME("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); -+ -+ return AGS_SOFTWAREVERSIONCHECK_OK; -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - TRACE("%p, %u, %p.\n", instance, reason, reserved); -From 9dff4b41f450f6182a0d567e6bd296cb8cef450c Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 16 Apr 2021 20:35:31 +0300 -Subject: [PATCH] amd_ags_x64: Implement - agsDriverExtensionsDX12_CreateDevice(). - -For FH4. ---- - dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- - dlls/amd_ags_x64/amd_ags_x64_main.c | 43 +++++++++++++++++++++++++++++ - 2 files changed, 44 insertions(+), 1 deletion(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -index 6806b145751..7551a9346d8 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64.spec -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -28,7 +28,7 @@ - @ stub agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount - @ stub agsDriverExtensionsDX11_SetViewBroadcastMasks - @ stub agsDriverExtensionsDX11_WriteBreadcrumb --@ stub agsDriverExtensionsDX12_CreateDevice -+@ stdcall agsDriverExtensionsDX12_CreateDevice(ptr ptr ptr ptr) - @ stub agsDriverExtensionsDX12_CreateFromDevice - @ stub agsDriverExtensionsDX12_DeInit - @ stub agsDriverExtensionsDX12_Destroy -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 6e2c22c80d9..6f40a4c509c 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -52,6 +52,21 @@ struct AGSContext - VkPhysicalDeviceMemoryProperties *memory_properties; - }; - -+static HMODULE hd3d12; -+static typeof(D3D12CreateDevice) *pD3D12CreateDevice; -+ -+static BOOL load_d3d12_functions(void) -+{ -+ if (hd3d12) -+ return TRUE; -+ -+ if (!(hd3d12 = LoadLibraryA("d3d12.dll"))) -+ return FALSE; -+ -+ pD3D12CreateDevice = (void *)GetProcAddress(hd3d12, "D3D12CreateDevice"); -+ return TRUE; -+} -+ - static AGSReturnCode vk_get_physical_device_properties(unsigned int *out_count, - VkPhysicalDeviceProperties **out, VkPhysicalDeviceMemoryProperties **out_memory) - { -@@ -356,6 +371,34 @@ AGSReturnCode WINAPI agsGetCrossfireGPUCount(AGSContext *context, int *gpu_count - return AGS_SUCCESS; - } - -+AGSReturnCode WINAPI agsDriverExtensionsDX12_CreateDevice(AGSContext *context, -+ const AGSDX12DeviceCreationParams *creation_params, const AGSDX12ExtensionParams *extension_params, -+ AGSDX12ReturnedParams *returned_params) -+{ -+ HRESULT hr; -+ -+ TRACE("feature level %#x, app %s, engine %s %#x %#x.\n", creation_params->FeatureLevel, debugstr_w(extension_params->pAppName), -+ debugstr_w(extension_params->pEngineName), extension_params->appVersion, extension_params->engineVersion); -+ -+ if (!load_d3d12_functions()) -+ { -+ ERR("Could not load d3d12.dll.\n"); -+ return AGS_MISSING_D3D_DLL; -+ } -+ -+ memset(returned_params, 0, sizeof(*returned_params)); -+ if (FAILED(hr = pD3D12CreateDevice((IUnknown *)creation_params->pAdapter, creation_params->FeatureLevel, -+ &creation_params->iid, (void **)&returned_params->pDevice))) -+ { -+ ERR("D3D12CreateDevice failed, hr %#x.\n", hr); -+ return AGS_DX_FAILURE; -+ } -+ -+ TRACE("Created d3d12 device %p.\n", returned_params->pDevice); -+ -+ return AGS_SUCCESS; -+} -+ - AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported, unsigned int version_required) - { - FIXME("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); -From 5343e10e71b0e21d1510da31386692faf290cd0d Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 16 Apr 2021 17:29:31 +0300 -Subject: [PATCH] amd_ags_x64: Fix devices array layout. - -For FH4. - -And refactor multiple layout device structure handling on the way -to avoid more switches in future patches. ---- - dlls/amd_ags_x64/amd_ags.h | 10 +- - dlls/amd_ags_x64/amd_ags_x64_main.c | 152 +++++++++++++++------------- - 2 files changed, 83 insertions(+), 79 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index 30f3735915c..47ed5b91a14 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -498,13 +498,7 @@ typedef struct AGSDeviceInfo_541 - int adlAdapterIndex; ///< Internally used index into the ADL list of adapters - } AGSDeviceInfo_541; - --typedef union AGSDeviceInfo --{ -- AGSDeviceInfo_511 agsDeviceInfo511; -- AGSDeviceInfo_520 agsDeviceInfo520; -- AGSDeviceInfo_540 agsDeviceInfo540; -- AGSDeviceInfo_541 agsDeviceInfo541; --} AGSDeviceInfo; -+struct AGSDeviceInfo; - - /// \defgroup general General API functions - /// API for initialization, cleanup, HDR display modes and Crossfire GPU count -@@ -545,7 +539,7 @@ typedef struct AGSGPUInfo - const char* radeonSoftwareVersion; ///< The Radeon Software Version - - int numDevices; ///< Number of GPUs in the system -- AGSDeviceInfo* devices; ///< List of GPUs in the system -+ struct AGSDeviceInfo* devices; ///< List of GPUs in the system - } AGSGPUInfo; - - /// The struct to specify the display settings to the driver. -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 6f40a4c509c..6c71db021dc 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -1,5 +1,6 @@ - #include - #include -+#include - - #include "windef.h" - #include "winbase.h" -@@ -27,27 +28,74 @@ enum amd_ags_version - AMD_AGS_VERSION_COUNT - }; - --struct -+static const struct - { - int major; - int minor; - int patch; -+ unsigned int device_size; - } --static const amd_ags_versions[AMD_AGS_VERSION_COUNT] = -+amd_ags_info[AMD_AGS_VERSION_COUNT] = - { -- {5, 1, 1}, -- {5, 2, 0}, -- {5, 2, 1}, -- {5, 3, 0}, -- {5, 4, 0}, -- {5, 4, 1}, -+ {5, 1, 1, sizeof(AGSDeviceInfo_511)}, -+ {5, 2, 0, sizeof(AGSDeviceInfo_520)}, -+ {5, 2, 1, sizeof(AGSDeviceInfo_520)}, -+ {5, 3, 0, sizeof(AGSDeviceInfo_520)}, -+ {5, 4, 0, sizeof(AGSDeviceInfo_540)}, -+ {5, 4, 1, sizeof(AGSDeviceInfo_541)}, - }; - -+#define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ -+ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ -+ offsetof(AGSDeviceInfo_541, name)}} -+#define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ -+ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ -+ -1}} -+#define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ -+ -1, -1, offsetof(AGSDeviceInfo_540, name), \ -+ offsetof(AGSDeviceInfo_541, name)}} -+ -+#define DEVICE_FIELD_adapterString 0 -+#define DEVICE_FIELD_architectureVersion 1 -+#define DEVICE_FIELD_asicFamily 2 -+#define DEVICE_FIELD_vendorId 3 -+#define DEVICE_FIELD_deviceId 4 -+#define DEVICE_FIELD_isPrimaryDevice 5 -+#define DEVICE_FIELD_localMemoryInBytes 6 -+ -+static const struct -+{ -+ unsigned int field_index; -+ int offset[AMD_AGS_VERSION_COUNT]; -+} -+device_struct_fields[] = -+{ -+ DEF_FIELD(adapterString), -+ DEF_FIELD_520_BELOW(architectureVersion), -+ DEF_FIELD_540_UP(asicFamily), -+ DEF_FIELD(vendorId), -+ DEF_FIELD(deviceId), -+ DEF_FIELD(isPrimaryDevice), -+ DEF_FIELD(localMemoryInBytes), -+}; -+ -+#undef DEF_FIELD -+ -+#define GET_DEVICE_FIELD_ADDR(device, name, type, version) \ -+ (device_struct_fields[DEVICE_FIELD_##name].offset[version] == -1 ? NULL \ -+ : (type *)((BYTE *)device + device_struct_fields[DEVICE_FIELD_##name].offset[version])) -+ -+#define SET_DEVICE_FIELD(device, name, type, version, value) { \ -+ type *addr; \ -+ if ((addr = GET_DEVICE_FIELD_ADDR(device, name, type, version))) \ -+ *addr = value; \ -+ } -+ - struct AGSContext - { - enum amd_ags_version version; - unsigned int device_count; -- AGSDeviceInfo *devices; -+ struct AGSDeviceInfo *devices; - VkPhysicalDeviceProperties *properties; - VkPhysicalDeviceMemoryProperties *memory_properties; - }; -@@ -190,11 +238,11 @@ static enum amd_ags_version determine_ags_version(void) - patch = info->dwFileVersionLS >> 16; - TRACE("Found amd_ags_x64.dll v%d.%d.%d\n", major, minor, patch); - -- for (i = 0; i < ARRAY_SIZE(amd_ags_versions); i++) -+ for (i = 0; i < ARRAY_SIZE(amd_ags_info); i++) - { -- if ((major == amd_ags_versions[i].major) && -- (minor == amd_ags_versions[i].minor) && -- (patch == amd_ags_versions[i].patch)) -+ if ((major == amd_ags_info[i].major) && -+ (minor == amd_ags_info[i].minor) && -+ (patch == amd_ags_info[i].patch)) - { - ret = i; - break; -@@ -204,7 +252,7 @@ static enum amd_ags_version determine_ags_version(void) - done: - heap_free(infobuf); - TRACE("Using AGS v%d.%d.%d interface\n", -- amd_ags_versions[ret].major, amd_ags_versions[ret].minor, amd_ags_versions[ret].patch); -+ amd_ags_info[ret].major, amd_ags_info[ret].minor, amd_ags_info[ret].patch); - return ret; - } - -@@ -212,6 +260,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) - { - AGSReturnCode ret; - unsigned int i, j; -+ BYTE *device; - - context->version = determine_ags_version(); - context->device_count = 0; -@@ -223,7 +272,9 @@ static AGSReturnCode init_ags_context(AGSContext *context) - if (ret != AGS_SUCCESS || !context->device_count) - return ret; - -- if (!(context->devices = heap_calloc(context->device_count, sizeof(*context->devices)))) -+ assert(context->version < AMD_AGS_VERSION_COUNT); -+ -+ if (!(context->devices = heap_calloc(context->device_count, amd_ags_info[context->version].device_size))) - { - WARN("Failed to allocate memory.\n"); - heap_free(context->properties); -@@ -231,11 +282,11 @@ static AGSReturnCode init_ags_context(AGSContext *context) - return AGS_OUT_OF_MEMORY; - } - -+ device = (BYTE *)context->devices; - for (i = 0; i < context->device_count; ++i) - { - const VkPhysicalDeviceProperties *vk_properties = &context->properties[i]; - const VkPhysicalDeviceMemoryProperties *vk_memory_properties = &context->memory_properties[i]; -- AGSDeviceInfo *device = &context->devices[i]; - VkDeviceSize local_memory_size = 0; - - for (j = 0; j < vk_memory_properties->memoryHeapCount; j++) -@@ -248,60 +299,19 @@ static AGSReturnCode init_ags_context(AGSContext *context) - } - TRACE("reporting local memory size 0x%s bytes\n", wine_dbgstr_longlong(local_memory_size)); - -- switch (context->version) -+ SET_DEVICE_FIELD(device, adapterString, const char *, context->version, vk_properties->deviceName); -+ SET_DEVICE_FIELD(device, vendorId, int, context->version, vk_properties->vendorID); -+ SET_DEVICE_FIELD(device, deviceId, int, context->version, vk_properties->deviceID); -+ if (vk_properties->vendorID == 0x1002) - { -- case AMD_AGS_VERSION_5_1_1: -- device->agsDeviceInfo511.adapterString = vk_properties->deviceName; -- device->agsDeviceInfo511.vendorId = vk_properties->vendorID; -- device->agsDeviceInfo511.deviceId = vk_properties->deviceID; -- device->agsDeviceInfo511.localMemoryInBytes = local_memory_size; -- -- if (device->agsDeviceInfo511.vendorId == 0x1002) -- device->agsDeviceInfo511.architectureVersion = ArchitectureVersion_GCN; -- -- if (!i) -- device->agsDeviceInfo511.isPrimaryDevice = 1; -- break; -- case AMD_AGS_VERSION_5_2_0: -- case AMD_AGS_VERSION_5_2_1: -- case AMD_AGS_VERSION_5_3_0: -- device->agsDeviceInfo520.adapterString = vk_properties->deviceName; -- device->agsDeviceInfo520.vendorId = vk_properties->vendorID; -- device->agsDeviceInfo520.deviceId = vk_properties->deviceID; -- device->agsDeviceInfo520.localMemoryInBytes = local_memory_size; -- -- if (device->agsDeviceInfo520.vendorId == 0x1002) -- device->agsDeviceInfo520.architectureVersion = ArchitectureVersion_GCN; -- -- if (!i) -- device->agsDeviceInfo520.isPrimaryDevice = 1; -- break; -- case AMD_AGS_VERSION_5_4_0: -- device->agsDeviceInfo540.adapterString = vk_properties->deviceName; -- device->agsDeviceInfo540.vendorId = vk_properties->vendorID; -- device->agsDeviceInfo540.deviceId = vk_properties->deviceID; -- device->agsDeviceInfo540.localMemoryInBytes = local_memory_size; -- -- if (device->agsDeviceInfo540.vendorId == 0x1002) -- device->agsDeviceInfo540.asicFamily = AsicFamily_GCN4; -- -- if (!i) -- device->agsDeviceInfo540.isPrimaryDevice = 1; -- break; -- case AMD_AGS_VERSION_5_4_1: -- default: -- device->agsDeviceInfo541.adapterString = vk_properties->deviceName; -- device->agsDeviceInfo541.vendorId = vk_properties->vendorID; -- device->agsDeviceInfo541.deviceId = vk_properties->deviceID; -- device->agsDeviceInfo541.localMemoryInBytes = local_memory_size; -- -- if (device->agsDeviceInfo541.vendorId == 0x1002) -- device->agsDeviceInfo541.asicFamily = AsicFamily_GCN4; -- -- if (!i) -- device->agsDeviceInfo541.isPrimaryDevice = 1; -- break; -+ SET_DEVICE_FIELD(device, architectureVersion, ArchitectureVersion, context->version, ArchitectureVersion_GCN); -+ SET_DEVICE_FIELD(device, asicFamily, AsicFamily, context->version, AsicFamily_GCN4); - } -+ SET_DEVICE_FIELD(device, localMemoryInBytes, ULONG64, context->version, local_memory_size); -+ if (!i) -+ SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); -+ -+ device += amd_ags_info[context->version].device_size; - } - - return AGS_SUCCESS; -@@ -330,9 +340,9 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi - } - - memset(gpu_info, 0, sizeof(*gpu_info)); -- gpu_info->agsVersionMajor = amd_ags_versions[object->version].major; -- gpu_info->agsVersionMinor = amd_ags_versions[object->version].minor; -- gpu_info->agsVersionPatch = amd_ags_versions[object->version].patch; -+ gpu_info->agsVersionMajor = amd_ags_info[object->version].major; -+ gpu_info->agsVersionMinor = amd_ags_info[object->version].minor; -+ gpu_info->agsVersionPatch = amd_ags_info[object->version].patch; - gpu_info->driverVersion = "20.20.2-180516a-328911C-RadeonSoftwareAdrenalin"; - gpu_info->radeonSoftwareVersion = "20.20.2"; - gpu_info->numDevices = object->device_count; -From a4082f0890971011e11102dcb424a68ca6e1f035 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 16 Apr 2021 19:33:36 +0300 -Subject: [PATCH] amd_ags_x64: Fill display info in AGS context. - -For FH4. ---- - dlls/amd_ags_x64/Makefile.in | 2 +- - dlls/amd_ags_x64/amd_ags_x64_main.c | 116 ++++++++++++++++++++++++++++ - 2 files changed, 117 insertions(+), 1 deletion(-) - -diff --git a/dlls/amd_ags_x64/Makefile.in b/dlls/amd_ags_x64/Makefile.in -index ec13c055a26..4bc7505f509 100644 ---- a/dlls/amd_ags_x64/Makefile.in -+++ b/dlls/amd_ags_x64/Makefile.in -@@ -1,5 +1,5 @@ - MODULE = amd_ags_x64.dll --IMPORTS = version vulkan-1 -+IMPORTS = version vulkan-1 user32 - IMPORTLIB = amd_ags_x64 - - EXTRADLLFLAGS = -mno-cygwin -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 6c71db021dc..c0a654939dd 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -62,6 +62,8 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = - #define DEVICE_FIELD_deviceId 4 - #define DEVICE_FIELD_isPrimaryDevice 5 - #define DEVICE_FIELD_localMemoryInBytes 6 -+#define DEVICE_FIELD_numDisplays 7 -+#define DEVICE_FIELD_displays 8 - - static const struct - { -@@ -77,6 +79,8 @@ device_struct_fields[] = - DEF_FIELD(deviceId), - DEF_FIELD(isPrimaryDevice), - DEF_FIELD(localMemoryInBytes), -+ DEF_FIELD(numDisplays), -+ DEF_FIELD(displays), - }; - - #undef DEF_FIELD -@@ -256,6 +260,105 @@ static enum amd_ags_version determine_ags_version(void) - return ret; - } - -+struct monitor_enum_context -+{ -+ const char *adapter_name; -+ AGSDisplayInfo **ret_displays; -+ int *ret_display_count; -+}; -+ -+static BOOL WINAPI monitor_enum_proc(HMONITOR hmonitor, HDC hdc, RECT *rect, LPARAM context) -+{ -+ struct monitor_enum_context *c = (struct monitor_enum_context *)context; -+ MONITORINFOEXA monitor_info; -+ AGSDisplayInfo *new_alloc; -+ DISPLAY_DEVICEA device; -+ AGSDisplayInfo *info; -+ unsigned int i, mode; -+ DEVMODEA dev_mode; -+ -+ -+ monitor_info.cbSize = sizeof(monitor_info); -+ GetMonitorInfoA(hmonitor, (MONITORINFO *)&monitor_info); -+ -+ device.cb = sizeof(device); -+ i = 0; -+ while (EnumDisplayDevicesA(NULL, i, &device, 0)) -+ { -+ ++i; -+ if (strcmp(device.DeviceString, c->adapter_name) || strcmp(device.DeviceName, monitor_info.szDevice)) -+ continue; -+ -+ if (*c->ret_display_count) -+ { -+ if (!(new_alloc = heap_realloc(*c->ret_displays, sizeof(*new_alloc) * (*c->ret_display_count + 1)))) -+ { -+ ERR("No memory."); -+ return FALSE; -+ } -+ *c->ret_displays = new_alloc; -+ } -+ else if (!(*c->ret_displays = heap_alloc(sizeof(**c->ret_displays)))) -+ { -+ ERR("No memory."); -+ return FALSE; -+ } -+ info = &(*c->ret_displays)[*c->ret_display_count]; -+ memset(info, 0, sizeof(*info)); -+ strcpy(info->displayDeviceName, device.DeviceName); -+ if (EnumDisplayDevicesA(info->displayDeviceName, 0, &device, 0)) -+ { -+ strcpy(info->name, device.DeviceString); -+ } -+ else -+ { -+ ERR("Could not get monitor name for device %s.\n", debugstr_a(info->displayDeviceName)); -+ strcpy(info->name, "Unknown"); -+ } -+ if (monitor_info.dwFlags & MONITORINFOF_PRIMARY) -+ info->displayFlags |= AGS_DISPLAYFLAG_PRIMARY_DISPLAY; -+ -+ mode = 0; -+ while (EnumDisplaySettingsExA(monitor_info.szDevice, mode, &dev_mode, EDS_RAWMODE)) -+ { -+ ++mode; -+ if (dev_mode.dmPelsWidth > info->maxResolutionX) -+ info->maxResolutionX = dev_mode.dmPelsWidth; -+ if (dev_mode.dmPelsHeight > info->maxResolutionY) -+ info->maxResolutionY = dev_mode.dmPelsHeight; -+ if (dev_mode.dmDisplayFrequency > info->maxRefreshRate) -+ info->maxRefreshRate = dev_mode.dmDisplayFrequency; -+ } -+ -+ info->currentResolution.offsetX = monitor_info.rcMonitor.left; -+ info->currentResolution.offsetY = monitor_info.rcMonitor.top; -+ info->currentResolution.width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left; -+ info->currentResolution.height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top; -+ info->visibleResolution = info->currentResolution; -+ -+ if (EnumDisplaySettingsExA(monitor_info.szDevice, ENUM_CURRENT_SETTINGS, &dev_mode, EDS_RAWMODE)) -+ info->currentRefreshRate = dev_mode.dmDisplayFrequency; -+ else -+ ERR("Could not get current display settings.\n"); -+ ++*c->ret_display_count; -+ -+ TRACE("Added display %s for %s.\n", debugstr_a(monitor_info.szDevice), debugstr_a(c->adapter_name)); -+ } -+ -+ return TRUE; -+} -+ -+static void init_device_displays(const char *adapter_name, AGSDisplayInfo **ret_displays, int *ret_display_count) -+{ -+ struct monitor_enum_context context; -+ -+ context.adapter_name = adapter_name; -+ context.ret_displays = ret_displays; -+ context.ret_display_count = ret_display_count; -+ -+ EnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)&context); -+} -+ - static AGSReturnCode init_ags_context(AGSContext *context) - { - AGSReturnCode ret; -@@ -311,6 +414,10 @@ static AGSReturnCode init_ags_context(AGSContext *context) - if (!i) - SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); - -+ init_device_displays(vk_properties->deviceName, -+ GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo *, context->version), -+ GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); -+ - device += amd_ags_info[context->version].device_size; - } - -@@ -357,12 +464,21 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi - - AGSReturnCode WINAPI agsDeInit(AGSContext *context) - { -+ unsigned int i; -+ BYTE *device; -+ - TRACE("context %p.\n", context); - - if (context) - { - heap_free(context->memory_properties); - heap_free(context->properties); -+ device = (BYTE *)context->devices; -+ for (i = 0; i < context->device_count; ++i) -+ { -+ heap_free(GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo *, context->version)); -+ device += amd_ags_info[context->version].device_size; -+ } - heap_free(context->devices); - heap_free(context); - } -From c175c21b2f0cd183a4d729a4fdcf67a403f4645f Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 16 Apr 2021 20:03:12 +0300 -Subject: [PATCH] amd_ags_x64: Bump driver version. - -For FH4. ---- - dlls/amd_ags_x64/amd_ags_x64_main.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index c0a654939dd..20bf4aa3434 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -450,8 +450,8 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi - gpu_info->agsVersionMajor = amd_ags_info[object->version].major; - gpu_info->agsVersionMinor = amd_ags_info[object->version].minor; - gpu_info->agsVersionPatch = amd_ags_info[object->version].patch; -- gpu_info->driverVersion = "20.20.2-180516a-328911C-RadeonSoftwareAdrenalin"; -- gpu_info->radeonSoftwareVersion = "20.20.2"; -+ gpu_info->driverVersion = "20.50.03.05-210326a-365573E-RadeonSoftwareAdrenalin2020"; -+ gpu_info->radeonSoftwareVersion = "21.3.2"; - gpu_info->numDevices = object->device_count; - gpu_info->devices = object->devices; - -From d6ef1e96438b3700c18fcbb3bfcb66ee3c223535 Mon Sep 17 00:00:00 2001 -From: Joshua Ashton -Date: Sat, 8 May 2021 04:39:30 +0100 -Subject: [PATCH] amd_ags_x64: Implement agsDriverExtensionsDX12_DestroyDevice - -Signed-off-by: Joshua Ashton ---- - dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- - dlls/amd_ags_x64/amd_ags_x64_main.c | 15 +++++++++++++++ - 2 files changed, 16 insertions(+), 1 deletion(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -index 7551a9346d8..ae825462f28 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64.spec -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -32,7 +32,7 @@ - @ stub agsDriverExtensionsDX12_CreateFromDevice - @ stub agsDriverExtensionsDX12_DeInit - @ stub agsDriverExtensionsDX12_Destroy --@ stub agsDriverExtensionsDX12_DestroyDevice -+@ stdcall agsDriverExtensionsDX12_DestroyDevice(ptr ptr ptr) - @ stub agsDriverExtensionsDX12_Init - @ stub agsDriverExtensionsDX12_PopMarker - @ stub agsDriverExtensionsDX12_PushMarker -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 1a425d11514..1d4eb74e502 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -9,6 +9,7 @@ - - #include "wine/vulkan.h" - -+#define COBJMACROS - #include "d3d11.h" - #include "d3d12.h" - -@@ -537,6 +538,20 @@ AGSReturnCode WINAPI agsDriverExtensionsDX12_CreateDevice(AGSContext *context, - return AGS_SUCCESS; - } - -+AGSReturnCode WINAPI agsDriverExtensionsDX12_DestroyDevice(AGSContext* context, ID3D12Device* device, unsigned int* device_refs) -+{ -+ ULONG ref_count; -+ -+ if (!device) -+ return AGS_SUCCESS; -+ -+ ref_count = ID3D12Device_Release(device); -+ if (device_refs) -+ *device_refs = (unsigned int)ref_count; -+ -+ return AGS_SUCCESS; -+} -+ - AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported, unsigned int version_required) - { - FIXME("version_reported %s, version_required %d semi-stub.\n", debugstr_a(version_reported), version_required); -From 627d913258288345c16c1fc45f1134c04594c3b6 Mon Sep 17 00:00:00 2001 -From: Joshua Ashton -Date: Sat, 8 May 2021 04:41:40 +0100 -Subject: [PATCH] amd_ags_x64: Implement AGS 5.4.2 - -Signed-off-by: Joshua Ashton ---- - dlls/amd_ags_x64/amd_ags.h | 46 ++++++++++++++++++++++++++++- - dlls/amd_ags_x64/amd_ags_x64_main.c | 8 +++-- - 2 files changed, 50 insertions(+), 4 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index 47ed5b91a14..0656e3fbbb3 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -34,6 +34,13 @@ - /// \endinternal - /// - /// --------------------------------------- -+/// What's new in AGS 5.4.2 since version 5.4.1 -+/// --------------------------------------- -+/// AGS 5.4.2 includes the following updates: -+/// * sharedMemoryInBytes has been reinstated. -+/// * Clock speed returned for APUs. -+/// -+/// --------------------------------------- - /// What's new in AGS 5.4.1 since version 5.4.0 - /// --------------------------------------- - /// AGS 5.4.1 includes the following updates: -@@ -130,7 +137,7 @@ - - #define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version - #define AMD_AGS_VERSION_MINOR 4 ///< AGS minor version --#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version -+#define AMD_AGS_VERSION_PATCH 2 ///< AGS patch version - - #ifdef __cplusplus - extern "C" { -@@ -498,6 +505,43 @@ typedef struct AGSDeviceInfo_541 - int adlAdapterIndex; ///< Internally used index into the ADL list of adapters - } AGSDeviceInfo_541; - -+/// The device info struct used to describe a physical GPU enumerated by AGS -+typedef struct AGSDeviceInfo_542 -+{ -+ const char* adapterString; ///< The adapter name string -+ AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware -+ int isAPU; ///< Whether or not this is an APU -+ int vendorId; ///< The vendor id -+ int deviceId; ///< The device id -+ int revisionId; ///< The revision id -+ -+ int numCUs; ///< Number of compute units. -+ int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. -+ -+ int numROPs; ///< Number of ROPs -+ int coreClock; ///< Core clock speed at 100% power in MHz -+ int memoryClock; ///< Memory clock speed at 100% power in MHz -+ int memoryBandwidth; ///< Memory bandwidth in MB/s -+ float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD -+ -+ int isPrimaryDevice; ///< Whether or not this is the primary adapter in the system. Not set on the WACK version. -+ unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. -+ unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs -+ ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. -+ -+ int numDisplays; ///< The number of active displays found to be attached to this adapter. -+ AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ -+ int eyefinityEnabled; ///< Indicates if Eyefinity is active -+ int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. -+ int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. -+ int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. -+ -+ int adlAdapterIndex; ///< Internally used index into the ADL list of adapters -+} AGSDeviceInfo_542; -+ - struct AGSDeviceInfo; - - /// \defgroup general General API functions -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 1d4eb74e502..35de799430d 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -25,6 +25,7 @@ enum amd_ags_version - AMD_AGS_VERSION_5_3_0, - AMD_AGS_VERSION_5_4_0, - AMD_AGS_VERSION_5_4_1, -+ AMD_AGS_VERSION_5_4_2, - - AMD_AGS_VERSION_COUNT - }; -@@ -44,17 +45,18 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = - {5, 3, 0, sizeof(AGSDeviceInfo_520)}, - {5, 4, 0, sizeof(AGSDeviceInfo_540)}, - {5, 4, 1, sizeof(AGSDeviceInfo_541)}, -+ {5, 4, 2, sizeof(AGSDeviceInfo_542)}, - }; - - #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ - offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ -- offsetof(AGSDeviceInfo_541, name)}} -+ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name)}} - #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ - offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ -- -1}} -+ -1, -1}} - #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ - -1, -1, offsetof(AGSDeviceInfo_540, name), \ -- offsetof(AGSDeviceInfo_541, name)}} -+ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name)}} - - #define DEVICE_FIELD_adapterString 0 - #define DEVICE_FIELD_architectureVersion 1 -From 4f14f287f3468b977e2978599e7ac81643b46ec6 Mon Sep 17 00:00:00 2001 -From: Joshua Ashton -Date: Sat, 8 May 2021 05:14:39 +0100 -Subject: [PATCH] amd_ags_x64: Implement AGS 6.0.0 - -Signed-off-by: Joshua Ashton ---- - dlls/amd_ags_x64/amd_ags.h | 409 +++++++++++++++++++++++----- - dlls/amd_ags_x64/amd_ags_x64.spec | 3 + - dlls/amd_ags_x64/amd_ags_x64_main.c | 137 ++++++++-- - 3 files changed, 468 insertions(+), 81 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index 0656e3fbbb3..af9c48c1dd5 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -34,6 +34,20 @@ - /// \endinternal - /// - /// --------------------------------------- -+/// What's new in AGS 6.0 since version 5.4.2 -+/// --------------------------------------- -+/// AGS 6.0 includes the following updates: -+/// * DX12 ray tracing hit token for RDNA2 hardware. -+/// * Shader intrinsic that exposes ReadLaneAt in DX12. -+/// * Shader intrinsics that expose explicit float conversions in DX12. -+/// * Refactored and revised API to minimize user error. -+/// * Added agsGetVersionNumber. -+/// * Detection for external GPUs. -+/// * Detection of RDNA2 architecture. -+/// * Grouped the more established intrinsics together into per year support. -+/// * Function pointer typedefs for the API -+/// -+/// --------------------------------------- - /// What's new in AGS 5.4.2 since version 5.4.1 - /// --------------------------------------- - /// AGS 5.4.2 includes the following updates: -@@ -128,16 +142,16 @@ - /// * Include the amd_ags.h header file from your source code. - /// * Include the AGS hlsl files if you are using the shader intrinsics. - /// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS. --/// * On game initialization, call \ref agsInit passing in the address of the context. On success, this function will return a valid context pointer. -+/// * On game initialization, call \ref agsInitialize passing in the address of the context. On success, this function will return a valid context pointer. - /// --/// Don't forget to cleanup AGS by calling \ref agsDeInit when the app exits, after the device has been destroyed. -+/// Don't forget to cleanup AGS by calling \ref agsDeInitialize when the app exits, after the device has been destroyed. - - #ifndef AMD_AGS_H - #define AMD_AGS_H - --#define AMD_AGS_VERSION_MAJOR 5 ///< AGS major version --#define AMD_AGS_VERSION_MINOR 4 ///< AGS minor version --#define AMD_AGS_VERSION_PATCH 2 ///< AGS patch version -+#define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version -+#define AMD_AGS_VERSION_MINOR 0 ///< AGS minor version -+#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version - - #ifdef __cplusplus - extern "C" { -@@ -151,14 +165,17 @@ extern "C" { - #define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version - /// @} - --// Forward declaration of D3D11 types -+// Forward declaration of D3D and DXGI types - struct IDXGIAdapter; -+struct IDXGISwapChain; -+struct DXGI_SWAP_CHAIN_DESC; - enum D3D_DRIVER_TYPE; - enum D3D_FEATURE_LEVEL; --struct DXGI_SWAP_CHAIN_DESC; -+ enum D3D_PRIMITIVE_TOPOLOGY; -+ -+// Forward declaration of D3D11 types - struct ID3D11Device; - struct ID3D11DeviceContext; --struct IDXGISwapChain; - struct ID3D11Resource; - struct ID3D11Buffer; - struct ID3D11Texture1D; -@@ -253,14 +270,6 @@ typedef enum AGSDriverExtensionDX12 - /// The space id for DirectX12 intrinsic support - const unsigned int AGS_DX12_SHADER_INSTRINSICS_SPACE_ID = 0x7FFF0ADE; // 2147420894 - -- --/// Additional topologies supported via extensions --typedef enum AGSPrimitiveTopology --{ -- AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, ///< Quad list -- AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 ///< Screen rect list --} AGSPrimitiveTopology; -- - /// The display flags describing various properties of the display. - typedef enum AGSDisplayFlags - { -@@ -282,7 +291,7 @@ typedef enum AGSDisplaySettingsFlags - - /// @} - --typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInit -+typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInitialize - - /// The rectangle struct used by AGS. - typedef struct AGSRect -@@ -293,25 +302,64 @@ typedef struct AGSRect - int height; ///< Height of rectangle - } AGSRect; - --/// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects --typedef struct AGSClipRect -+/// The display info struct used to describe a display enumerated by AGS -+typedef struct AGSDisplayInfo_511 - { -- /// The inclusion mode for the rect -- enum -- { -- ClipRectIncluded = 0, ///< Include the rect -- ClipRectExcluded = 1 ///< Exclude the rect -- } mode; ; ///< Include/exclude rect region -- AGSRect rect; ///< The rect to include/exclude --} AGSClipRect; -+ char name[ 256 ]; ///< The name of the display -+ char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName -+ -+ unsigned int displayFlags; ///< Bitfield of \ref AGSDisplayFlags -+ -+ int maxResolutionX; ///< The maximum supported resolution of the unrotated display -+ int maxResolutionY; ///< The maximum supported resolution of the unrotated display -+ float maxRefreshRate; ///< The maximum supported refresh rate of the display -+ -+ AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation -+ AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will -+ ///< be the sub region in the Eyefinity single large surface (SLS) -+ float currentRefreshRate; ///< The current refresh rate -+ -+ int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group -+ int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group -+ -+ double chromaticityRedX; ///< Red display primary X coord -+ double chromaticityRedY; ///< Red display primary Y coord -+ -+ double chromaticityGreenX; ///< Green display primary X coord -+ double chromaticityGreenY; ///< Green display primary Y coord -+ -+ double chromaticityBlueX; ///< Blue display primary X coord -+ double chromaticityBlueY; ///< Blue display primary Y coord -+ -+ double chromaticityWhitePointX; ///< White point X coord -+ double chromaticityWhitePointY; ///< White point Y coord -+ -+ double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1 -+ double screenSpecularReflectance; ///< Percentage expressed between 0 - 1 -+ -+ double minLuminance; ///< The minimum luminance of the display in nits -+ double maxLuminance; ///< The maximum luminance of the display in nits -+ double avgLuminance; ///< The average luminance of the display in nits -+ -+ int logicalDisplayIndex; ///< The internally used index of this display -+ int adlAdapterIndex; ///< The internally used ADL adapter index -+} AGSDisplayInfo_511; - - /// The display info struct used to describe a display enumerated by AGS --typedef struct AGSDisplayInfo -+typedef struct AGSDisplayInfo_600 - { - char name[ 256 ]; ///< The name of the display - char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName - -- unsigned int displayFlags; ///< Bitfield of \ref AGSDisplayFlags -+ unsigned int isPrimaryDisplay : 1; ///< Whether this display is marked as the primary display -+ unsigned int HDR10 : 1; ///< HDR10 is supported on this display -+ unsigned int dolbyVision : 1; ///< Dolby Vision is supported on this display -+ unsigned int freesync : 1; ///< Freesync is supported on this display -+ unsigned int freesyncHDR : 1; ///< Freesync HDR is supported on this display -+ unsigned int eyefinityInGroup : 1; ///< The display is part of the Eyefinity group -+ unsigned int eyefinityPreferredDisplay : 1; ///< The display is the preferred display in the Eyefinity group for displaying the UI -+ unsigned int eyefinityInPortraitMode : 1; ///< The display is in the Eyefinity group but in portrait mode -+ unsigned int reservedPadding : 24; ///< Reserved for future use - - int maxResolutionX; ///< The maximum supported resolution of the unrotated display - int maxResolutionY; ///< The maximum supported resolution of the unrotated display -@@ -346,7 +394,8 @@ typedef struct AGSDisplayInfo - - int logicalDisplayIndex; ///< The internally used index of this display - int adlAdapterIndex; ///< The internally used ADL adapter index --} AGSDisplayInfo; -+ int reserved; ///< reserved field -+} AGSDisplayInfo_600; - - /// The architecture version - typedef enum ArchitectureVersion -@@ -367,6 +416,7 @@ typedef enum AsicFamily - AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris. - AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU). - AsicFamily_RDNA, ///< AMD RDNA architecture -+ AsicFamily_RDNA2, ///< AMD RDNA2 architecture - - AsicFamily_Count ///< Number of enumerated ASIC families - } AsicFamily; -@@ -389,7 +439,7 @@ typedef struct AGSDeviceInfo_511 - long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. - - int numDisplays; ///< The number of active displays found to be attached to this adapter. -- AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. - - int eyefinityEnabled; ///< Indicates if Eyefinity is active - int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -@@ -421,7 +471,7 @@ typedef struct AGSDeviceInfo_520 - long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. - - int numDisplays; ///< The number of active displays found to be attached to this adapter. -- AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. - - int eyefinityEnabled; ///< Indicates if Eyefinity is active - int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -@@ -458,7 +508,7 @@ typedef struct AGSDeviceInfo_540 - ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. - - int numDisplays; ///< The number of active displays found to be attached to this adapter. -- AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. - - int eyefinityEnabled; ///< Indicates if Eyefinity is active - int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -@@ -493,7 +543,7 @@ typedef struct AGSDeviceInfo_541 - long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. - - int numDisplays; ///< The number of active displays found to be attached to this adapter. -- AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. - - int eyefinityEnabled; ///< Indicates if Eyefinity is active - int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -@@ -530,7 +580,7 @@ typedef struct AGSDeviceInfo_542 - ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. - - int numDisplays; ///< The number of active displays found to be attached to this adapter. -- AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ AGSDisplayInfo_511* displays; ///< List of displays allocated by AGS to be numDisplays in length. - - int eyefinityEnabled; ///< Indicates if Eyefinity is active - int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -@@ -542,6 +592,47 @@ typedef struct AGSDeviceInfo_542 - int adlAdapterIndex; ///< Internally used index into the ADL list of adapters - } AGSDeviceInfo_542; - -+/// The device info struct used to describe a physical GPU enumerated by AGS -+typedef struct AGSDeviceInfo_600 -+{ -+ const char* adapterString; ///< The adapter name string -+ AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware -+ unsigned int isAPU : 1; ///< Whether this device is an APU -+ unsigned int isPrimaryDevice : 1; ///< Whether this device is marked as the primary device -+ unsigned int isExternal :1; ///< Whether this device is a detachable, external device -+ unsigned int reservedPadding : 29; ///< Reserved for future use -+ -+ int vendorId; ///< The vendor id -+ int deviceId; ///< The device id -+ int revisionId; ///< The revision id -+ -+ int numCUs; ///< Number of compute units -+ int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards. -+ -+ int numROPs; ///< Number of ROPs -+ int coreClock; ///< Core clock speed at 100% power in MHz -+ int memoryClock; ///< Memory clock speed at 100% power in MHz -+ int memoryBandwidth; ///< Memory bandwidth in MB/s -+ float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD -+ -+ unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware. -+ unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs -+ ///< as the reported local memory will only be a small fraction of the total memory available to the GPU. -+ -+ int numDisplays; ///< The number of active displays found to be attached to this adapter. -+ AGSDisplayInfo_600* displays; ///< List of displays allocated by AGS to be numDisplays in length. -+ -+ int eyefinityEnabled; ///< Indicates if Eyefinity is active -+ int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface. -+ int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface. -+ int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface. -+ int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled. -+ -+ int adlAdapterIndex; ///< Internally used index into the ADL list of adapters -+ int reserved; ///< reserved field -+} AGSDeviceInfo_600; -+ - struct AGSDeviceInfo; - - /// \defgroup general General API functions -@@ -552,7 +643,7 @@ typedef void* (__stdcall *AGS_ALLOC_CALLBACK_511)( int allocationSize ); ///< - typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype - typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype - --/// The configuration options that can be passed in to \ref agsInit -+/// The configuration options that can be passed in to \ref agsInititalize - typedef struct AGSConfiguration_511 - { - AGS_ALLOC_CALLBACK_511 allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used -@@ -571,8 +662,8 @@ typedef union AGSConfiguration - AGSConfiguration_520 agsConfiguration520; - } AGSConfiguration; - --/// The top level GPU information returned from \ref agsInit --typedef struct AGSGPUInfo -+/// The top level GPU information returned from \ref agsInitialize -+typedef struct AGSGPUInfo_511 - { - int agsVersionMajor; ///< Major field of Major.Minor.Patch AGS version number - int agsVersionMinor; ///< Minor field of Major.Minor.Patch AGS version number -@@ -584,24 +675,35 @@ typedef struct AGSGPUInfo - - int numDevices; ///< Number of GPUs in the system - struct AGSDeviceInfo* devices; ///< List of GPUs in the system --} AGSGPUInfo; -+} AGSGPUInfo_511; - --/// The struct to specify the display settings to the driver. --typedef struct AGSDisplaySettings -+/// The top level GPU information returned from \ref agsInit -+typedef struct AGSGPUInfo_600 - { -- /// The display mode -- enum -- { -- Mode_SDR, ///< SDR mode -- Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. -- Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. -- Mode_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. -- // Mode_FreesyncHDR_Gamma22 ADDED IN 5.3.0 -- Mode_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. -- Mode_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain -+ const char* driverVersion; ///< The AMD driver package version -+ const char* radeonSoftwareVersion; ///< The Radeon Software Version -+ -+ int numDevices; ///< Number of GPUs in the system -+ struct AGSDeviceInfo* devices; ///< List of GPUs in the system -+} AGSGPUInfo_600; - -- Mode_Count ///< Number of enumerated display modes -- } mode; ///< The display mode to set the display into -+/// The display mode -+typedef enum AGSDisplaySettings_Mode -+{ -+ Mode_SDR, ///< SDR mode -+ Mode_HDR10_PQ, ///< HDR10 PQ encoding, requiring a 1010102 UNORM swapchain and PQ encoding in the output shader. -+ Mode_HDR10_scRGB, ///< HDR10 scRGB, requiring an FP16 swapchain. Values of 1.0 == 80 nits, 125.0 == 10000 nits. -+ Mode_FreesyncHDR_scRGB, ///< Freesync HDR scRGB, requiring an FP16 swapchain. A value of 1.0 == 80 nits. -+ Mode_FreesyncHDR_Gamma22, ///< Freesync HDR Gamma 2.2, requiring a 1010102 UNORM swapchain. The output needs to be encoded to gamma 2.2. -+ Mode_DolbyVision, ///< Dolby Vision, requiring an 8888 UNORM swapchain -+ -+ Mode_Count ///< Number of enumerated display modes -+} AGSDisplaySettings_Mode; -+ -+/// The struct to specify the display settings to the driver. -+typedef struct AGSDisplaySettings_511 -+{ -+ AGSDisplaySettings_Mode mode; ///< The display mode to set the display into - - double chromaticityRedX; ///< Red display primary X coord - double chromaticityRedY; ///< Red display primary Y coord -@@ -623,6 +725,39 @@ typedef struct AGSDisplaySettings - - // ADDED IN 5.2.0 - int flags; ///< Bitfield of ::AGSDisplaySettingsFlags -+} AGSDisplaySettings_511; -+ -+/// The struct to specify the display settings to the driver. -+typedef struct AGSDisplaySettings_600 -+{ -+ AGSDisplaySettings_Mode mode; ///< The display mode to set the display into -+ -+ double chromaticityRedX; ///< Red display primary X coord -+ double chromaticityRedY; ///< Red display primary Y coord -+ -+ double chromaticityGreenX; ///< Green display primary X coord -+ double chromaticityGreenY; ///< Green display primary Y coord -+ -+ double chromaticityBlueX; ///< Blue display primary X coord -+ double chromaticityBlueY; ///< Blue display primary Y coord -+ -+ double chromaticityWhitePointX; ///< White point X coord -+ double chromaticityWhitePointY; ///< White point Y coord -+ -+ double minLuminance; ///< The minimum scene luminance in nits -+ double maxLuminance; ///< The maximum scene luminance in nits -+ -+ double maxContentLightLevel; ///< The maximum content light level in nits (MaxCLL) -+ double maxFrameAverageLightLevel; ///< The maximum frame average light level in nits (MaxFALL) -+ -+ unsigned int disableLocalDimming : 1; ///< Disables local dimming if possible -+ unsigned int reservedPadding : 31; ///< Reserved -+} AGSDisplaySettings_600; -+ -+typedef union AGSDisplaySettings -+{ -+ AGSDisplaySettings_511 agsDisplaySettings511; -+ AGSDisplaySettings_600 agsDisplaySettings600; - } AGSDisplaySettings; - - /// The result returned from \ref agsCheckDriverVersion -@@ -642,6 +777,12 @@ typedef enum AGSDriverVersionResult - /// - AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired ); - -+/// -+/// Function to return the AGS version number. -+/// -+/// \return The version number made using AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ). -+/// -+AMD_AGS_API int agsGetVersionNumber( void ); - - /// - /// Function used to initialize the AGS library. -@@ -656,7 +797,23 @@ AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoft - /// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration. - /// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system. - /// --AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* config, AGSGPUInfo* gpuInfo ); -+AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* config, AGSGPUInfo_511* gpuInfo ); -+ -+/// -+/// Function used to initialize the AGS library. -+/// agsVersion must be specified as AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ) or the call will return \ref AGS_INVALID_ARGS. -+/// Must be called prior to any of the subsequent AGS API calls. -+/// Must be called prior to ID3D11Device or ID3D12Device creation. -+/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInitialize if there is an AMD GPU present. -+/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system. -+/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20. -+/// -+/// \param [in] agsVersion The API version specified using the \ref AGS_MAKE_VERSION macro. If this does not match the version in the binary this initialization call will fail. -+/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration. -+/// \param [out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls. -+/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system. -+/// -+AMD_AGS_API AGSReturnCode agsInitialize( int agsVersion, const AGSConfiguration* config, AGSContext** context, AGSGPUInfo_600* gpuInfo ); - - /// - /// Function used to clean up the AGS library. -@@ -665,6 +822,13 @@ AMD_AGS_API AGSReturnCode agsInit( AGSContext** context, const AGSConfiguration* - /// - AMD_AGS_API AGSReturnCode agsDeInit( AGSContext* context ); - -+/// -+/// Function used to clean up the AGS library. -+/// -+/// \param [in] context Pointer to a context. This function will deallocate the context from the heap. -+/// -+AMD_AGS_API AGSReturnCode agsDeInitialize( AGSContext* context ); -+ - /// - /// Function used to query the number of GPUs used for Crossfire acceleration. - /// This may be different from the total number of GPUs present in the system. -@@ -685,7 +849,7 @@ AMD_AGS_API AGSReturnCode agsGetCrossfireGPUCount( AGSContext* context, int* num - /// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain. - /// \note Dolby Vision requires a 8888 UNORM swapchain. - /// --/// \param [in] context Pointer to a context. This is generated by \ref agsInit -+/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize - /// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices. - /// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays. - /// \param [in] settings Pointer to the display settings to use. -@@ -726,6 +890,29 @@ typedef struct AGSDX12ExtensionParams - typedef struct AGSDX12ReturnedParams - { - ID3D12Device* pDevice; ///< The newly created device -+ /* -+ This was changed to a struct in 6.0.0+ but it's still the size of an unsigned int. -+ Ignoring this change for now. -+ -+ typedef struct ExtensionsSupported /// Extensions for DX12 -+ { -+ unsigned int intrinsics16 : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. ReadFirstLane, ReadLane, LaneID, Swizzle, Ballot, MBCount, Med3, Barycentrics -+ unsigned int intrinsics17 : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. WaveReduce, WaveScan -+ unsigned int userMarkers : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. -+ unsigned int appRegistration : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. -+ unsigned int UAVBindSlot : 1; ///< Supported in Radeon Software Version 19.5.1 onwards. -+ unsigned int intrinsics19 : 1; ///< Supported in Radeon Software Version 19.12.2 onwards. DrawIndex, AtomicU64 -+ unsigned int baseVertex : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. -+ unsigned int baseInstance : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. -+ unsigned int getWaveSize : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. -+ unsigned int floatConversion : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. -+ unsigned int readLaneAt : 1; ///< Supported in Radeon Software Version 20.11.1 onwards. -+ unsigned int rayHitToken : 1; ///< Supported in Radeon Software Version 20.11.1 onwards. -+ unsigned int padding : 20; ///< Reserved -+ } ExtensionsSupported; -+ ExtensionsSupported extensionsSupported; ///< List of supported extensions -+ */ -+ - unsigned int extensionsSupported; ///< Bit mask that \ref agsDriverExtensionsDX12_CreateDevice will fill in to indicate which extensions are supported. See \ref AGSDriverExtensionDX12 - } AGSDX12ReturnedParams; - -@@ -747,11 +934,11 @@ typedef struct AGSDX12ReturnedParams - /// range[ 0 ].Init( D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 1, 0, AGS_DX12_SHADER_INSTRINSICS_SPACE_ID ); // u0 at driver-reserved space id - /// \endcode - /// --/// Newer drivers also support a user-specified slot in which case the register space id is assumed to be 0. It is important that the \ref AGS_DX12_EXTENSION_INTRINSIC_UAV_BIND_SLOT bit is set -+/// Newer drivers also support a user-specified slot in which case the register space id is assumed to be 0. It is important that the \ref AGSDX12ReturnedParams::ExtensionsSupported::UAVBindSlot bit is set. - /// to ensure the driver can support this. If not, then u0 and \ref AGS_DX12_SHADER_INSTRINSICS_SPACE_ID must be used. - /// If the driver does support this feature and a non zero slot is required, then the HLSL must also define AMD_EXT_SHADER_INTRINSIC_UAV_OVERRIDE as the matching slot value. - /// --/// \param [in] context Pointer to a context. This is generated by \ref agsInit -+/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize - /// \param [in] creationParams Pointer to the struct to specify the existing DX12 device creation parameters. - /// \param [in] extensionParams Optional pointer to the struct to specify DX12 additional device creation parameters. - /// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. -@@ -777,7 +964,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DestroyDevice( AGSContext* con - /// * The intrinsic instructions require a 5.1 shader model. - /// * The Root Signature will need to use an extra resource and sampler. These are not real resources/samplers, they are just used to encode the intrinsic instruction. - /// --/// \param [in] context Pointer to a context. This is generated by \ref agsInit -+/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize - /// \param [in] device The D3D12 device. - /// \param [out] extensionsSupported Pointer to a bit mask that this function will fill in to indicate which extensions are supported. See ::AGSDriverExtensionDX12 - /// -@@ -799,7 +986,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX12_DeInit( AGSContext* context ); - - /// - /// Function used to push an AMD user marker onto the command list. --/// This is only has an effect if \ref AGS_DX12_EXTENSION_USER_MARKERS is present in the extensionsSupported bitfield of \ref agsDriverExtensionsDX12_CreateDevice -+/// This is only has an effect if \ref AGSDX12ReturnedParams::ExtensionsSupported::userMarkers is present. - /// Supported in Radeon Software Version 17.9.1 onwards. - /// - /// \param [in] context Pointer to a context. -@@ -912,10 +1099,47 @@ typedef struct AGSDX11ReturnedParams_520 - void* breadcrumbBuffer; ///< The CPU buffer returned if the initialization of the breadcrumb was successful. - } AGSDX11ReturnedParams_520; - -+typedef struct AGSDX11ExtensionsSupported_600 /// Extensions for DX11 -+{ -+ unsigned int quadList : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. -+ unsigned int screenRectList : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. -+ unsigned int uavOverlap : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. -+ unsigned int depthBoundsTest : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. -+ unsigned int multiDrawIndirect : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. -+ unsigned int multiDrawIndirectCountIndirect : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. -+ unsigned int crossfireAPI : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. -+ unsigned int createShaderControls : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. -+ unsigned int intrinsics16 : 1; ///< Supported in Radeon Software Version 16.9.2 onwards. ReadFirstLane, ReadLane, LaneID, Swizzle, Ballot, MBCount, Med3, Barycentrics -+ unsigned int multiView : 1; ///< Supported in Radeon Software Version 16.12.1 onwards. -+ unsigned int intrinsics17 : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. WaveReduce, WaveScan -+ unsigned int appRegistration : 1; ///< Supported in Radeon Software Version 17.9.1 onwards. -+ unsigned int breadcrumbMarkers : 1; ///< Supported in Radeon Software Version 17.11.1 onwards. -+ unsigned int MDIDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. -+ unsigned int UAVOverlapDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. -+ unsigned int depthBoundsDeferredContexts : 1; ///< Supported in Radeon Software Version 18.8.1 onwards. -+ unsigned int intrinsics19 : 1; ///< Supported in Radeon Software Version 19.12.2 onwards. DrawIndex, AtomicU64 -+ unsigned int getWaveSize : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. -+ unsigned int baseVertex : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. -+ unsigned int baseInstance : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. -+ unsigned int padding : 12; ///< Reserved -+} AGSDX11ExtensionsSupported_600; -+ -+typedef struct AGSDX11ReturnedParams_600 -+{ -+ ID3D11Device* pDevice; ///< The newly created device -+ ID3D11DeviceContext* pImmediateContext; ///< The newly created immediate device context -+ IDXGISwapChain* pSwapChain; ///< The newly created swap chain. This is only created if a valid pSwapChainDesc is supplied in AGSDX11DeviceCreationParams. -+ D3D_FEATURE_LEVEL featureLevel; ///< The feature level supported by the newly created device -+ AGSDX11ExtensionsSupported_600 extensionsSupported; ///< List of supported extensions -+ unsigned int crossfireGPUCount; ///< The number of GPUs that are active for this app -+ void* breadcrumbBuffer; ///< The CPU buffer returned if the initialization of the breadcrumb was successful -+} AGSDX11ReturnedParams_600; -+ - typedef union AGSDX11ReturnedParams - { - AGSDX11ReturnedParams_511 agsDX11ReturnedParams511; - AGSDX11ReturnedParams_520 agsDX11ReturnedParams520; -+ AGSDX11ReturnedParams_600 agsDX11ReturnedParams600; - } AGSDX11ReturnedParams; - - /// -@@ -925,7 +1149,7 @@ typedef union AGSDX11ReturnedParams - /// * The shader compiler should not use the D3DCOMPILE_SKIP_OPTIMIZATION (/Od) option, otherwise it will not work. - /// * The shader compiler needs D3DCOMPILE_ENABLE_STRICTNESS (/Ges) enabled. - /// --/// \param [in] context Pointer to a context. This is generated by \ref agsInit -+/// \param [in] context Pointer to a context. This is generated by \ref agsInititalize - /// \param [in] creationParams Pointer to the struct to specify the existing DX11 device creation parameters. - /// \param [in] extensionParams Optional pointer to the struct to specify DX11 additional device creation parameters. - /// \param [out] returnedParams Pointer to struct to hold all the returned parameters from the call. -@@ -991,7 +1215,7 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_DestroyDevice_511( AGSContext* - /// \defgroup breadcrumbs Breadcrumb API - /// API for writing top-of-pipe and bottom-of-pipe markers to help track down GPU hangs. - /// --/// The API is available if the \ref AGS_DX11_EXTENSION_BREADCRUMB_MARKERS is present in \ref AGSDX11ReturnedParams::extensionsSupported. -+/// The API is available if the \ref AGSDX11ReturnedParams::ExtensionsSupported::breadcrumbMarkers is present. - /// - /// To use the API, a non zero value needs to be specificed in \ref AGSDX11ExtensionParams::numBreadcrumbMarkers. This enables the API (if available) and allocates a system memory buffer - /// which is returned to the user in \ref AGSDX11ReturnedParams::breadcrumbBuffer. -@@ -1197,6 +1421,13 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_WriteBreadcrumb( AGSContext* c - /// API for primitive topologies - /// @{ - -+/// Additional topologies supported via extensions -+typedef enum AGSPrimitiveTopology -+{ -+ AGS_PRIMITIVE_TOPOLOGY_QUADLIST = 7, ///< Quad list -+ AGS_PRIMITIVE_TOPOLOGY_SCREENRECTLIST = 9 ///< Screen rect list -+} AGSPrimitiveTopology; -+ - /// - /// Function used to set the primitive topology. If you are using any of the extended topology types, then this function should - /// be called to set ALL topology types. -@@ -1447,6 +1678,22 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_SetViewBroadcastMasks( AGSCont - /// - AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_GetMaxClipRects( AGSContext* context, unsigned int* maxRectCount ); - -+/// The inclusion mode for the rect -+typedef enum AGSClipRect_Mode -+{ -+ ClipRectIncluded = 0, ///< Include the rect -+ ClipRectExcluded = 1 ///< Exclude the rect -+} AGSClipRect_Mode; -+ -+/// The clip rectangle struct used by \ref agsDriverExtensionsDX11_SetClipRects -+typedef struct AGSClipRect -+{ -+ AGSClipRect_Mode mode; ///< Include/exclude rect region -+ AGSRect rect; ///< The rect to include/exclude -+} AGSClipRect; -+ -+ -+ - /// - /// Function sets clip rectangles. - /// -@@ -1563,6 +1810,46 @@ AMD_AGS_API AGSReturnCode agsDriverExtensionsDX11_NotifyResourceEndAllAccess( AG - - /// @} - -+/// \defgroup typedefs Function pointer typedefs -+/// List of function pointer typedefs for the API -+/// @{ -+ -+typedef AMD_AGS_API AGSDriverVersionResult (*AGS_CHECKDRIVERVERSION)( const char*, unsigned int ); ///< \ref agsCheckDriverVersion -+typedef AMD_AGS_API int (*AGS_GETVERSIONNUMBER)( void ); ///< \ref agsGetVersionNumber -+typedef AMD_AGS_API AGSReturnCode (*AGS_INITIALIZE)( int, const AGSConfiguration*, AGSContext**, AGSGPUInfo_600* ); ///< \ref agsInitialize -+typedef AMD_AGS_API AGSReturnCode (*AGS_DEINITIALIZE)( AGSContext* ); ///< \ref agsDeInitialize -+typedef AMD_AGS_API AGSReturnCode (*AGS_SETDISPLAYMODE)( AGSContext*, int, int, const AGSDisplaySettings* ); ///< \ref agsSetDisplayMode -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_CREATEDEVICE)( AGSContext*, const AGSDX12DeviceCreationParams*, const AGSDX12ExtensionParams*, AGSDX12ReturnedParams* ); ///< \ref agsDriverExtensionsDX12_CreateDevice -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_DESTROYDEVICE)( AGSContext*, ID3D12Device*, unsigned int* ); ///< \ref agsDriverExtensionsDX12_DestroyDevice -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_PUSHMARKER)( AGSContext*, ID3D12GraphicsCommandList*, const char* ); ///< \ref agsDriverExtensionsDX12_PushMarker -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_POPMARKER)( AGSContext*, ID3D12GraphicsCommandList* ); ///< \ref agsDriverExtensionsDX12_PopMarker -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX12_SETMARKER)( AGSContext*, ID3D12GraphicsCommandList*, const char* ); ///< \ref agsDriverExtensionsDX12_SetMarker -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATEDEVICE)( AGSContext*, const AGSDX11DeviceCreationParams*, const AGSDX11ExtensionParams*, AGSDX11ReturnedParams* ); ///< \ref agsDriverExtensionsDX11_CreateDevice -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_DESTROYDEVICE)( AGSContext*, ID3D11Device*, unsigned int*, ID3D11DeviceContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_DestroyDevice -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_WRITEBREADCRUMB)( AGSContext*, const AGSBreadcrumbMarker* ); ///< \ref agsDriverExtensionsDX11_WriteBreadcrumb -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_IASETPRIMITIVETOPOLOGY)( AGSContext*, enum D3D_PRIMITIVE_TOPOLOGY ); ///< \ref agsDriverExtensionsDX11_IASetPrimitiveTopology -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_BEGINUAVOVERLAP)( AGSContext*, ID3D11DeviceContext* ); ///< \ref agsDriverExtensionsDX11_BeginUAVOverlap -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_ENDUAVOVERLAP)( AGSContext*, ID3D11DeviceContext* ); ///< \ref agsDriverExtensionsDX11_EndUAVOverlap -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETDEPTHBOUNDS)( AGSContext*, ID3D11DeviceContext*, bool, float, float ); ///< \ref agsDriverExtensionsDX11_SetDepthBounds -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINSTANCEDINDIRECT)( AGSContext*, ID3D11DeviceContext*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawInstancedIndirect -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINDEXEDINSTANCEDINDIRECT)( AGSContext*, ID3D11DeviceContext*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINSTANCEDINDIRECTCOUNTINDIRECT)( AGSContext*, ID3D11DeviceContext*, ID3D11Buffer*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawInstancedIndirectCountIndirect -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_MULTIDRAWINDEXEDINSTANCEDINDIRECTCOUNTINDIRECT)( AGSContext*, ID3D11DeviceContext*, ID3D11Buffer*, unsigned int, ID3D11Buffer*, unsigned int, unsigned int ); ///< \ref agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETMAXASYNCCOMPILETHREADCOUNT)( AGSContext*, unsigned int ); ///< \ref agsDriverExtensionsDX11_SetMaxAsyncCompileThreadCount -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NUMPENDINGASYNCOMPILEJOBS)( AGSContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_NumPendingAsyncCompileJobs -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETDISKSHADERCACHEENABLED)( AGSContext*, int ); ///< \ref agsDriverExtensionsDX11_SetDiskShaderCacheEnabled -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETVIEWBROADCASTMASKS)( AGSContext*, unsigned long long, unsigned long long, int ); ///< \ref agsDriverExtensionsDX11_SetViewBroadcastMasks -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_GETMAXCLIPRECTS)( AGSContext*, unsigned int* ); ///< \ref agsDriverExtensionsDX11_GetMaxClipRects -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_SETCLIPRECTS)( AGSContext*, unsigned int, const AGSClipRect* ); ///< \ref agsDriverExtensionsDX11_SetClipRects -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATEBUFFER)( AGSContext*, const D3D11_BUFFER_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Buffer**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateBuffer -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE1D)( AGSContext*, const D3D11_TEXTURE1D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture1D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture1D -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE2D)( AGSContext*, const D3D11_TEXTURE2D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture2D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture2D -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_CREATETEXTURE3D)( AGSContext*, const D3D11_TEXTURE3D_DESC*, const D3D11_SUBRESOURCE_DATA*, ID3D11Texture3D**, AGSAfrTransferType, AGSAfrTransferEngine ); ///< \ref agsDriverExtensionsDX11_CreateTexture3D -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEENDWRITES)( AGSContext*, ID3D11Resource*, const D3D11_RECT*, const unsigned int*, unsigned int ); ///< \ref agsDriverExtensionsDX11_NotifyResourceEndWrites -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEBEGINALLACCESS)( AGSContext*, ID3D11Resource* ); ///< \ref agsDriverExtensionsDX11_NotifyResourceBeginAllAccess -+typedef AMD_AGS_API AGSReturnCode (*AGS_DRIVEREXTENSIONSDX11_NOTIFYRESOURCEENDALLACCESS)( AGSContext*, ID3D11Resource* ); ///< \ref agsDriverExtensionsDX11_NotifyResourceEndAllAccess -+/// @} -+ - #ifdef __cplusplus - } // extern "C" - #endif -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -index ae825462f28..562c4103343 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64.spec -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -1,4 +1,5 @@ - @ stdcall agsDeInit(ptr) -+@ stdcall agsDeInitialize(ptr) - @ stdcall agsCheckDriverVersion(ptr long) - @ stub agsDriverExtensionsDX11_BeginUAVOverlap - @ stub agsDriverExtensionsDX11_CreateBuffer -@@ -38,5 +39,7 @@ - @ stub agsDriverExtensionsDX12_PushMarker - @ stub agsDriverExtensionsDX12_SetMarker - @ stdcall agsGetCrossfireGPUCount(ptr ptr) -+@ stdcall agsGetVersionNumber() - @ stdcall agsInit(ptr ptr ptr) -+@ stdcall agsInitialize(long ptr ptr ptr) - @ stub agsSetDisplayMode -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 35de799430d..b7b85b7f7a4 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -26,6 +26,7 @@ enum amd_ags_version - AMD_AGS_VERSION_5_4_0, - AMD_AGS_VERSION_5_4_1, - AMD_AGS_VERSION_5_4_2, -+ AMD_AGS_VERSION_6_0_0, - - AMD_AGS_VERSION_COUNT - }; -@@ -46,17 +47,21 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = - {5, 4, 0, sizeof(AGSDeviceInfo_540)}, - {5, 4, 1, sizeof(AGSDeviceInfo_541)}, - {5, 4, 2, sizeof(AGSDeviceInfo_542)}, -+ {6, 0, 0, sizeof(AGSDeviceInfo_600)}, - }; - - #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ - offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ -- offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name)}} -+ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name)}} - #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ - offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ -- -1, -1}} -+ -1, -1, -1}} - #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ - -1, -1, offsetof(AGSDeviceInfo_540, name), \ -- offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name)}} -+ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name)}} -+#define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ -+ offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ -+ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1}} - - #define DEVICE_FIELD_adapterString 0 - #define DEVICE_FIELD_architectureVersion 1 -@@ -80,7 +85,7 @@ device_struct_fields[] = - DEF_FIELD_540_UP(asicFamily), - DEF_FIELD(vendorId), - DEF_FIELD(deviceId), -- DEF_FIELD(isPrimaryDevice), -+ DEF_FIELD_600_BELOW(isPrimaryDevice), - DEF_FIELD(localMemoryInBytes), - DEF_FIELD(numDisplays), - DEF_FIELD(displays), -@@ -263,20 +268,20 @@ static enum amd_ags_version determine_ags_version(void) - return ret; - } - --struct monitor_enum_context -+struct monitor_enum_context_600 - { - const char *adapter_name; -- AGSDisplayInfo **ret_displays; -+ AGSDisplayInfo_600 **ret_displays; - int *ret_display_count; - }; - --static BOOL WINAPI monitor_enum_proc(HMONITOR hmonitor, HDC hdc, RECT *rect, LPARAM context) -+static BOOL WINAPI monitor_enum_proc_600(HMONITOR hmonitor, HDC hdc, RECT *rect, LPARAM context) - { -- struct monitor_enum_context *c = (struct monitor_enum_context *)context; -+ struct monitor_enum_context_600 *c = (struct monitor_enum_context_600 *)context; - MONITORINFOEXA monitor_info; -- AGSDisplayInfo *new_alloc; -+ AGSDisplayInfo_600 *new_alloc; - DISPLAY_DEVICEA device; -- AGSDisplayInfo *info; -+ AGSDisplayInfo_600 *info; - unsigned int i, mode; - DEVMODEA dev_mode; - -@@ -321,7 +326,7 @@ static BOOL WINAPI monitor_enum_proc(HMONITOR hmonitor, HDC hdc, RECT *rect, LPA - strcpy(info->name, "Unknown"); - } - if (monitor_info.dwFlags & MONITORINFOF_PRIMARY) -- info->displayFlags |= AGS_DISPLAYFLAG_PRIMARY_DISPLAY; -+ info->isPrimaryDisplay = 1; - - mode = 0; - memset(&dev_mode, 0, sizeof(dev_mode)); -@@ -360,9 +365,9 @@ static BOOL WINAPI monitor_enum_proc(HMONITOR hmonitor, HDC hdc, RECT *rect, LPA - return TRUE; - } - --static void init_device_displays(const char *adapter_name, AGSDisplayInfo **ret_displays, int *ret_display_count) -+static void init_device_displays_600(const char *adapter_name, AGSDisplayInfo_600 **ret_displays, int *ret_display_count) - { -- struct monitor_enum_context context; -+ struct monitor_enum_context_600 context; - - TRACE("adapter_name %s.\n", debugstr_a(adapter_name)); - -@@ -370,9 +375,32 @@ static void init_device_displays(const char *adapter_name, AGSDisplayInfo **ret_ - context.ret_displays = ret_displays; - context.ret_display_count = ret_display_count; - -- EnumDisplayMonitors(NULL, NULL, monitor_enum_proc, (LPARAM)&context); -+ EnumDisplayMonitors(NULL, NULL, monitor_enum_proc_600, (LPARAM)&context); -+} -+ -+static void init_device_displays_511(const char *adapter_name, AGSDisplayInfo_511 **ret_displays, int *ret_display_count) -+{ -+ AGSDisplayInfo_600 *displays = NULL; -+ int display_count = 0; -+ int i; -+ *ret_displays = NULL; -+ *ret_display_count = 0; -+ -+ init_device_displays_600(adapter_name, &displays, &display_count); -+ -+ if ((*ret_displays = heap_alloc(sizeof(**ret_displays) * display_count))) -+ { -+ for (i = 0; i < display_count; i++) -+ { -+ memcpy(&(*ret_displays)[i], &displays[i], sizeof(AGSDisplayInfo_511)); -+ } -+ *ret_display_count = display_count; -+ } -+ -+ heap_free(displays); - } - -+ - static AGSReturnCode init_ags_context(AGSContext *context) - { - AGSReturnCode ret; -@@ -427,11 +455,31 @@ static AGSReturnCode init_ags_context(AGSContext *context) - } - SET_DEVICE_FIELD(device, localMemoryInBytes, ULONG64, context->version, local_memory_size); - if (!i) -- SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); -+ { -+ if (context->version >= AMD_AGS_VERSION_6_0_0) -+ { -+ // This is a bitfield now... Nice... -+ struct AGSDeviceInfo_600 *device_600 = (struct AGSDeviceInfo_600 *)device; -+ device_600->isPrimaryDevice = 1; -+ } -+ else -+ { -+ SET_DEVICE_FIELD(device, isPrimaryDevice, int, context->version, 1); -+ } -+ } - -- init_device_displays(vk_properties->deviceName, -- GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo *, context->version), -- GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); -+ if (context->version >= AMD_AGS_VERSION_6_0_0) -+ { -+ init_device_displays_600(vk_properties->deviceName, -+ GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo_600 *, context->version), -+ GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); -+ } -+ else -+ { -+ init_device_displays_511(vk_properties->deviceName, -+ GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo_511 *, context->version), -+ GET_DEVICE_FIELD_ADDR(device, numDisplays, int, context->version)); -+ } - - device += amd_ags_info[context->version].device_size; - } -@@ -439,7 +487,7 @@ static AGSReturnCode init_ags_context(AGSContext *context) - return AGS_SUCCESS; - } - --AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *config, AGSGPUInfo *gpu_info) -+AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *config, AGSGPUInfo_511 *gpu_info) - { - struct AGSContext *object; - AGSReturnCode ret; -@@ -477,7 +525,47 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi - return AGS_SUCCESS; - } - -+AGSReturnCode WINAPI agsInitialize(int ags_version, const AGSConfiguration *config, AGSContext **context, AGSGPUInfo_600 *gpu_info) -+{ -+ struct AGSContext *object; -+ AGSReturnCode ret; -+ -+ TRACE("ags_verison %d, context %p, config %p, gpu_info %p.\n", ags_version, context, config, gpu_info); -+ -+ if (!context || !gpu_info) -+ return AGS_INVALID_ARGS; -+ -+ if (config) -+ FIXME("Ignoring config %p.\n", config); -+ -+ if (!(object = heap_alloc(sizeof(*object)))) -+ return AGS_OUT_OF_MEMORY; -+ -+ if ((ret = init_ags_context(object)) != AGS_SUCCESS) -+ { -+ heap_free(object); -+ return ret; -+ } -+ -+ memset(gpu_info, 0, sizeof(*gpu_info)); -+ gpu_info->driverVersion = "20.50.03.05-210326a-365573E-RadeonSoftwareAdrenalin2020"; -+ gpu_info->radeonSoftwareVersion = "21.3.2"; -+ gpu_info->numDevices = object->device_count; -+ gpu_info->devices = object->devices; -+ -+ TRACE("Created context %p.\n", object); -+ -+ *context = object; -+ -+ return AGS_SUCCESS; -+} -+ - AGSReturnCode WINAPI agsDeInit(AGSContext *context) -+{ -+ return agsDeInitialize(context); -+} -+ -+AGSReturnCode WINAPI agsDeInitialize(AGSContext *context) - { - unsigned int i; - BYTE *device; -@@ -491,7 +579,7 @@ AGSReturnCode WINAPI agsDeInit(AGSContext *context) - device = (BYTE *)context->devices; - for (i = 0; i < context->device_count; ++i) - { -- heap_free(GET_DEVICE_FIELD_ADDR(device, displays, AGSDisplayInfo *, context->version)); -+ heap_free(GET_DEVICE_FIELD_ADDR(device, displays, void *, context->version)); - device += amd_ags_info[context->version].device_size; - } - heap_free(context->devices); -@@ -561,6 +649,15 @@ AGSDriverVersionResult WINAPI agsCheckDriverVersion(const char* version_reported - return AGS_SOFTWAREVERSIONCHECK_OK; - } - -+int WINAPI agsGetVersionNumber(void) -+{ -+ enum amd_ags_version version = determine_ags_version(); -+ -+ TRACE("version %d.\n", version); -+ -+ return AGS_MAKE_VERSION(amd_ags_info[version].major, amd_ags_info[version].minor, amd_ags_info[version].patch); -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - TRACE("%p, %u, %p.\n", instance, reason, reserved); -From 4d7523540486ce8fb038332f795758b153429818 Mon Sep 17 00:00:00 2001 -From: Joshua Ashton -Date: Sat, 8 May 2021 05:20:08 +0100 -Subject: [PATCH] amd_ags_x64: Implement AGS 6.0.1 - -Signed-off-by: Joshua Ashton ---- - dlls/amd_ags_x64/amd_ags.h | 8 ++++---- - dlls/amd_ags_x64/amd_ags_x64_main.c | 13 +++++++++---- - 2 files changed, 13 insertions(+), 8 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags.h b/dlls/amd_ags_x64/amd_ags.h -index af9c48c1dd5..20fef455f00 100644 ---- a/dlls/amd_ags_x64/amd_ags.h -+++ b/dlls/amd_ags_x64/amd_ags.h -@@ -151,7 +151,7 @@ - - #define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version - #define AMD_AGS_VERSION_MINOR 0 ///< AGS minor version --#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version -+#define AMD_AGS_VERSION_PATCH 1 ///< AGS patch version - - #ifdef __cplusplus - extern "C" { -@@ -906,8 +906,8 @@ typedef struct AGSDX12ReturnedParams - unsigned int baseInstance : 1; ///< Supported in Radeon Software Version 20.2.1 onwards. - unsigned int getWaveSize : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. - unsigned int floatConversion : 1; ///< Supported in Radeon Software Version 20.5.1 onwards. -- unsigned int readLaneAt : 1; ///< Supported in Radeon Software Version 20.11.1 onwards. -- unsigned int rayHitToken : 1; ///< Supported in Radeon Software Version 20.11.1 onwards. -+ unsigned int readLaneAt : 1; ///< Supported in Radeon Software Version 20.11.2 onwards. -+ unsigned int rayHitToken : 1; ///< Supported in Radeon Software Version 20.11.2 onwards. - unsigned int padding : 20; ///< Reserved - } ExtensionsSupported; - ExtensionsSupported extensionsSupported; ///< List of supported extensions -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index b7b85b7f7a4..97fda0b5230 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -27,6 +27,7 @@ enum amd_ags_version - AMD_AGS_VERSION_5_4_1, - AMD_AGS_VERSION_5_4_2, - AMD_AGS_VERSION_6_0_0, -+ AMD_AGS_VERSION_6_0_1, - - AMD_AGS_VERSION_COUNT - }; -@@ -48,20 +49,24 @@ amd_ags_info[AMD_AGS_VERSION_COUNT] = - {5, 4, 1, sizeof(AGSDeviceInfo_541)}, - {5, 4, 2, sizeof(AGSDeviceInfo_542)}, - {6, 0, 0, sizeof(AGSDeviceInfo_600)}, -+ {6, 0, 1, sizeof(AGSDeviceInfo_600)}, - }; - - #define DEF_FIELD(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ - offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ -- offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name)}} -+ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ -+ offsetof(AGSDeviceInfo_600, name)}} - #define DEF_FIELD_520_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ - offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), -1, \ -- -1, -1, -1}} -+ -1, -1, -1, -1}} - #define DEF_FIELD_540_UP(name) {DEVICE_FIELD_##name, {-1, -1, \ - -1, -1, offsetof(AGSDeviceInfo_540, name), \ -- offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name)}} -+ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), offsetof(AGSDeviceInfo_600, name), \ -+ offsetof(AGSDeviceInfo_600, name)}} - #define DEF_FIELD_600_BELOW(name) {DEVICE_FIELD_##name, {offsetof(AGSDeviceInfo_511, name), offsetof(AGSDeviceInfo_520, name), \ - offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_520, name), offsetof(AGSDeviceInfo_540, name), \ -- offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1}} -+ offsetof(AGSDeviceInfo_541, name), offsetof(AGSDeviceInfo_542, name), -1, \ -+ -1}} - - #define DEVICE_FIELD_adapterString 0 - #define DEVICE_FIELD_architectureVersion 1 -From 074fec36577b7334f5223d0c59d47b219b03f263 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 6 Oct 2021 22:56:07 +0300 -Subject: [PATCH] amd_ags_x64: Add agsDriverExtensionsDX11_Init() semi-stub. - ---- - dlls/amd_ags_x64/amd_ags_x64.spec | 2 +- - dlls/amd_ags_x64/amd_ags_x64_main.c | 8 ++++++++ - 2 files changed, 9 insertions(+), 1 deletion(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64.spec b/dlls/amd_ags_x64/amd_ags_x64.spec -index 562c4103343..ebb026da35e 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64.spec -+++ b/dlls/amd_ags_x64/amd_ags_x64.spec -@@ -14,7 +14,7 @@ - @ stub agsDriverExtensionsDX11_EndUAVOverlap - @ stub agsDriverExtensionsDX11_GetMaxClipRects - @ stub agsDriverExtensionsDX11_IASetPrimitiveTopology --@ stub agsDriverExtensionsDX11_Init -+@ stdcall agsDriverExtensionsDX11_Init(ptr ptr long ptr) - @ stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirect - @ stub agsDriverExtensionsDX11_MultiDrawIndexedInstancedIndirectCountIndirect - @ stub agsDriverExtensionsDX11_MultiDrawInstancedIndirect -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index 97fda0b5230..bbf5efff741 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -663,6 +663,14 @@ int WINAPI agsGetVersionNumber(void) - return AGS_MAKE_VERSION(amd_ags_info[version].major, amd_ags_info[version].minor, amd_ags_info[version].patch); - } - -+AGSReturnCode WINAPI agsDriverExtensionsDX11_Init( AGSContext* context, ID3D11Device* device, unsigned int uavSlot, unsigned int* extensionsSupported ) -+{ -+ FIXME("context %p, device %p, uavSlot %u, extensionsSupported %p stub.\n", context, device, uavSlot, extensionsSupported); -+ -+ *extensionsSupported = 0; -+ return AGS_SUCCESS; -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - TRACE("%p, %u, %p.\n", instance, reason, reserved); -From c7c0c87cdfa767d5588837dfadbaba541775ed35 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 10 Nov 2021 22:11:59 +0300 -Subject: [PATCH] amd_ags_x64: Bump driver version to 21.10.2. - -For FH5. ---- - dlls/amd_ags_x64/amd_ags_x64_main.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c -index bbf5efff741..264d92af019 100644 ---- a/dlls/amd_ags_x64/amd_ags_x64_main.c -+++ b/dlls/amd_ags_x64/amd_ags_x64_main.c -@@ -518,8 +518,8 @@ AGSReturnCode WINAPI agsInit(AGSContext **context, const AGSConfiguration *confi - gpu_info->agsVersionMajor = amd_ags_info[object->version].major; - gpu_info->agsVersionMinor = amd_ags_info[object->version].minor; - gpu_info->agsVersionPatch = amd_ags_info[object->version].patch; -- gpu_info->driverVersion = "20.50.03.05-210326a-365573E-RadeonSoftwareAdrenalin2020"; -- gpu_info->radeonSoftwareVersion = "21.3.2"; -+ gpu_info->driverVersion = "21.30.25.05-211005a-372402E-RadeonSoftware"; -+ gpu_info->radeonSoftwareVersion = "21.10.2"; - gpu_info->numDevices = object->device_count; - gpu_info->devices = object->devices; - -@@ -553,8 +553,8 @@ AGSReturnCode WINAPI agsInitialize(int ags_version, const AGSConfiguration *conf - } - - memset(gpu_info, 0, sizeof(*gpu_info)); -- gpu_info->driverVersion = "20.50.03.05-210326a-365573E-RadeonSoftwareAdrenalin2020"; -- gpu_info->radeonSoftwareVersion = "21.3.2"; -+ gpu_info->driverVersion = "21.30.25.05-211005a-372402E-RadeonSoftware"; -+ gpu_info->radeonSoftwareVersion = "21.10.2"; - gpu_info->numDevices = object->device_count; - gpu_info->devices = object->devices; - diff --git a/patches/proton/19-proton-msvcrt_nativebuiltin.patch b/patches/proton/19-proton-msvcrt_nativebuiltin.patch deleted file mode 100755 index 8a78fbeb8..000000000 --- a/patches/proton/19-proton-msvcrt_nativebuiltin.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 9ab4f6a838eaefe8501eb8876a70ecf5f7792639 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 29 Mar 2018 11:09:53 -0500 -Subject: [PATCH] HACK: wine.inf: Add native,builtin overrides for msvcrt DLLs - ---- - loader/wine.inf.in | 54 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 54 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index d32bd8d28eb..3ade58e7da6 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -3877,6 +3877,33 @@ HKCU,Software\Valve\Steam,"SteamExe",,"%16422%\Steam\Steam.exe" - HKCU,Software\Valve\Steam\ActiveProcess,"PID",0x10001,0x0000fffe - HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll",,"%16422%\Steam\steamclient.dll" - HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16422%\Steam" -+;;Likely want *80 and *90 too, but those require removing Wine's manifest files. -+HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcr100",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcomp100",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"atl110",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcp110",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcr110",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcomp110",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"atl120",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcp120",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcr120",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcomp120",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-conio-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-heap-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-locale-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-math-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-runtime-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-stdio-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-time-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"atl140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"concrt140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcp140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcr140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" - - [SteamClient.ntamd64] - HKCU,Software\Valve\Steam,"SteamPath",,"%16422%\Steam" -@@ -3886,6 +3913,33 @@ HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll",,"%16426%\Steam\steamcl - HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steamclient64.dll" - HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" - HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" -+;;Likely want *80 and *90 too, but those require removing Wine's manifest files. -+HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcr100",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcomp100",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"atl110",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcp110",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcr110",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcomp110",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"atl120",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcp120",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcr120",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcomp120",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-conio-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-heap-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-locale-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-math-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-runtime-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-stdio-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"api-ms-win-crt-time-l1-1-0",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"atl140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"concrt140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcp140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"msvcr140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" - - [NlsFiles] - c_037.nls diff --git a/patches/proton/20-proton-atiadlxx.patch b/patches/proton/20-proton-atiadlxx.patch deleted file mode 100755 index b23b2a9db..000000000 --- a/patches/proton/20-proton-atiadlxx.patch +++ /dev/null @@ -1,1865 +0,0 @@ -From fb15479455380deaac564e47613dcfd60c703693 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 10 Jul 2020 10:09:21 +0200 -Subject: [PATCH] HACK: atiadlxx: Add stub DLL, disabled by default. - -This is required by several Call of Duty games when using AMD GPU. ---- - configure | 2 + - configure.ac | 1 + - dlls/atiadlxx/Makefile.in | 5 + - dlls/atiadlxx/atiadlxx.spec | 1138 +++++++++++++++++++++++++++++++++ - dlls/atiadlxx/atiadlxx_main.c | 93 +++ - loader/wine.inf.in | 2 + - 6 files changed, 1241 insertions(+) - create mode 100644 dlls/atiadlxx/Makefile.in - create mode 100644 dlls/atiadlxx/atiadlxx.spec - create mode 100644 dlls/atiadlxx/atiadlxx_main.c - -diff --git a/configure b/configure -index b6d84f93272..7a425d08eab 100755 ---- a/configure -+++ b/configure -@@ -1141,6 +1141,7 @@ enable_api_ms_win_shell_shellcom_l1_1_0 - enable_api_ms_win_shell_shellfolders_l1_1_0 - enable_apphelp - enable_appwiz_cpl -+enable_atiadlxx - enable_atl - enable_atl100 - enable_atl110 -@@ -20547,6 +20548,7 @@ wine_fn_config_makefile dlls/api-ms-win-shell-shellfolders-l1-1-0 enable_api_ms_ - wine_fn_config_makefile dlls/apphelp enable_apphelp - wine_fn_config_makefile dlls/apphelp/tests enable_tests - wine_fn_config_makefile dlls/appwiz.cpl enable_appwiz_cpl -+wine_fn_config_makefile dlls/atiadlxx enable_atiadlxx - wine_fn_config_makefile dlls/atl enable_atl - wine_fn_config_makefile dlls/atl/tests enable_tests - wine_fn_config_makefile dlls/atl100 enable_atl100 -diff --git a/configure.ac b/configure.ac -index c4f6d2975b3..1733a63b034 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3076,6 +3076,7 @@ WINE_CONFIG_MAKEFILE(dlls/api-ms-win-shell-shellfolders-l1-1-0) - WINE_CONFIG_MAKEFILE(dlls/apphelp) - WINE_CONFIG_MAKEFILE(dlls/apphelp/tests) - WINE_CONFIG_MAKEFILE(dlls/appwiz.cpl) -+WINE_CONFIG_MAKEFILE(dlls/atiadlxx) - WINE_CONFIG_MAKEFILE(dlls/atl) - WINE_CONFIG_MAKEFILE(dlls/atl/tests) - WINE_CONFIG_MAKEFILE(dlls/atl100) -diff --git a/dlls/atiadlxx/Makefile.in b/dlls/atiadlxx/Makefile.in -new file mode 100644 -index 00000000000..78af7168c20 ---- /dev/null -+++ b/dlls/atiadlxx/Makefile.in -@@ -0,0 +1,5 @@ -+MODULE = atiadlxx.dll -+EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native -+ -+C_SRCS = \ -+ atiadlxx_main.c -diff --git a/dlls/atiadlxx/atiadlxx.spec b/dlls/atiadlxx/atiadlxx.spec -new file mode 100644 -index 00000000000..e2a1f46a838 ---- /dev/null -+++ b/dlls/atiadlxx/atiadlxx.spec -@@ -0,0 +1,1138 @@ -+@ stub ADL2_ADC_CurrentProfileFromDrv_Get -+@ stub ADL2_ADC_Display_AdapterDeviceProfileEx_Get -+@ stub ADL2_ADC_DrvDataToProfile_Copy -+@ stub ADL2_ADC_FindClosestMode_Get -+@ stub ADL2_ADC_IsDevModeEqual_Get -+@ stub ADL2_ADC_Profile_Apply -+@ stub ADL2_APO_AudioDelayAdjustmentInfo_Get -+@ stub ADL2_APO_AudioDelay_Restore -+@ stub ADL2_APO_AudioDelay_Set -+@ stub ADL2_AdapterLimitation_Caps -+@ stub ADL2_AdapterX2_Caps -+@ stub ADL2_Adapter_AMDAndNonAMDDIsplayClone_Get -+@ stub ADL2_Adapter_ASICFamilyType_Get -+@ stub ADL2_Adapter_ASICInfo_Get -+@ stub ADL2_Adapter_Accessibility_Get -+@ stub ADL2_Adapter_AceDefaults_Restore -+@ stub ADL2_Adapter_Active_Get -+@ stub ADL2_Adapter_Active_Set -+@ stub ADL2_Adapter_Active_SetPrefer -+@ stub ADL2_Adapter_AdapterInfoX2_Get -+@ stub ADL2_Adapter_AdapterInfoX3_Get -+@ stub ADL2_Adapter_AdapterInfoX4_Get -+@ stub ADL2_Adapter_AdapterInfo_Get -+@ stub ADL2_Adapter_AdapterList_Disable -+@ stub ADL2_Adapter_AdapterLocationPath_Get -+@ stub ADL2_Adapter_Aspects_Get -+@ stub ADL2_Adapter_AudioChannelSplitConfiguration_Get -+@ stub ADL2_Adapter_AudioChannelSplit_Disable -+@ stub ADL2_Adapter_AudioChannelSplit_Enable -+@ stub ADL2_Adapter_BigSw_Info_Get -+@ stub ADL2_Adapter_BlackAndWhiteLevelSupport_Get -+@ stub ADL2_Adapter_BlackAndWhiteLevel_Get -+@ stub ADL2_Adapter_BlackAndWhiteLevel_Set -+@ stub ADL2_Adapter_BoardLayout_Get -+@ stub ADL2_Adapter_Caps -+@ stub ADL2_Adapter_ChipSetInfo_Get -+@ stub ADL2_Adapter_CloneTypes_Get -+@ stub ADL2_Adapter_ConfigMemory_Cap -+@ stub ADL2_Adapter_ConfigMemory_Get -+@ stub ADL2_Adapter_ConfigureState_Get -+@ stub ADL2_Adapter_ConnectionData_Get -+@ stub ADL2_Adapter_ConnectionData_Remove -+@ stub ADL2_Adapter_ConnectionData_Set -+@ stub ADL2_Adapter_ConnectionState_Get -+@ stub ADL2_Adapter_CrossDisplayPlatformInfo_Get -+@ stub ADL2_Adapter_CrossGPUClone_Disable -+@ stub ADL2_Adapter_CrossdisplayAdapterRole_Caps -+@ stub ADL2_Adapter_CrossdisplayInfoX2_Set -+@ stub ADL2_Adapter_CrossdisplayInfo_Get -+@ stub ADL2_Adapter_CrossdisplayInfo_Set -+@ stub ADL2_Adapter_CrossfireX2_Get -+@ stub ADL2_Adapter_Crossfire_Caps -+@ stub ADL2_Adapter_Crossfire_Get -+@ stub ADL2_Adapter_Crossfire_Set -+@ stub ADL2_Adapter_DefaultAudioChannelTable_Load -+@ stub ADL2_Adapter_Desktop_Caps -+@ stub ADL2_Adapter_Desktop_SupportedSLSGridTypes_Get -+@ stub ADL2_Adapter_DeviceID_Get -+@ stub ADL2_Adapter_DisplayAudioEndpoint_Enable -+@ stub ADL2_Adapter_DisplayAudioEndpoint_Mute -+@ stub ADL2_Adapter_DisplayAudioInfo_Get -+@ stub ADL2_Adapter_DisplayGTCCaps_Get -+@ stub ADL2_Adapter_Display_Caps -+@ stub ADL2_Adapter_DriverSettings_Get -+@ stub ADL2_Adapter_DriverSettings_Set -+@ stub ADL2_Adapter_ECC_ErrorInjection_Set -+@ stub ADL2_Adapter_ECC_ErrorRecords_Get -+@ stub ADL2_Adapter_EDC_ErrorInjection_Set -+@ stub ADL2_Adapter_EDC_ErrorRecords_Get -+@ stub ADL2_Adapter_EDIDManagement_Caps -+@ stub ADL2_Adapter_EmulationMode_Set -+@ stub ADL2_Adapter_ExtInfo_Get -+@ stub ADL2_Adapter_Feature_Caps -+@ stub ADL2_Adapter_FrameMetrics_Caps -+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Disable -+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Enable -+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Get -+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Start -+@ stub ADL2_Adapter_FrameMetrics_FrameDuration_Stop -+@ stub ADL2_Adapter_FrameMetrics_Get -+@ stub ADL2_Adapter_FrameMetrics_Start -+@ stub ADL2_Adapter_FrameMetrics_Stop -+@ stub ADL2_Adapter_Gamma_Get -+@ stub ADL2_Adapter_Gamma_Set -+@ stub ADL2_Adapter_Graphic_Core_Info_Get -+@ stub ADL2_Adapter_HBC_Caps -+@ stub ADL2_Adapter_HBM_ECC_UC_Check -+@ stub ADL2_Adapter_Headless_Get -+@ stub ADL2_Adapter_ID_Get -+@ stub ADL2_Adapter_IsGamingDriver_Info_Get -+@ stub ADL2_Adapter_LocalDisplayConfig_Get -+@ stub ADL2_Adapter_LocalDisplayConfig_Set -+@ stub ADL2_Adapter_LocalDisplayState_Get -+@ stub ADL2_Adapter_MVPU_Set -+@ stub ADL2_Adapter_MaxCursorSize_Get -+@ stub ADL2_Adapter_MemoryInfo2_Get -+@ stub ADL2_Adapter_MemoryInfo_Get -+@ stub ADL2_Adapter_MirabilisSupport_Get -+@ stub ADL2_Adapter_ModeSwitch -+@ stub ADL2_Adapter_ModeTimingOverride_Caps -+@ stub ADL2_Adapter_Modes_ReEnumerate -+@ stub ADL2_Adapter_NumberOfActivatableSources_Get -+@ stdcall ADL2_Adapter_NumberOfAdapters_Get(ptr ptr) -+@ stub ADL2_Adapter_ObservedClockInfo_Get -+@ stub ADL2_Adapter_PMLog_Start -+@ stub ADL2_Adapter_PMLog_Stop -+@ stub ADL2_Adapter_PMLog_Support_Get -+@ stub ADL2_Adapter_PreFlipPostProcessing_Disable -+@ stub ADL2_Adapter_PreFlipPostProcessing_Enable -+@ stub ADL2_Adapter_PreFlipPostProcessing_Get_Status -+@ stub ADL2_Adapter_PreFlipPostProcessing_Select_LUT_Algorithm -+@ stub ADL2_Adapter_PreFlipPostProcessing_Select_LUT_Buffer -+@ stub ADL2_Adapter_PreFlipPostProcessing_Unselect_LUT_Buffer -+@ stub ADL2_Adapter_Primary_Get -+@ stub ADL2_Adapter_Primary_Set -+@ stub ADL2_Adapter_RAS_ErrorInjection_Set -+@ stub ADL2_Adapter_RegValueInt_Get -+@ stub ADL2_Adapter_RegValueInt_Set -+@ stub ADL2_Adapter_RegValueString_Get -+@ stub ADL2_Adapter_RegValueString_Set -+@ stub ADL2_Adapter_SWInfo_Get -+@ stub ADL2_Adapter_Speed_Caps -+@ stub ADL2_Adapter_Speed_Get -+@ stub ADL2_Adapter_Speed_Set -+@ stub ADL2_Adapter_SupportedConnections_Get -+@ stub ADL2_Adapter_TRNG_Get -+@ stub ADL2_Adapter_Tear_Free_Cap -+@ stub ADL2_Adapter_VRAMUsage_Get -+@ stub ADL2_Adapter_VariBrightEnable_Set -+@ stub ADL2_Adapter_VariBrightLevel_Get -+@ stub ADL2_Adapter_VariBrightLevel_Set -+@ stub ADL2_Adapter_VariBright_Caps -+@ stub ADL2_Adapter_VerndorID_Int_get -+@ stub ADL2_Adapter_VideoBiosInfo_Get -+@ stub ADL2_Adapter_VideoTheaterModeInfo_Get -+@ stub ADL2_Adapter_VideoTheaterModeInfo_Set -+@ stub ADL2_Adapter_XConnectSupport_Get -+@ stub ADL2_ApplicationProfilesX2_AppInterceptionList_Set -+@ stub ADL2_ApplicationProfilesX2_AppStartStopInfo_Get -+@ stub ADL2_ApplicationProfiles_AppInterceptionList_Set -+@ stub ADL2_ApplicationProfiles_AppInterception_Set -+@ stub ADL2_ApplicationProfiles_AppStartStopInfo_Get -+@ stub ADL2_ApplicationProfiles_AppStartStop_Resume -+@ stub ADL2_ApplicationProfiles_Applications_Get -+@ stub ADL2_ApplicationProfiles_ConvertToCompact -+@ stub ADL2_ApplicationProfiles_DriverAreaPrivacy_Get -+@ stub ADL2_ApplicationProfiles_GetCustomization -+@ stub ADL2_ApplicationProfiles_HitListsX2_Get -+@ stub ADL2_ApplicationProfiles_HitListsX3_Get -+@ stub ADL2_ApplicationProfiles_HitLists_Get -+@ stub ADL2_ApplicationProfiles_ProfileApplicationX2_Assign -+@ stub ADL2_ApplicationProfiles_ProfileApplication_Assign -+@ stub ADL2_ApplicationProfiles_ProfileOfAnApplicationX2_Search -+@ stub ADL2_ApplicationProfiles_ProfileOfAnApplication_InMemorySearch -+@ stub ADL2_ApplicationProfiles_ProfileOfAnApplication_Search -+@ stub ADL2_ApplicationProfiles_Profile_Create -+@ stub ADL2_ApplicationProfiles_Profile_Exist -+@ stub ADL2_ApplicationProfiles_Profile_Remove -+@ stub ADL2_ApplicationProfiles_PropertyType_Get -+@ stub ADL2_ApplicationProfiles_Release_Get -+@ stub ADL2_ApplicationProfiles_RemoveApplication -+@ stub ADL2_ApplicationProfiles_StatusInfo_Get -+@ stub ADL2_ApplicationProfiles_System_Reload -+@ stub ADL2_ApplicationProfiles_User_Load -+@ stub ADL2_ApplicationProfiles_User_Unload -+@ stub ADL2_Audio_CurrentSampleRate_Get -+@ stub ADL2_AutoTuningResult_Get -+@ stub ADL2_BOOST_Settings_Get -+@ stub ADL2_BOOST_Settings_Set -+@ stub ADL2_Blockchain_BlockchainMode_Caps -+@ stub ADL2_Blockchain_BlockchainMode_Get -+@ stub ADL2_Blockchain_BlockchainMode_Set -+@ stub ADL2_Blockchain_Hashrate_Set -+@ stub ADL2_CDS_UnsafeMode_Set -+@ stub ADL2_CHILL_SettingsX2_Get -+@ stub ADL2_CHILL_SettingsX2_Set -+@ stub ADL2_CV_DongleSettings_Get -+@ stub ADL2_CV_DongleSettings_Reset -+@ stub ADL2_CV_DongleSettings_Set -+@ stub ADL2_Chill_Caps_Get -+@ stub ADL2_Chill_Settings_Get -+@ stub ADL2_Chill_Settings_Notify -+@ stub ADL2_Chill_Settings_Set -+@ stub ADL2_CustomFan_Caps -+@ stub ADL2_CustomFan_Get -+@ stub ADL2_CustomFan_Set -+@ stub ADL2_DELAG_Settings_Get -+@ stub ADL2_DELAG_Settings_Set -+@ stub ADL2_DFP_AllowOnlyCETimings_Get -+@ stub ADL2_DFP_AllowOnlyCETimings_Set -+@ stub ADL2_DFP_BaseAudioSupport_Get -+@ stub ADL2_DFP_GPUScalingEnable_Get -+@ stub ADL2_DFP_GPUScalingEnable_Set -+@ stub ADL2_DFP_HDMISupport_Get -+@ stub ADL2_DFP_MVPUAnalogSupport_Get -+@ stub ADL2_DFP_PixelFormat_Caps -+@ stub ADL2_DFP_PixelFormat_Get -+@ stub ADL2_DFP_PixelFormat_Set -+@ stub ADL2_DVRSupport_Get -+@ stub ADL2_Desktop_DOPP_Enable -+@ stub ADL2_Desktop_DOPP_EnableX2 -+@ stub ADL2_Desktop_Detach -+@ stub ADL2_Desktop_Device_Create -+@ stub ADL2_Desktop_Device_Destroy -+@ stub ADL2_Desktop_ExclusiveModeX2_Get -+@ stub ADL2_Desktop_HardwareCursor_SetBitmap -+@ stub ADL2_Desktop_HardwareCursor_SetPosition -+@ stub ADL2_Desktop_HardwareCursor_Toggle -+@ stub ADL2_Desktop_PFPAComplete_Set -+@ stub ADL2_Desktop_PFPAState_Get -+@ stub ADL2_Desktop_PrimaryInfo_Get -+@ stub ADL2_Desktop_TextureState_Get -+@ stub ADL2_Desktop_Texture_Enable -+@ stub ADL2_Device_PMLog_Device_Create -+@ stub ADL2_Device_PMLog_Device_Destroy -+@ stub ADL2_DisplayScaling_Set -+@ stub ADL2_Display_AdapterID_Get -+@ stub ADL2_Display_AdjustCaps_Get -+@ stub ADL2_Display_AdjustmentCoherent_Get -+@ stub ADL2_Display_AdjustmentCoherent_Set -+@ stub ADL2_Display_AudioMappingInfo_Get -+@ stub ADL2_Display_AvivoColor_Get -+@ stub ADL2_Display_AvivoCurrentColor_Set -+@ stub ADL2_Display_AvivoDefaultColor_Set -+@ stub ADL2_Display_BackLight_Get -+@ stub ADL2_Display_BackLight_Set -+@ stub ADL2_Display_BezelOffsetSteppingSize_Get -+@ stub ADL2_Display_BezelOffset_Set -+@ stub ADL2_Display_BezelSupported_Validate -+@ stub ADL2_Display_Capabilities_Get -+@ stub ADL2_Display_ColorCaps_Get -+@ stub ADL2_Display_ColorDepth_Get -+@ stub ADL2_Display_ColorDepth_Set -+@ stub ADL2_Display_ColorTemperatureSourceDefault_Get -+@ stub ADL2_Display_ColorTemperatureSource_Get -+@ stub ADL2_Display_ColorTemperatureSource_Set -+@ stub ADL2_Display_Color_Get -+@ stub ADL2_Display_Color_Set -+@ stub ADL2_Display_ConnectedDisplays_Get -+@ stub ADL2_Display_ContainerID_Get -+@ stub ADL2_Display_ControllerOverlayAdjustmentCaps_Get -+@ stub ADL2_Display_ControllerOverlayAdjustmentData_Get -+@ stub ADL2_Display_ControllerOverlayAdjustmentData_Set -+@ stub ADL2_Display_CustomizedModeListNum_Get -+@ stub ADL2_Display_CustomizedModeList_Get -+@ stub ADL2_Display_CustomizedMode_Add -+@ stub ADL2_Display_CustomizedMode_Delete -+@ stub ADL2_Display_CustomizedMode_Validate -+@ stub ADL2_Display_DCE_Get -+@ stub ADL2_Display_DCE_Set -+@ stub ADL2_Display_DDCBlockAccess_Get -+@ stub ADL2_Display_DDCInfo2_Get -+@ stub ADL2_Display_DDCInfo_Get -+@ stub ADL2_Display_Deflicker_Get -+@ stub ADL2_Display_Deflicker_Set -+@ stub ADL2_Display_DeviceConfig_Get -+@ stub ADL2_Display_DisplayContent_Cap -+@ stub ADL2_Display_DisplayContent_Get -+@ stub ADL2_Display_DisplayContent_Set -+@ stub ADL2_Display_DisplayInfo_Get -+@ stub ADL2_Display_DisplayMapConfigX2_Set -+@ stub ADL2_Display_DisplayMapConfig_Get -+@ stub ADL2_Display_DisplayMapConfig_PossibleAddAndRemove -+@ stub ADL2_Display_DisplayMapConfig_Set -+@ stub ADL2_Display_DisplayMapConfig_Validate -+@ stub ADL2_Display_DitherState_Get -+@ stub ADL2_Display_DitherState_Set -+@ stub ADL2_Display_Downscaling_Caps -+@ stub ADL2_Display_DpMstAuxMsg_Get -+@ stub ADL2_Display_DpMstInfo_Get -+@ stub ADL2_Display_DummyVirtual_Destroy -+@ stub ADL2_Display_DummyVirtual_Get -+@ stub ADL2_Display_EdidData_Get -+@ stub ADL2_Display_EdidData_Set -+@ stub ADL2_Display_EnumDisplays_Get -+@ stub ADL2_Display_FilterSVideo_Get -+@ stub ADL2_Display_FilterSVideo_Set -+@ stub ADL2_Display_ForcibleDisplay_Get -+@ stub ADL2_Display_ForcibleDisplay_Set -+@ stub ADL2_Display_FormatsOverride_Get -+@ stub ADL2_Display_FormatsOverride_Set -+@ stub ADL2_Display_FreeSyncState_Get -+@ stub ADL2_Display_FreeSyncState_Set -+@ stub ADL2_Display_FreeSync_Cap -+@ stub ADL2_Display_GamutMapping_Get -+@ stub ADL2_Display_GamutMapping_Reset -+@ stub ADL2_Display_GamutMapping_Set -+@ stub ADL2_Display_Gamut_Caps -+@ stub ADL2_Display_Gamut_Get -+@ stub ADL2_Display_Gamut_Set -+@ stub ADL2_Display_HDCP_Get -+@ stub ADL2_Display_HDCP_Set -+@ stub ADL2_Display_HDRState_Get -+@ stub ADL2_Display_HDRState_Set -+@ stub ADL2_Display_ImageExpansion_Get -+@ stub ADL2_Display_ImageExpansion_Set -+@ stub ADL2_Display_InfoPacket_Get -+@ stub ADL2_Display_InfoPacket_Set -+@ stub ADL2_Display_IsVirtual_Get -+@ stub ADL2_Display_LCDRefreshRateCapability_Get -+@ stub ADL2_Display_LCDRefreshRateOptions_Get -+@ stub ADL2_Display_LCDRefreshRateOptions_Set -+@ stub ADL2_Display_LCDRefreshRate_Get -+@ stub ADL2_Display_LCDRefreshRate_Set -+@ stub ADL2_Display_Limits_Get -+@ stub ADL2_Display_MVPUCaps_Get -+@ stub ADL2_Display_MVPUStatus_Get -+@ stub ADL2_Display_ModeTimingOverrideInfo_Get -+@ stub ADL2_Display_ModeTimingOverrideListX2_Get -+@ stub ADL2_Display_ModeTimingOverrideListX3_Get -+@ stub ADL2_Display_ModeTimingOverrideList_Get -+@ stub ADL2_Display_ModeTimingOverrideX2_Get -+@ stub ADL2_Display_ModeTimingOverrideX2_Set -+@ stub ADL2_Display_ModeTimingOverrideX3_Get -+@ stub ADL2_Display_ModeTimingOverride_Delete -+@ stub ADL2_Display_ModeTimingOverride_Get -+@ stub ADL2_Display_ModeTimingOverride_Set -+@ stub ADL2_Display_Modes_Get -+@ stub ADL2_Display_Modes_Set -+@ stub ADL2_Display_Modes_X2_Get -+@ stub ADL2_Display_MonitorPowerState_Set -+@ stub ADL2_Display_NativeAUXChannel_Access -+@ stub ADL2_Display_NeedWorkaroundFor5Clone_Get -+@ stub ADL2_Display_NumberOfDisplays_Get -+@ stub ADL2_Display_ODClockConfig_Set -+@ stub ADL2_Display_ODClockInfo_Get -+@ stub ADL2_Display_Overlap_NotifyAdjustment -+@ stub ADL2_Display_Overlap_Set -+@ stub ADL2_Display_Overscan_Get -+@ stub ADL2_Display_Overscan_Set -+@ stub ADL2_Display_PixelFormatDefault_Get -+@ stub ADL2_Display_PixelFormat_Get -+@ stub ADL2_Display_PixelFormat_Set -+@ stub ADL2_Display_Position_Get -+@ stub ADL2_Display_Position_Set -+@ stub ADL2_Display_PossibleMapping_Get -+@ stub ADL2_Display_PossibleMode_Get -+@ stub ADL2_Display_PowerXpressActiveGPU_Get -+@ stub ADL2_Display_PowerXpressActiveGPU_Set -+@ stub ADL2_Display_PowerXpressActvieGPUR2_Get -+@ stub ADL2_Display_PowerXpressVersion_Get -+@ stub ADL2_Display_PowerXpress_AutoSwitchConfig_Get -+@ stub ADL2_Display_PowerXpress_AutoSwitchConfig_Set -+@ stub ADL2_Display_PreferredMode_Get -+@ stub ADL2_Display_PreservedAspectRatio_Get -+@ stub ADL2_Display_PreservedAspectRatio_Set -+@ stub ADL2_Display_Property_Get -+@ stub ADL2_Display_Property_Set -+@ stub ADL2_Display_RcDisplayAdjustment -+@ stub ADL2_Display_ReGammaCoefficients_Get -+@ stub ADL2_Display_ReGammaCoefficients_Set -+@ stub ADL2_Display_ReducedBlanking_Get -+@ stub ADL2_Display_ReducedBlanking_Set -+@ stub ADL2_Display_RegammaR1_Get -+@ stub ADL2_Display_RegammaR1_Set -+@ stub ADL2_Display_Regamma_Get -+@ stub ADL2_Display_Regamma_Set -+@ stub ADL2_Display_SLSBuilder_CommonMode_Get -+@ stub ADL2_Display_SLSBuilder_Create -+@ stub ADL2_Display_SLSBuilder_DisplaysCanBeNextCandidateInSLS_Get -+@ stub ADL2_Display_SLSBuilder_DisplaysCanBeNextCandidateToEnabled_Get -+@ stub ADL2_Display_SLSBuilder_Get -+@ stub ADL2_Display_SLSBuilder_IsActive_Notify -+@ stub ADL2_Display_SLSBuilder_MaxSLSLayoutSize_Get -+@ stub ADL2_Display_SLSBuilder_TimeOut_Get -+@ stub ADL2_Display_SLSBuilder_Update -+@ stub ADL2_Display_SLSGrid_Caps -+@ stub ADL2_Display_SLSMapConfigX2_Delete -+@ stub ADL2_Display_SLSMapConfigX2_Get -+@ stub ADL2_Display_SLSMapConfig_Create -+@ stub ADL2_Display_SLSMapConfig_Delete -+@ stub ADL2_Display_SLSMapConfig_Get -+@ stub ADL2_Display_SLSMapConfig_ImageCropType_Set -+@ stub ADL2_Display_SLSMapConfig_Rearrange -+@ stub ADL2_Display_SLSMapConfig_SetState -+@ stub ADL2_Display_SLSMapConfig_SupportedImageCropType_Get -+@ stub ADL2_Display_SLSMapConfig_Valid -+@ stub ADL2_Display_SLSMapIndexList_Get -+@ stub ADL2_Display_SLSMapIndex_Get -+@ stub ADL2_Display_SLSMiddleMode_Get -+@ stub ADL2_Display_SLSMiddleMode_Set -+@ stub ADL2_Display_SLSRecords_Get -+@ stub ADL2_Display_Sharpness_Caps -+@ stub ADL2_Display_Sharpness_Get -+@ stub ADL2_Display_Sharpness_Info_Get -+@ stub ADL2_Display_Sharpness_Set -+@ stub ADL2_Display_Size_Get -+@ stub ADL2_Display_Size_Set -+@ stub ADL2_Display_SourceContentAttribute_Get -+@ stub ADL2_Display_SourceContentAttribute_Set -+@ stub ADL2_Display_SplitDisplay_Caps -+@ stub ADL2_Display_SplitDisplay_Get -+@ stub ADL2_Display_SplitDisplay_RestoreDesktopConfiguration -+@ stub ADL2_Display_SplitDisplay_Set -+@ stub ADL2_Display_SupportedColorDepth_Get -+@ stub ADL2_Display_SupportedPixelFormat_Get -+@ stub ADL2_Display_SwitchingCapability_Get -+@ stub ADL2_Display_TVCaps_Get -+@ stub ADL2_Display_TargetTimingX2_Get -+@ stub ADL2_Display_TargetTiming_Get -+@ stub ADL2_Display_UnderScan_Auto_Get -+@ stub ADL2_Display_UnderScan_Auto_Set -+@ stub ADL2_Display_UnderscanState_Get -+@ stub ADL2_Display_UnderscanState_Set -+@ stub ADL2_Display_UnderscanSupport_Get -+@ stub ADL2_Display_Underscan_Get -+@ stub ADL2_Display_Underscan_Set -+@ stub ADL2_Display_Vector_Get -+@ stub ADL2_Display_ViewPort_Cap -+@ stub ADL2_Display_ViewPort_Get -+@ stub ADL2_Display_ViewPort_Set -+@ stub ADL2_Display_VirtualType_Get -+@ stub ADL2_Display_WriteAndReadI2C -+@ stub ADL2_Display_WriteAndReadI2CLargePayload -+@ stub ADL2_Display_WriteAndReadI2CRev_Get -+@ stub ADL2_ElmCompatibilityMode_Caps -+@ stub ADL2_ElmCompatibilityMode_Status_Get -+@ stub ADL2_ElmCompatibilityMode_Status_Set -+@ stub ADL2_ExclusiveModeGet -+@ stub ADL2_FPS_Caps -+@ stub ADL2_FPS_Settings_Get -+@ stub ADL2_FPS_Settings_Reset -+@ stub ADL2_FPS_Settings_Set -+@ stub ADL2_Feature_Settings_Get -+@ stub ADL2_Feature_Settings_Set -+@ stub ADL2_Flush_Driver_Data -+@ stub ADL2_GPUVMPageSize_Info_Get -+@ stub ADL2_GPUVMPageSize_Info_Set -+@ stub ADL2_GPUVerInfo_Get -+@ stub ADL2_GcnAsicInfo_Get -+@ stub ADL2_Graphics_IsDetachableGraphicsPlatform_Get -+@ stub ADL2_Graphics_IsGfx9AndAbove -+@ stub ADL2_Graphics_MantleVersion_Get -+@ stub ADL2_Graphics_Platform_Get -+@ stdcall ADL2_Graphics_VersionsX2_Get(ptr ptr) -+@ stub ADL2_Graphics_Versions_Get -+@ stub ADL2_Graphics_VulkanVersion_Get -+@ stub ADL2_HybridGraphicsGPU_Set -+@ stub ADL2_MGPUSLS_Status_Set -+@ stub ADL2_MMD_FeatureList_Get -+@ stub ADL2_MMD_FeatureValuesX2_Get -+@ stub ADL2_MMD_FeatureValuesX2_Set -+@ stub ADL2_MMD_FeatureValues_Get -+@ stub ADL2_MMD_FeatureValues_Set -+@ stub ADL2_MMD_FeaturesX2_Caps -+@ stub ADL2_MMD_Features_Caps -+@ stub ADL2_MMD_VideoAdjustInfo_Get -+@ stub ADL2_MMD_VideoAdjustInfo_Set -+@ stub ADL2_MMD_VideoColor_Caps -+@ stub ADL2_MMD_VideoColor_Get -+@ stub ADL2_MMD_VideoColor_Set -+@ stub ADL2_MMD_Video_Caps -+@ stub ADL2_Main_ControlX2_Create -+@ stdcall ADL2_Main_Control_Create(ptr long ptr) -+@ stub ADL2_Main_Control_Destroy -+@ stub ADL2_Main_Control_GetProcAddress -+@ stub ADL2_Main_Control_IsFunctionValid -+@ stub ADL2_Main_Control_Refresh -+@ stub ADL2_Main_LogDebug_Set -+@ stub ADL2_Main_LogError_Set -+@ stub ADL2_New_QueryPMLogData_Get -+@ stub ADL2_Overdrive5_CurrentActivity_Get -+@ stub ADL2_Overdrive5_FanSpeedInfo_Get -+@ stub ADL2_Overdrive5_FanSpeedToDefault_Set -+@ stub ADL2_Overdrive5_FanSpeed_Get -+@ stub ADL2_Overdrive5_FanSpeed_Set -+@ stub ADL2_Overdrive5_ODParameters_Get -+@ stub ADL2_Overdrive5_ODPerformanceLevels_Get -+@ stub ADL2_Overdrive5_ODPerformanceLevels_Set -+@ stub ADL2_Overdrive5_PowerControlAbsValue_Caps -+@ stub ADL2_Overdrive5_PowerControlAbsValue_Get -+@ stub ADL2_Overdrive5_PowerControlAbsValue_Set -+@ stub ADL2_Overdrive5_PowerControlInfo_Get -+@ stub ADL2_Overdrive5_PowerControl_Caps -+@ stub ADL2_Overdrive5_PowerControl_Get -+@ stub ADL2_Overdrive5_PowerControl_Set -+@ stub ADL2_Overdrive5_Temperature_Get -+@ stub ADL2_Overdrive5_ThermalDevices_Enum -+@ stub ADL2_Overdrive6_AdvancedFan_Caps -+@ stub ADL2_Overdrive6_CapabilitiesEx_Get -+@ stub ADL2_Overdrive6_Capabilities_Get -+@ stub ADL2_Overdrive6_ControlI2C -+@ stub ADL2_Overdrive6_CurrentPower_Get -+@ stub ADL2_Overdrive6_CurrentStatus_Get -+@ stub ADL2_Overdrive6_FanPWMLimitData_Get -+@ stub ADL2_Overdrive6_FanPWMLimitData_Set -+@ stub ADL2_Overdrive6_FanPWMLimitRangeInfo_Get -+@ stub ADL2_Overdrive6_FanSpeed_Get -+@ stub ADL2_Overdrive6_FanSpeed_Reset -+@ stub ADL2_Overdrive6_FanSpeed_Set -+@ stub ADL2_Overdrive6_FuzzyController_Caps -+@ stub ADL2_Overdrive6_MaxClockAdjust_Get -+@ stub ADL2_Overdrive6_PowerControlInfo_Get -+@ stub ADL2_Overdrive6_PowerControlInfo_Get_X2 -+@ stub ADL2_Overdrive6_PowerControl_Caps -+@ stub ADL2_Overdrive6_PowerControl_Get -+@ stub ADL2_Overdrive6_PowerControl_Set -+@ stub ADL2_Overdrive6_StateEx_Get -+@ stub ADL2_Overdrive6_StateEx_Set -+@ stub ADL2_Overdrive6_StateInfo_Get -+@ stub ADL2_Overdrive6_State_Reset -+@ stub ADL2_Overdrive6_State_Set -+@ stub ADL2_Overdrive6_TargetTemperatureData_Get -+@ stub ADL2_Overdrive6_TargetTemperatureData_Set -+@ stub ADL2_Overdrive6_TargetTemperatureRangeInfo_Get -+@ stub ADL2_Overdrive6_TemperatureEx_Get -+@ stub ADL2_Overdrive6_Temperature_Get -+@ stub ADL2_Overdrive6_ThermalController_Caps -+@ stub ADL2_Overdrive6_ThermalLimitUnlock_Get -+@ stub ADL2_Overdrive6_ThermalLimitUnlock_Set -+@ stub ADL2_Overdrive6_VoltageControlInfo_Get -+@ stub ADL2_Overdrive6_VoltageControl_Get -+@ stub ADL2_Overdrive6_VoltageControl_Set -+@ stub ADL2_Overdrive8_Current_SettingX2_Get -+@ stub ADL2_Overdrive8_Current_SettingX3_Get -+@ stub ADL2_Overdrive8_Current_Setting_Get -+@ stub ADL2_Overdrive8_Init_SettingX2_Get -+@ stub ADL2_Overdrive8_Init_Setting_Get -+@ stub ADL2_Overdrive8_PMLogSenorRange_Caps -+@ stub ADL2_Overdrive8_PMLogSenorType_Support_Get -+@ stub ADL2_Overdrive8_PMLog_ShareMemory_Read -+@ stub ADL2_Overdrive8_PMLog_ShareMemory_Start -+@ stub ADL2_Overdrive8_PMLog_ShareMemory_Stop -+@ stub ADL2_Overdrive8_PMLog_ShareMemory_Support -+@ stub ADL2_Overdrive8_Setting_Set -+@ stub ADL2_OverdriveN_AutoWattman_Caps -+@ stub ADL2_OverdriveN_AutoWattman_Get -+@ stub ADL2_OverdriveN_AutoWattman_Set -+@ stub ADL2_OverdriveN_CapabilitiesX2_Get -+@ stub ADL2_OverdriveN_Capabilities_Get -+@ stub ADL2_OverdriveN_CountOfEvents_Get -+@ stub ADL2_OverdriveN_FanControl_Get -+@ stub ADL2_OverdriveN_FanControl_Set -+@ stub ADL2_OverdriveN_MemoryClocksX2_Get -+@ stub ADL2_OverdriveN_MemoryClocksX2_Set -+@ stub ADL2_OverdriveN_MemoryClocks_Get -+@ stub ADL2_OverdriveN_MemoryClocks_Set -+@ stub ADL2_OverdriveN_MemoryTimingLevel_Get -+@ stub ADL2_OverdriveN_MemoryTimingLevel_Set -+@ stub ADL2_OverdriveN_PerformanceStatus_Get -+@ stub ADL2_OverdriveN_PowerLimit_Get -+@ stub ADL2_OverdriveN_PowerLimit_Set -+@ stub ADL2_OverdriveN_SCLKAutoOverClock_Get -+@ stub ADL2_OverdriveN_SCLKAutoOverClock_Set -+@ stub ADL2_OverdriveN_SettingsExt_Get -+@ stub ADL2_OverdriveN_SettingsExt_Set -+@ stub ADL2_OverdriveN_SystemClocksX2_Get -+@ stub ADL2_OverdriveN_SystemClocksX2_Set -+@ stub ADL2_OverdriveN_SystemClocks_Get -+@ stub ADL2_OverdriveN_SystemClocks_Set -+@ stub ADL2_OverdriveN_Temperature_Get -+@ stub ADL2_OverdriveN_Test_Set -+@ stub ADL2_OverdriveN_ThrottleNotification_Get -+@ stub ADL2_OverdriveN_ZeroRPMFan_Get -+@ stub ADL2_OverdriveN_ZeroRPMFan_Set -+@ stub ADL2_Overdrive_Caps -+@ stub ADL2_PPLogSettings_Get -+@ stub ADL2_PPLogSettings_Set -+@ stub ADL2_PPW_Caps -+@ stub ADL2_PPW_Status_Get -+@ stub ADL2_PPW_Status_Set -+@ stub ADL2_PageMigration_Settings_Get -+@ stub ADL2_PageMigration_Settings_Set -+@ stub ADL2_PerGPU_GDEvent_Register -+@ stub ADL2_PerGPU_GDEvent_UnRegister -+@ stub ADL2_PerfTuning_Status_Get -+@ stub ADL2_PerfTuning_Status_Set -+@ stub ADL2_PerformanceTuning_Caps -+@ stub ADL2_PowerStates_Get -+@ stub ADL2_PowerXpress_AncillaryDevices_Get -+@ stub ADL2_PowerXpress_Config_Caps -+@ stub ADL2_PowerXpress_Configuration_Get -+@ stub ADL2_PowerXpress_ExtendedBatteryMode_Caps -+@ stub ADL2_PowerXpress_ExtendedBatteryMode_Get -+@ stub ADL2_PowerXpress_ExtendedBatteryMode_Set -+@ stub ADL2_PowerXpress_LongIdleDetect_Get -+@ stub ADL2_PowerXpress_LongIdleDetect_Set -+@ stub ADL2_PowerXpress_PowerControlMode_Get -+@ stub ADL2_PowerXpress_PowerControlMode_Set -+@ stub ADL2_PowerXpress_Scheme_Get -+@ stub ADL2_PowerXpress_Scheme_Set -+@ stub ADL2_RIS_Settings_Get -+@ stub ADL2_RIS_Settings_Set -+@ stub ADL2_RegisterEvent -+@ stub ADL2_RegisterEventX2 -+@ stub ADL2_Remap -+@ stub ADL2_RemoteDisplay_Destroy -+@ stub ADL2_RemoteDisplay_Display_Acquire -+@ stub ADL2_RemoteDisplay_Display_Release -+@ stub ADL2_RemoteDisplay_Display_Release_All -+@ stub ADL2_RemoteDisplay_Hdcp20_Create -+@ stub ADL2_RemoteDisplay_Hdcp20_Destroy -+@ stub ADL2_RemoteDisplay_Hdcp20_Notify -+@ stub ADL2_RemoteDisplay_Hdcp20_Process -+@ stub ADL2_RemoteDisplay_IEPort_Set -+@ stub ADL2_RemoteDisplay_Initialize -+@ stub ADL2_RemoteDisplay_Nofitiation_Register -+@ stub ADL2_RemoteDisplay_Notification_UnRegister -+@ stub ADL2_RemoteDisplay_Support_Caps -+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_InUse_Get -+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_Info_Get -+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_RadioState_Get -+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Change -+@ stub ADL2_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Get -+@ stub ADL2_RemoteDisplay_WFDDeviceInfo_Get -+@ stub ADL2_RemoteDisplay_WFDDeviceName_Change -+@ stub ADL2_RemoteDisplay_WFDDevice_StatusInfo_Get -+@ stub ADL2_RemoteDisplay_WFDDiscover_Start -+@ stub ADL2_RemoteDisplay_WFDDiscover_Stop -+@ stub ADL2_RemoteDisplay_WFDLink_Connect -+@ stub ADL2_RemoteDisplay_WFDLink_Creation_Accept -+@ stub ADL2_RemoteDisplay_WFDLink_Disconnect -+@ stub ADL2_RemoteDisplay_WFDLink_WPS_Process -+@ stub ADL2_RemoteDisplay_WFDWDSPSettings_Set -+@ stub ADL2_RemoteDisplay_WirelessDisplayEnableDisable_Commit -+@ stub ADL2_RemotePlay_ControlFlags_Set -+@ stub ADL2_ScreenPoint_AudioMappingInfo_Get -+@ stub ADL2_Send -+@ stub ADL2_SendX2 -+@ stub ADL2_Stereo3D_2DPackedFormat_Set -+@ stub ADL2_Stereo3D_3DCursorOffset_Get -+@ stub ADL2_Stereo3D_3DCursorOffset_Set -+@ stub ADL2_Stereo3D_CurrentFormat_Get -+@ stub ADL2_Stereo3D_Info_Get -+@ stub ADL2_Stereo3D_Modes_Get -+@ stub ADL2_SwitchableGraphics_Applications_Get -+@ stub ADL2_TV_Standard_Get -+@ stub ADL2_TV_Standard_Set -+@ stub ADL2_TurboSyncSupport_Get -+@ stub ADL2_UnRegisterEvent -+@ stub ADL2_UnRegisterEventX2 -+@ stub ADL2_User_Settings_Notify -+@ stub ADL2_WS_Overdrive_Caps -+@ stub ADL2_Win_IsHybridAI -+@ stub ADL2_Workstation_8BitGrayscale_Get -+@ stub ADL2_Workstation_8BitGrayscale_Set -+@ stub ADL2_Workstation_AdapterNumOfGLSyncConnectors_Get -+@ stub ADL2_Workstation_Caps -+@ stub ADL2_Workstation_DeepBitDepthX2_Get -+@ stub ADL2_Workstation_DeepBitDepthX2_Set -+@ stub ADL2_Workstation_DeepBitDepth_Get -+@ stub ADL2_Workstation_DeepBitDepth_Set -+@ stub ADL2_Workstation_DisplayGLSyncMode_Get -+@ stub ADL2_Workstation_DisplayGLSyncMode_Set -+@ stub ADL2_Workstation_DisplayGenlockCapable_Get -+@ stub ADL2_Workstation_ECCData_Get -+@ stub ADL2_Workstation_ECCX2_Get -+@ stub ADL2_Workstation_ECC_Caps -+@ stub ADL2_Workstation_ECC_Get -+@ stub ADL2_Workstation_ECC_Set -+@ stub ADL2_Workstation_GLSyncCounters_Get -+@ stub ADL2_Workstation_GLSyncGenlockConfiguration_Get -+@ stub ADL2_Workstation_GLSyncGenlockConfiguration_Set -+@ stub ADL2_Workstation_GLSyncModuleDetect_Get -+@ stub ADL2_Workstation_GLSyncModuleInfo_Get -+@ stub ADL2_Workstation_GLSyncPortState_Get -+@ stub ADL2_Workstation_GLSyncPortState_Set -+@ stub ADL2_Workstation_GLSyncSupportedTopology_Get -+@ stub ADL2_Workstation_GlobalEDIDPersistence_Get -+@ stub ADL2_Workstation_GlobalEDIDPersistence_Set -+@ stub ADL2_Workstation_LoadBalancing_Caps -+@ stub ADL2_Workstation_LoadBalancing_Get -+@ stub ADL2_Workstation_LoadBalancing_Set -+@ stub ADL2_Workstation_RAS_ErrorCounts_Get -+@ stub ADL2_Workstation_RAS_ErrorCounts_Reset -+@ stub ADL2_Workstation_SDISegmentList_Get -+@ stub ADL2_Workstation_SDI_Caps -+@ stub ADL2_Workstation_SDI_Get -+@ stub ADL2_Workstation_SDI_Set -+@ stub ADL2_Workstation_Stereo_Get -+@ stub ADL2_Workstation_Stereo_Set -+@ stub ADL2_Workstation_UnsupportedDisplayModes_Enable -+@ stub ADL_ADC_CurrentProfileFromDrv_Get -+@ stub ADL_ADC_Display_AdapterDeviceProfileEx_Get -+@ stub ADL_ADC_DrvDataToProfile_Copy -+@ stub ADL_ADC_FindClosestMode_Get -+@ stub ADL_ADC_IsDevModeEqual_Get -+@ stub ADL_ADC_Profile_Apply -+@ stub ADL_APO_AudioDelayAdjustmentInfo_Get -+@ stub ADL_APO_AudioDelay_Restore -+@ stub ADL_APO_AudioDelay_Set -+@ stub ADL_AdapterLimitation_Caps -+@ stub ADL_AdapterX2_Caps -+@ stub ADL_Adapter_ASICFamilyType_Get -+@ stub ADL_Adapter_ASICInfo_Get -+@ stub ADL_Adapter_Accessibility_Get -+@ stub ADL_Adapter_Active_Get -+@ stub ADL_Adapter_Active_Set -+@ stub ADL_Adapter_Active_SetPrefer -+@ stub ADL_Adapter_AdapterInfoX2_Get -+@ stub ADL_Adapter_AdapterInfo_Get -+@ stub ADL_Adapter_AdapterList_Disable -+@ stub ADL_Adapter_Aspects_Get -+@ stub ADL_Adapter_AudioChannelSplitConfiguration_Get -+@ stub ADL_Adapter_AudioChannelSplit_Disable -+@ stub ADL_Adapter_AudioChannelSplit_Enable -+@ stub ADL_Adapter_BigSw_Info_Get -+@ stub ADL_Adapter_BlackAndWhiteLevelSupport_Get -+@ stub ADL_Adapter_BlackAndWhiteLevel_Get -+@ stub ADL_Adapter_BlackAndWhiteLevel_Set -+@ stub ADL_Adapter_BoardLayout_Get -+@ stub ADL_Adapter_Caps -+@ stub ADL_Adapter_ChipSetInfo_Get -+@ stub ADL_Adapter_ConfigMemory_Cap -+@ stub ADL_Adapter_ConfigMemory_Get -+@ stub ADL_Adapter_ConfigureState_Get -+@ stub ADL_Adapter_ConnectionData_Get -+@ stub ADL_Adapter_ConnectionData_Remove -+@ stub ADL_Adapter_ConnectionData_Set -+@ stub ADL_Adapter_ConnectionState_Get -+@ stub ADL_Adapter_CrossDisplayPlatformInfo_Get -+@ stub ADL_Adapter_CrossdisplayAdapterRole_Caps -+@ stub ADL_Adapter_CrossdisplayInfoX2_Set -+@ stub ADL_Adapter_CrossdisplayInfo_Get -+@ stub ADL_Adapter_CrossdisplayInfo_Set -+@ stub ADL_Adapter_CrossfireX2_Get -+@ stub ADL_Adapter_Crossfire_Caps -+@ stub ADL_Adapter_Crossfire_Get -+@ stub ADL_Adapter_Crossfire_Set -+@ stub ADL_Adapter_DefaultAudioChannelTable_Load -+@ stub ADL_Adapter_DisplayAudioEndpoint_Enable -+@ stub ADL_Adapter_DisplayAudioEndpoint_Mute -+@ stub ADL_Adapter_DisplayAudioInfo_Get -+@ stub ADL_Adapter_DisplayGTCCaps_Get -+@ stub ADL_Adapter_Display_Caps -+@ stub ADL_Adapter_DriverSettings_Get -+@ stub ADL_Adapter_DriverSettings_Set -+@ stub ADL_Adapter_EDIDManagement_Caps -+@ stub ADL_Adapter_EmulationMode_Set -+@ stub ADL_Adapter_ExtInfo_Get -+@ stub ADL_Adapter_Gamma_Get -+@ stub ADL_Adapter_Gamma_Set -+@ stub ADL_Adapter_ID_Get -+@ stub ADL_Adapter_LocalDisplayConfig_Get -+@ stub ADL_Adapter_LocalDisplayConfig_Set -+@ stub ADL_Adapter_LocalDisplayState_Get -+@ stub ADL_Adapter_MaxCursorSize_Get -+@ stub ADL_Adapter_MemoryInfo2_Get -+@ stub ADL_Adapter_MemoryInfo_Get -+@ stub ADL_Adapter_MirabilisSupport_Get -+@ stub ADL_Adapter_ModeSwitch -+@ stub ADL_Adapter_ModeTimingOverride_Caps -+@ stub ADL_Adapter_Modes_ReEnumerate -+@ stub ADL_Adapter_NumberOfActivatableSources_Get -+@ stub ADL_Adapter_NumberOfAdapters_Get -+@ stub ADL_Adapter_ObservedClockInfo_Get -+@ stub ADL_Adapter_ObservedGameClockInfo_Get -+@ stub ADL_Adapter_Primary_Get -+@ stub ADL_Adapter_Primary_Set -+@ stub ADL_Adapter_RegValueInt_Get -+@ stub ADL_Adapter_RegValueInt_Set -+@ stub ADL_Adapter_RegValueString_Get -+@ stub ADL_Adapter_RegValueString_Set -+@ stub ADL_Adapter_SWInfo_Get -+@ stub ADL_Adapter_Speed_Caps -+@ stub ADL_Adapter_Speed_Get -+@ stub ADL_Adapter_Speed_Set -+@ stub ADL_Adapter_SupportedConnections_Get -+@ stub ADL_Adapter_Tear_Free_Cap -+@ stub ADL_Adapter_VariBrightEnable_Set -+@ stub ADL_Adapter_VariBrightLevel_Get -+@ stub ADL_Adapter_VariBrightLevel_Set -+@ stub ADL_Adapter_VariBright_Caps -+@ stub ADL_Adapter_VideoBiosInfo_Get -+@ stub ADL_Adapter_VideoTheaterModeInfo_Get -+@ stub ADL_Adapter_VideoTheaterModeInfo_Set -+@ stub ADL_ApplicationProfiles_Applications_Get -+@ stub ADL_ApplicationProfiles_ConvertToCompact -+@ stub ADL_ApplicationProfiles_DriverAreaPrivacy_Get -+@ stub ADL_ApplicationProfiles_GetCustomization -+@ stub ADL_ApplicationProfiles_HitListsX2_Get -+@ stub ADL_ApplicationProfiles_HitLists_Get -+@ stub ADL_ApplicationProfiles_ProfileApplicationX2_Assign -+@ stub ADL_ApplicationProfiles_ProfileApplication_Assign -+@ stub ADL_ApplicationProfiles_ProfileOfAnApplicationX2_Search -+@ stub ADL_ApplicationProfiles_ProfileOfAnApplication_InMemorySearch -+@ stub ADL_ApplicationProfiles_ProfileOfAnApplication_Search -+@ stub ADL_ApplicationProfiles_Profile_Create -+@ stub ADL_ApplicationProfiles_Profile_Exist -+@ stub ADL_ApplicationProfiles_Profile_Remove -+@ stub ADL_ApplicationProfiles_PropertyType_Get -+@ stub ADL_ApplicationProfiles_Release_Get -+@ stub ADL_ApplicationProfiles_RemoveApplication -+@ stub ADL_ApplicationProfiles_StatusInfo_Get -+@ stub ADL_ApplicationProfiles_System_Reload -+@ stub ADL_ApplicationProfiles_User_Load -+@ stub ADL_ApplicationProfiles_User_Unload -+@ stub ADL_Audio_CurrentSampleRate_Get -+@ stub ADL_CDS_UnsafeMode_Set -+@ stub ADL_CV_DongleSettings_Get -+@ stub ADL_CV_DongleSettings_Reset -+@ stub ADL_CV_DongleSettings_Set -+@ stub ADL_DFP_AllowOnlyCETimings_Get -+@ stub ADL_DFP_AllowOnlyCETimings_Set -+@ stub ADL_DFP_BaseAudioSupport_Get -+@ stub ADL_DFP_GPUScalingEnable_Get -+@ stub ADL_DFP_GPUScalingEnable_Set -+@ stub ADL_DFP_HDMISupport_Get -+@ stub ADL_DFP_MVPUAnalogSupport_Get -+@ stub ADL_DFP_PixelFormat_Caps -+@ stub ADL_DFP_PixelFormat_Get -+@ stub ADL_DFP_PixelFormat_Set -+@ stub ADL_DisplayScaling_Set -+@ stub ADL_Display_AdapterID_Get -+@ stub ADL_Display_AdjustCaps_Get -+@ stub ADL_Display_AdjustmentCoherent_Get -+@ stub ADL_Display_AdjustmentCoherent_Set -+@ stub ADL_Display_AudioMappingInfo_Get -+@ stub ADL_Display_AvivoColor_Get -+@ stub ADL_Display_AvivoCurrentColor_Set -+@ stub ADL_Display_AvivoDefaultColor_Set -+@ stub ADL_Display_BackLight_Get -+@ stub ADL_Display_BackLight_Set -+@ stub ADL_Display_BezelOffsetSteppingSize_Get -+@ stub ADL_Display_BezelOffset_Set -+@ stub ADL_Display_BezelSupported_Validate -+@ stub ADL_Display_Capabilities_Get -+@ stub ADL_Display_ColorCaps_Get -+@ stub ADL_Display_ColorDepth_Get -+@ stub ADL_Display_ColorDepth_Set -+@ stub ADL_Display_ColorTemperatureSource_Get -+@ stub ADL_Display_ColorTemperatureSource_Set -+@ stub ADL_Display_Color_Get -+@ stub ADL_Display_Color_Set -+@ stub ADL_Display_ConnectedDisplays_Get -+@ stub ADL_Display_ContainerID_Get -+@ stub ADL_Display_ControllerOverlayAdjustmentCaps_Get -+@ stub ADL_Display_ControllerOverlayAdjustmentData_Get -+@ stub ADL_Display_ControllerOverlayAdjustmentData_Set -+@ stub ADL_Display_CurrentPixelClock_Get -+@ stub ADL_Display_CustomizedModeListNum_Get -+@ stub ADL_Display_CustomizedModeList_Get -+@ stub ADL_Display_CustomizedMode_Add -+@ stub ADL_Display_CustomizedMode_Delete -+@ stub ADL_Display_CustomizedMode_Validate -+@ stub ADL_Display_DCE_Get -+@ stub ADL_Display_DCE_Set -+@ stub ADL_Display_DDCBlockAccess_Get -+@ stub ADL_Display_DDCInfo2_Get -+@ stub ADL_Display_DDCInfo_Get -+@ stub ADL_Display_Deflicker_Get -+@ stub ADL_Display_Deflicker_Set -+@ stub ADL_Display_DeviceConfig_Get -+@ stub ADL_Display_DisplayContent_Cap -+@ stub ADL_Display_DisplayContent_Get -+@ stub ADL_Display_DisplayContent_Set -+@ stub ADL_Display_DisplayInfo_Get -+@ stub ADL_Display_DisplayMapConfig_Get -+@ stub ADL_Display_DisplayMapConfig_PossibleAddAndRemove -+@ stub ADL_Display_DisplayMapConfig_Set -+@ stub ADL_Display_DisplayMapConfig_Validate -+@ stub ADL_Display_DitherState_Get -+@ stub ADL_Display_DitherState_Set -+@ stub ADL_Display_Downscaling_Caps -+@ stub ADL_Display_DpMstInfo_Get -+@ stub ADL_Display_EdidData_Get -+@ stub ADL_Display_EdidData_Set -+@ stub ADL_Display_EnumDisplays_Get -+@ stub ADL_Display_FilterSVideo_Get -+@ stub ADL_Display_FilterSVideo_Set -+@ stub ADL_Display_ForcibleDisplay_Get -+@ stub ADL_Display_ForcibleDisplay_Set -+@ stub ADL_Display_FormatsOverride_Get -+@ stub ADL_Display_FormatsOverride_Set -+@ stub ADL_Display_FreeSyncState_Get -+@ stub ADL_Display_FreeSyncState_Set -+@ stub ADL_Display_FreeSync_Cap -+@ stub ADL_Display_GamutMapping_Get -+@ stub ADL_Display_GamutMapping_Reset -+@ stub ADL_Display_GamutMapping_Set -+@ stub ADL_Display_Gamut_Caps -+@ stub ADL_Display_Gamut_Get -+@ stub ADL_Display_Gamut_Set -+@ stub ADL_Display_ImageExpansion_Get -+@ stub ADL_Display_ImageExpansion_Set -+@ stub ADL_Display_InfoPacket_Get -+@ stub ADL_Display_InfoPacket_Set -+@ stub ADL_Display_LCDRefreshRateCapability_Get -+@ stub ADL_Display_LCDRefreshRateOptions_Get -+@ stub ADL_Display_LCDRefreshRateOptions_Set -+@ stub ADL_Display_LCDRefreshRate_Get -+@ stub ADL_Display_LCDRefreshRate_Set -+@ stub ADL_Display_Limits_Get -+@ stub ADL_Display_MVPUCaps_Get -+@ stub ADL_Display_MVPUStatus_Get -+@ stub ADL_Display_ModeTimingOverrideInfo_Get -+@ stub ADL_Display_ModeTimingOverrideListX2_Get -+@ stub ADL_Display_ModeTimingOverrideList_Get -+@ stub ADL_Display_ModeTimingOverrideX2_Get -+@ stub ADL_Display_ModeTimingOverride_Delete -+@ stub ADL_Display_ModeTimingOverride_Get -+@ stub ADL_Display_ModeTimingOverride_Set -+@ stub ADL_Display_Modes_Get -+@ stub ADL_Display_Modes_Set -+@ stub ADL_Display_MonitorPowerState_Set -+@ stub ADL_Display_NativeAUXChannel_Access -+@ stub ADL_Display_NeedWorkaroundFor5Clone_Get -+@ stub ADL_Display_NumberOfDisplays_Get -+@ stub ADL_Display_ODClockConfig_Set -+@ stub ADL_Display_ODClockInfo_Get -+@ stub ADL_Display_Overlap_Set -+@ stub ADL_Display_Overscan_Get -+@ stub ADL_Display_Overscan_Set -+@ stub ADL_Display_PixelClockAllowableRange_Set -+@ stub ADL_Display_PixelClockCaps_Get -+@ stub ADL_Display_PixelFormat_Get -+@ stub ADL_Display_PixelFormat_Set -+@ stub ADL_Display_Position_Get -+@ stub ADL_Display_Position_Set -+@ stub ADL_Display_PossibleMapping_Get -+@ stub ADL_Display_PossibleMode_Get -+@ stub ADL_Display_PowerXpressActiveGPU_Get -+@ stub ADL_Display_PowerXpressActiveGPU_Set -+@ stub ADL_Display_PowerXpressActvieGPUR2_Get -+@ stub ADL_Display_PowerXpressVersion_Get -+@ stub ADL_Display_PowerXpress_AutoSwitchConfig_Get -+@ stub ADL_Display_PowerXpress_AutoSwitchConfig_Set -+@ stub ADL_Display_PreservedAspectRatio_Get -+@ stub ADL_Display_PreservedAspectRatio_Set -+@ stub ADL_Display_Property_Get -+@ stub ADL_Display_Property_Set -+@ stub ADL_Display_RcDisplayAdjustment -+@ stub ADL_Display_ReGammaCoefficients_Get -+@ stub ADL_Display_ReGammaCoefficients_Set -+@ stub ADL_Display_ReducedBlanking_Get -+@ stub ADL_Display_ReducedBlanking_Set -+@ stub ADL_Display_RegammaR1_Get -+@ stub ADL_Display_RegammaR1_Set -+@ stub ADL_Display_Regamma_Get -+@ stub ADL_Display_Regamma_Set -+@ stub ADL_Display_SLSGrid_Caps -+@ stub ADL_Display_SLSMapConfigX2_Get -+@ stub ADL_Display_SLSMapConfig_Create -+@ stub ADL_Display_SLSMapConfig_Delete -+@ stub ADL_Display_SLSMapConfig_Get -+@ stub ADL_Display_SLSMapConfig_Rearrange -+@ stub ADL_Display_SLSMapConfig_SetState -+@ stub ADL_Display_SLSMapIndexList_Get -+@ stub ADL_Display_SLSMapIndex_Get -+@ stub ADL_Display_SLSMiddleMode_Get -+@ stub ADL_Display_SLSMiddleMode_Set -+@ stub ADL_Display_SLSRecords_Get -+@ stub ADL_Display_Sharpness_Caps -+@ stub ADL_Display_Sharpness_Get -+@ stub ADL_Display_Sharpness_Info_Get -+@ stub ADL_Display_Sharpness_Set -+@ stub ADL_Display_Size_Get -+@ stub ADL_Display_Size_Set -+@ stub ADL_Display_SourceContentAttribute_Get -+@ stub ADL_Display_SourceContentAttribute_Set -+@ stub ADL_Display_SplitDisplay_Caps -+@ stub ADL_Display_SplitDisplay_Get -+@ stub ADL_Display_SplitDisplay_RestoreDesktopConfiguration -+@ stub ADL_Display_SplitDisplay_Set -+@ stub ADL_Display_SupportedColorDepth_Get -+@ stub ADL_Display_SupportedPixelFormat_Get -+@ stub ADL_Display_SwitchingCapability_Get -+@ stub ADL_Display_TVCaps_Get -+@ stub ADL_Display_TargetTiming_Get -+@ stub ADL_Display_UnderScan_Auto_Get -+@ stub ADL_Display_UnderScan_Auto_Set -+@ stub ADL_Display_Underscan_Get -+@ stub ADL_Display_Underscan_Set -+@ stub ADL_Display_Vector_Get -+@ stub ADL_Display_ViewPort_Cap -+@ stub ADL_Display_ViewPort_Get -+@ stub ADL_Display_ViewPort_Set -+@ stub ADL_Display_WriteAndReadI2C -+@ stub ADL_Display_WriteAndReadI2CLargePayload -+@ stub ADL_Display_WriteAndReadI2CRev_Get -+@ stub ADL_Flush_Driver_Data -+@ stub ADL_Graphics_Platform_Get -+@ stdcall ADL_Graphics_Versions_Get(ptr) -+@ stub ADL_MMD_FeatureList_Get -+@ stub ADL_MMD_FeatureValuesX2_Get -+@ stub ADL_MMD_FeatureValuesX2_Set -+@ stub ADL_MMD_FeatureValues_Get -+@ stub ADL_MMD_FeatureValues_Set -+@ stub ADL_MMD_FeaturesX2_Caps -+@ stub ADL_MMD_Features_Caps -+@ stub ADL_MMD_VideoAdjustInfo_Get -+@ stub ADL_MMD_VideoAdjustInfo_Set -+@ stub ADL_MMD_VideoColor_Caps -+@ stub ADL_MMD_VideoColor_Get -+@ stub ADL_MMD_VideoColor_Set -+@ stub ADL_MMD_Video_Caps -+@ stub ADL_Main_ControlX2_Create -+@ stdcall ADL_Main_Control_Create(ptr long) -+@ stdcall ADL_Main_Control_Destroy() -+@ stub ADL_Main_Control_GetProcAddress -+@ stub ADL_Main_Control_IsFunctionValid -+@ stub ADL_Main_Control_Refresh -+@ stub ADL_Main_LogDebug_Set -+@ stub ADL_Main_LogError_Set -+@ stub ADL_Overdrive5_CurrentActivity_Get -+@ stub ADL_Overdrive5_FanSpeedInfo_Get -+@ stub ADL_Overdrive5_FanSpeedToDefault_Set -+@ stub ADL_Overdrive5_FanSpeed_Get -+@ stub ADL_Overdrive5_FanSpeed_Set -+@ stub ADL_Overdrive5_ODParameters_Get -+@ stub ADL_Overdrive5_ODPerformanceLevels_Get -+@ stub ADL_Overdrive5_ODPerformanceLevels_Set -+@ stub ADL_Overdrive5_PowerControlAbsValue_Caps -+@ stub ADL_Overdrive5_PowerControlAbsValue_Get -+@ stub ADL_Overdrive5_PowerControlAbsValue_Set -+@ stub ADL_Overdrive5_PowerControlInfo_Get -+@ stub ADL_Overdrive5_PowerControl_Caps -+@ stub ADL_Overdrive5_PowerControl_Get -+@ stub ADL_Overdrive5_PowerControl_Set -+@ stub ADL_Overdrive5_Temperature_Get -+@ stub ADL_Overdrive5_ThermalDevices_Enum -+@ stub ADL_Overdrive6_AdvancedFan_Caps -+@ stub ADL_Overdrive6_CapabilitiesEx_Get -+@ stub ADL_Overdrive6_Capabilities_Get -+@ stub ADL_Overdrive6_CurrentStatus_Get -+@ stub ADL_Overdrive6_FanPWMLimitData_Get -+@ stub ADL_Overdrive6_FanPWMLimitData_Set -+@ stub ADL_Overdrive6_FanPWMLimitRangeInfo_Get -+@ stub ADL_Overdrive6_FanSpeed_Get -+@ stub ADL_Overdrive6_FanSpeed_Reset -+@ stub ADL_Overdrive6_FanSpeed_Set -+@ stub ADL_Overdrive6_FuzzyController_Caps -+@ stub ADL_Overdrive6_MaxClockAdjust_Get -+@ stub ADL_Overdrive6_PowerControlInfo_Get -+@ stub ADL_Overdrive6_PowerControl_Caps -+@ stub ADL_Overdrive6_PowerControl_Get -+@ stub ADL_Overdrive6_PowerControl_Set -+@ stub ADL_Overdrive6_StateEx_Get -+@ stub ADL_Overdrive6_StateEx_Set -+@ stub ADL_Overdrive6_StateInfo_Get -+@ stub ADL_Overdrive6_State_Reset -+@ stub ADL_Overdrive6_State_Set -+@ stub ADL_Overdrive6_TargetTemperatureData_Get -+@ stub ADL_Overdrive6_TargetTemperatureData_Set -+@ stub ADL_Overdrive6_TargetTemperatureRangeInfo_Get -+@ stub ADL_Overdrive6_Temperature_Get -+@ stub ADL_Overdrive6_ThermalController_Caps -+@ stub ADL_Overdrive6_ThermalLimitUnlock_Get -+@ stub ADL_Overdrive6_ThermalLimitUnlock_Set -+@ stub ADL_Overdrive6_VoltageControlInfo_Get -+@ stub ADL_Overdrive6_VoltageControl_Get -+@ stub ADL_Overdrive6_VoltageControl_Set -+@ stub ADL_Overdrive_Caps -+@ stub ADL_PowerXpress_AncillaryDevices_Get -+@ stub ADL_PowerXpress_Config_Caps -+@ stub ADL_PowerXpress_ExtendedBatteryMode_Caps -+@ stub ADL_PowerXpress_ExtendedBatteryMode_Get -+@ stub ADL_PowerXpress_ExtendedBatteryMode_Set -+@ stub ADL_PowerXpress_LongIdleDetect_Get -+@ stub ADL_PowerXpress_LongIdleDetect_Set -+@ stub ADL_PowerXpress_PowerControlMode_Get -+@ stub ADL_PowerXpress_PowerControlMode_Set -+@ stub ADL_PowerXpress_Scheme_Get -+@ stub ADL_PowerXpress_Scheme_Set -+@ stub ADL_Remap -+@ stub ADL_RemoteDisplay_Destroy -+@ stub ADL_RemoteDisplay_Display_Acquire -+@ stub ADL_RemoteDisplay_Display_Release -+@ stub ADL_RemoteDisplay_Display_Release_All -+@ stub ADL_RemoteDisplay_Hdcp20_Create -+@ stub ADL_RemoteDisplay_Hdcp20_Destroy -+@ stub ADL_RemoteDisplay_Hdcp20_Notify -+@ stub ADL_RemoteDisplay_Hdcp20_Process -+@ stub ADL_RemoteDisplay_IEPort_Set -+@ stub ADL_RemoteDisplay_Initialize -+@ stub ADL_RemoteDisplay_Nofitiation_Register -+@ stub ADL_RemoteDisplay_Notification_UnRegister -+@ stub ADL_RemoteDisplay_Support_Caps -+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_InUse_Get -+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_Info_Get -+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_RadioState_Get -+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Change -+@ stub ADL_RemoteDisplay_VirtualWirelessAdapter_WPSSetting_Get -+@ stub ADL_RemoteDisplay_WFDDeviceInfo_Get -+@ stub ADL_RemoteDisplay_WFDDeviceName_Change -+@ stub ADL_RemoteDisplay_WFDDevice_StatusInfo_Get -+@ stub ADL_RemoteDisplay_WFDDiscover_Start -+@ stub ADL_RemoteDisplay_WFDDiscover_Stop -+@ stub ADL_RemoteDisplay_WFDLink_Connect -+@ stub ADL_RemoteDisplay_WFDLink_Creation_Accept -+@ stub ADL_RemoteDisplay_WFDLink_Disconnect -+@ stub ADL_RemoteDisplay_WFDLink_WPS_Process -+@ stub ADL_RemoteDisplay_WFDWDSPSettings_Set -+@ stub ADL_RemoteDisplay_WirelessDisplayEnableDisable_Commit -+@ stub ADL_ScreenPoint_AudioMappingInfo_Get -+@ stub ADL_Stereo3D_2DPackedFormat_Set -+@ stub ADL_Stereo3D_3DCursorOffset_Get -+@ stub ADL_Stereo3D_3DCursorOffset_Set -+@ stub ADL_Stereo3D_CurrentFormat_Get -+@ stub ADL_Stereo3D_Info_Get -+@ stub ADL_Stereo3D_Modes_Get -+@ stub ADL_TV_Standard_Get -+@ stub ADL_TV_Standard_Set -+@ stub ADL_Win_IsHybridAI -+@ stub ADL_Workstation_8BitGrayscale_Get -+@ stub ADL_Workstation_8BitGrayscale_Set -+@ stub ADL_Workstation_AdapterNumOfGLSyncConnectors_Get -+@ stub ADL_Workstation_Caps -+@ stub ADL_Workstation_DeepBitDepthX2_Get -+@ stub ADL_Workstation_DeepBitDepthX2_Set -+@ stub ADL_Workstation_DeepBitDepth_Get -+@ stub ADL_Workstation_DeepBitDepth_Set -+@ stub ADL_Workstation_DisplayGLSyncMode_Get -+@ stub ADL_Workstation_DisplayGLSyncMode_Set -+@ stub ADL_Workstation_DisplayGenlockCapable_Get -+@ stub ADL_Workstation_ECCData_Get -+@ stub ADL_Workstation_ECCX2_Get -+@ stub ADL_Workstation_ECC_Caps -+@ stub ADL_Workstation_ECC_Get -+@ stub ADL_Workstation_ECC_Set -+@ stub ADL_Workstation_GLSyncCounters_Get -+@ stub ADL_Workstation_GLSyncGenlockConfiguration_Get -+@ stub ADL_Workstation_GLSyncGenlockConfiguration_Set -+@ stub ADL_Workstation_GLSyncModuleDetect_Get -+@ stub ADL_Workstation_GLSyncModuleInfo_Get -+@ stub ADL_Workstation_GLSyncPortState_Get -+@ stub ADL_Workstation_GLSyncPortState_Set -+@ stub ADL_Workstation_GLSyncSupportedTopology_Get -+@ stub ADL_Workstation_GlobalEDIDPersistence_Get -+@ stub ADL_Workstation_GlobalEDIDPersistence_Set -+@ stub ADL_Workstation_LoadBalancing_Caps -+@ stub ADL_Workstation_LoadBalancing_Get -+@ stub ADL_Workstation_LoadBalancing_Set -+@ stub ADL_Workstation_RAS_Get_Error_Counts -+@ stub ADL_Workstation_RAS_Get_Features -+@ stub ADL_Workstation_RAS_Reset_Error_Counts -+@ stub ADL_Workstation_RAS_Set_Features -+@ stub ADL_Workstation_SDISegmentList_Get -+@ stub ADL_Workstation_SDI_Caps -+@ stub ADL_Workstation_SDI_Get -+@ stub ADL_Workstation_SDI_Set -+@ stub ADL_Workstation_Stereo_Get -+@ stub ADL_Workstation_Stereo_Set -+@ stub ADL_Workstation_UnsupportedDisplayModes_Enable -+@ stub AmdPowerXpressRequestHighPerformance -+@ stub Desktop_Detach -+@ stub Send -+@ stub SendX2 -diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c -new file mode 100644 -index 00000000000..3518761b7f6 ---- /dev/null -+++ b/dlls/atiadlxx/atiadlxx_main.c -@@ -0,0 +1,93 @@ -+#include -+ -+#include "windef.h" -+#include "winbase.h" -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(atiadlxx); -+ -+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) -+{ -+ TRACE("(%p, %u, %p)\n", instance, reason, reserved); -+ -+ switch (reason) -+ { -+ -+ -+ case DLL_PROCESS_ATTACH: -+ DisableThreadLibraryCalls(instance); -+ break; -+ } -+ -+ return TRUE; -+} -+ -+typedef void *(CALLBACK *ADL_MAIN_MALLOC_CALLBACK)(int); -+typedef void *ADL_CONTEXT_HANDLE; -+ -+typedef struct ADLVersionsInfo -+{ -+ char strDriverVer[256]; -+ char strCatalystVersion[256]; -+ char strCatalystWebLink[256]; -+} ADLVersionsInfo, *LPADLVersionsInfo; -+ -+typedef struct ADLVersionsInfoX2 -+{ -+ char strDriverVer[256]; -+ char strCatalystVersion[256]; -+ char strCrimsonVersion[256]; -+ char strCatalystWebLink[256]; -+} ADLVersionsInfoX2, *LPADLVersionsInfoX2; -+ -+static const ADLVersionsInfo version = { -+ "20.11.1", -+ "20.11.1", -+ "", -+}; -+ -+static const ADLVersionsInfoX2 version2 = { -+ "20.11.1", -+ "20.11.1", -+ "20.11.1", -+ "", -+}; -+ -+int WINAPI ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg, ADL_CONTEXT_HANDLE *ptr) -+{ -+ FIXME("cb %p, arg %d, ptr %p stub!\n", cb, arg, ptr); -+ return 0; -+} -+ -+int WINAPI ADL_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg) -+{ -+ FIXME("cb %p, arg %d stub!\n", cb, arg); -+ return 0; -+} -+ -+int WINAPI ADL_Main_Control_Destroy(void) -+{ -+ FIXME("stub!\n"); -+ return 0; -+} -+ -+int WINAPI ADL2_Adapter_NumberOfAdapters_Get(ADL_CONTEXT_HANDLE *ptr, int *count) -+{ -+ FIXME("ptr %p, count %p stub!\n", ptr, count); -+ *count = 0; -+ return 0; -+} -+ -+int WINAPI ADL2_Graphics_VersionsX2_Get(ADL_CONTEXT_HANDLE *ptr, ADLVersionsInfoX2 *ver) -+{ -+ FIXME("ptr %p, ver %p stub!\n", ptr, ver); -+ memcpy(ver, &version2, sizeof(version2)); -+ return 0; -+} -+ -+int WINAPI ADL_Graphics_Versions_Get(ADLVersionsInfo *ver) -+{ -+ FIXME("ver %p stub!\n", ver); -+ memcpy(ver, &version, sizeof(version)); -+ return 0; -+} -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 472cc5fe425..d0dcc9b6d20 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4000,6 +4000,7 @@ HKCU,Software\Wine\DllOverrides,"msvcr140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"atiadlxx",,"disabled" - - [SteamClient.ntamd64] - HKCU,Software\Valve\Steam,"SteamPath",,"%16422%\Steam" -@@ -4364,6 +4364,7 @@ HKCU,Software\Wine\DllOverrides,"msvcr140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" -+HKCU,Software\Wine\DllOverrides,"atiadlxx",,"disabled" - - [NlsFiles] - c_037.nls -From cbfd1dad246e246ad4ed9d6af45b46a3376f21cf Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Mon, 12 Oct 2020 17:46:27 +0300 -Subject: [PATCH] atidlxx: Stub GPU/display enumeration and clock/memory info. - -Shadow of War uses atiadlxx to query the following GPU information: - - * current memory frequency - * current core frequency - * memory size - * memory bandwidth - -Those are used to apprise the GPU and recommend user settings. - -Most of them can be fetched via AMD's powerplay sysfs entries / wined3d -helpers. The only value that is not exposed is the memory bandwith so we -set it to the value my RX580 reports on Windows. - -Because of that on high end system the game may recommend lower settings -than it would with the real value, and the other way around on low end -systems. - -We also report some "sane default" in case we can't find the powerplay -entries - this may be the case with nvapi hack enabled when we report -any NVIDIA card as RX480. - -ADL2 stubs used by Call of Duty games are untouched and still report 0 -GPUs. ---- - dlls/atiadlxx/Makefile.in | 2 + - dlls/atiadlxx/atiadlxx.spec | 18 +- - dlls/atiadlxx/atiadlxx_main.c | 367 ++++++++++++++++++++++++++++++++-- - 3 files changed, 365 insertions(+), 22 deletions(-) - -diff --git a/dlls/atiadlxx/Makefile.in b/dlls/atiadlxx/Makefile.in -index 78af7168c20..7708c714213 100644 ---- a/dlls/atiadlxx/Makefile.in -+++ b/dlls/atiadlxx/Makefile.in -@@ -1,4 +1,6 @@ - MODULE = atiadlxx.dll -+IMPORTS = wined3d -+ - EXTRADLLFLAGS = -mno-cygwin -Wb,--prefer-native - - C_SRCS = \ -diff --git a/dlls/atiadlxx/atiadlxx.spec b/dlls/atiadlxx/atiadlxx.spec -index e2a1f46a838..e2fb060ae8d 100644 ---- a/dlls/atiadlxx/atiadlxx.spec -+++ b/dlls/atiadlxx/atiadlxx.spec -@@ -681,14 +681,14 @@ - @ stub ADL_APO_AudioDelay_Set - @ stub ADL_AdapterLimitation_Caps - @ stub ADL_AdapterX2_Caps --@ stub ADL_Adapter_ASICFamilyType_Get -+@ stdcall ADL_Adapter_ASICFamilyType_Get(long ptr ptr) - @ stub ADL_Adapter_ASICInfo_Get - @ stub ADL_Adapter_Accessibility_Get - @ stub ADL_Adapter_Active_Get - @ stub ADL_Adapter_Active_Set - @ stub ADL_Adapter_Active_SetPrefer - @ stub ADL_Adapter_AdapterInfoX2_Get --@ stub ADL_Adapter_AdapterInfo_Get -+@ stdcall ADL_Adapter_AdapterInfo_Get(ptr long) - @ stub ADL_Adapter_AdapterList_Disable - @ stub ADL_Adapter_Aspects_Get - @ stub ADL_Adapter_AudioChannelSplitConfiguration_Get -@@ -714,8 +714,8 @@ - @ stub ADL_Adapter_CrossdisplayInfo_Get - @ stub ADL_Adapter_CrossdisplayInfo_Set - @ stub ADL_Adapter_CrossfireX2_Get --@ stub ADL_Adapter_Crossfire_Caps --@ stub ADL_Adapter_Crossfire_Get -+@ stdcall ADL_Adapter_Crossfire_Caps(long ptr ptr ptr) -+@ stdcall ADL_Adapter_Crossfire_Get(long ptr ptr) - @ stub ADL_Adapter_Crossfire_Set - @ stub ADL_Adapter_DefaultAudioChannelTable_Load - @ stub ADL_Adapter_DisplayAudioEndpoint_Enable -@@ -736,14 +736,14 @@ - @ stub ADL_Adapter_LocalDisplayState_Get - @ stub ADL_Adapter_MaxCursorSize_Get - @ stub ADL_Adapter_MemoryInfo2_Get --@ stub ADL_Adapter_MemoryInfo_Get -+@ stdcall ADL_Adapter_MemoryInfo_Get(long ptr) - @ stub ADL_Adapter_MirabilisSupport_Get - @ stub ADL_Adapter_ModeSwitch - @ stub ADL_Adapter_ModeTimingOverride_Caps - @ stub ADL_Adapter_Modes_ReEnumerate - @ stub ADL_Adapter_NumberOfActivatableSources_Get --@ stub ADL_Adapter_NumberOfAdapters_Get --@ stub ADL_Adapter_ObservedClockInfo_Get -+@ stdcall ADL_Adapter_NumberOfAdapters_Get(ptr) -+@ stdcall ADL_Adapter_ObservedClockInfo_Get(long ptr ptr) - @ stub ADL_Adapter_ObservedGameClockInfo_Get - @ stub ADL_Adapter_Primary_Get - @ stub ADL_Adapter_Primary_Set -@@ -844,7 +844,7 @@ - @ stub ADL_Display_DisplayContent_Cap - @ stub ADL_Display_DisplayContent_Get - @ stub ADL_Display_DisplayContent_Set --@ stub ADL_Display_DisplayInfo_Get -+@ stdcall ADL_Display_DisplayInfo_Get(long long ptr long) - @ stub ADL_Display_DisplayMapConfig_Get - @ stub ADL_Display_DisplayMapConfig_PossibleAddAndRemove - @ stub ADL_Display_DisplayMapConfig_Set -@@ -969,7 +969,7 @@ - @ stub ADL_Display_WriteAndReadI2CLargePayload - @ stub ADL_Display_WriteAndReadI2CRev_Get - @ stub ADL_Flush_Driver_Data --@ stub ADL_Graphics_Platform_Get -+@ stdcall ADL_Graphics_Platform_Get(ptr) - @ stdcall ADL_Graphics_Versions_Get(ptr) - @ stub ADL_MMD_FeatureList_Get - @ stub ADL_MMD_FeatureValuesX2_Get -diff --git a/dlls/atiadlxx/atiadlxx_main.c b/dlls/atiadlxx/atiadlxx_main.c -index 3518761b7f6..66a64379ffe 100644 ---- a/dlls/atiadlxx/atiadlxx_main.c -+++ b/dlls/atiadlxx/atiadlxx_main.c -@@ -1,8 +1,43 @@ -+/* Headers: https://github.com/GPUOpen-LibrariesAndSDKs/display-library */ -+ - #include -+#include -+#include - -+#define COBJMACROS - #include "windef.h" - #include "winbase.h" -+#include "winuser.h" -+#include "objbase.h" - #include "wine/debug.h" -+#include "wine/wined3d.h" -+ -+#define MAX_GPUS 64 -+#define VENDOR_AMD 0x1002 -+ -+#define ADL_OK 0 -+#define ADL_ERR -1 -+#define ADL_ERR_INVALID_PARAM -3 -+#define ADL_ERR_INVALID_ADL_IDX -5 -+#define ADL_ERR_NOT_SUPPORTED -8 -+#define ADL_ERR_NULL_POINTER -9 -+ -+#define ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED 0x00000001 -+#define ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED 0x00000002 -+#define ADL_DISPLAY_DISPLAYINFO_MASK 0x31fff -+ -+#define ADL_ASIC_DISCRETE (1 << 0) -+#define ADL_ASIC_MASK 0xAF -+ -+enum ADLPlatForm -+{ -+ GRAPHICS_PLATFORM_DESKTOP = 0, -+ GRAPHICS_PLATFORM_MOBILE = 1 -+}; -+#define GRAPHICS_PLATFORM_UNKNOWN -1 -+ -+ -+static struct wined3d *wined3d; - - WINE_DEFAULT_DEBUG_CHANNEL(atiadlxx); - -@@ -25,21 +60,83 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - typedef void *(CALLBACK *ADL_MAIN_MALLOC_CALLBACK)(int); - typedef void *ADL_CONTEXT_HANDLE; - -+ADL_MAIN_MALLOC_CALLBACK adl_malloc; -+#define ADL_MAX_PATH 256 -+ - typedef struct ADLVersionsInfo - { -- char strDriverVer[256]; -- char strCatalystVersion[256]; -- char strCatalystWebLink[256]; -+ char strDriverVer[ADL_MAX_PATH]; -+ char strCatalystVersion[ADL_MAX_PATH]; -+ char strCatalystWebLink[ADL_MAX_PATH]; - } ADLVersionsInfo, *LPADLVersionsInfo; - - typedef struct ADLVersionsInfoX2 - { -- char strDriverVer[256]; -- char strCatalystVersion[256]; -- char strCrimsonVersion[256]; -- char strCatalystWebLink[256]; -+ char strDriverVer[ADL_MAX_PATH]; -+ char strCatalystVersion[ADL_MAX_PATH]; -+ char strCrimsonVersion[ADL_MAX_PATH]; -+ char strCatalystWebLink[ADL_MAX_PATH]; - } ADLVersionsInfoX2, *LPADLVersionsInfoX2; - -+typedef struct ADLAdapterInfo { -+ int iSize; -+ int iAdapterIndex; -+ char strUDID[ADL_MAX_PATH]; -+ int iBusNumber; -+ int iDeviceNumber; -+ int iFunctionNumber; -+ int iVendorID; -+ char strAdapterName[ADL_MAX_PATH]; -+ char strDisplayName[ADL_MAX_PATH]; -+ int iPresent; -+ int iExist; -+ char strDriverPath[ADL_MAX_PATH]; -+ char strDriverPathExt[ADL_MAX_PATH]; -+ char strPNPString[ADL_MAX_PATH]; -+ int iOSDisplayIndex; -+} ADLAdapterInfo, *LPADLAdapterInfo; -+ -+typedef struct ADLDisplayID -+{ -+ int iDisplayLogicalIndex; -+ int iDisplayPhysicalIndex; -+ int iDisplayLogicalAdapterIndex; -+ int iDisplayPhysicalAdapterIndex; -+} ADLDisplayID, *LPADLDisplayID; -+ -+typedef struct ADLDisplayInfo -+{ -+ ADLDisplayID displayID; -+ int iDisplayControllerIndex; -+ char strDisplayName[ADL_MAX_PATH]; -+ char strDisplayManufacturerName[ADL_MAX_PATH]; -+ int iDisplayType; -+ int iDisplayOutputType; -+ int iDisplayConnector; -+ int iDisplayInfoMask; -+ int iDisplayInfoValue; -+} ADLDisplayInfo, *LPADLDisplayInfo; -+ -+typedef struct ADLCrossfireComb -+{ -+ int iNumLinkAdapter; -+ int iAdaptLink[3]; -+} ADLCrossfireComb; -+ -+typedef struct ADLCrossfireInfo -+{ -+ int iErrorCode; -+ int iState; -+ int iSupported; -+} ADLCrossfireInfo; -+ -+typedef struct ADLMemoryInfo -+{ -+ long long iMemorySize; -+ char strMemoryType[ADL_MAX_PATH]; -+ long long iMemoryBandwidth; -+} ADLMemoryInfo, *LPADLMemoryInfo; -+ - static const ADLVersionsInfo version = { - "20.11.1", - "20.11.1", -@@ -56,38 +153,282 @@ static const ADLVersionsInfoX2 version2 = { - int WINAPI ADL2_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg, ADL_CONTEXT_HANDLE *ptr) - { - FIXME("cb %p, arg %d, ptr %p stub!\n", cb, arg, ptr); -- return 0; -+ return ADL_OK; - } - - int WINAPI ADL_Main_Control_Create(ADL_MAIN_MALLOC_CALLBACK cb, int arg) - { - FIXME("cb %p, arg %d stub!\n", cb, arg); -- return 0; -+ adl_malloc = cb; -+ -+ if ((wined3d = wined3d_create(0))) -+ return ADL_OK; -+ else -+ return ADL_ERR; - } - - int WINAPI ADL_Main_Control_Destroy(void) - { - FIXME("stub!\n"); -- return 0; -+ -+ if (wined3d != NULL) -+ wined3d_decref(wined3d); -+ -+ return ADL_OK; - } - - int WINAPI ADL2_Adapter_NumberOfAdapters_Get(ADL_CONTEXT_HANDLE *ptr, int *count) - { - FIXME("ptr %p, count %p stub!\n", ptr, count); -+ - *count = 0; -- return 0; -+ -+ return ADL_OK; - } - - int WINAPI ADL2_Graphics_VersionsX2_Get(ADL_CONTEXT_HANDLE *ptr, ADLVersionsInfoX2 *ver) - { - FIXME("ptr %p, ver %p stub!\n", ptr, ver); - memcpy(ver, &version2, sizeof(version2)); -- return 0; -+ return ADL_OK; - } - - int WINAPI ADL_Graphics_Versions_Get(ADLVersionsInfo *ver) - { - FIXME("ver %p stub!\n", ver); - memcpy(ver, &version, sizeof(version)); -- return 0; -+ return ADL_OK; -+} -+ -+int WINAPI ADL_Adapter_NumberOfAdapters_Get(int *count) -+{ -+ FIXME("count %p stub!\n", count); -+ *count = wined3d_get_adapter_count(wined3d); -+ TRACE("*count = %d\n", *count); -+ return ADL_OK; -+} -+ -+static BOOL get_adapter_identifier(int index, struct wined3d_adapter_identifier *identifier) -+{ -+ struct wined3d_adapter *adapter; -+ HRESULT hr; -+ -+ adapter = wined3d_get_adapter(wined3d, index); -+ if (adapter == NULL) -+ return FALSE; -+ -+ memset(identifier, 0, sizeof(*identifier)); -+ hr = wined3d_adapter_get_identifier(adapter, 0, identifier); -+ -+ if (!SUCCEEDED(hr)) -+ return FALSE; -+ -+ return TRUE; -+} -+ -+/* yep, seriously */ -+static int convert_vendor_id(int id) -+{ -+ char str[16]; -+ snprintf(str, ARRAY_SIZE(str), "%x", id); -+ return atoi(str); -+} -+ -+int WINAPI ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo *adapters, int input_size) -+{ -+ int count, i; -+ struct wined3d_adapter_identifier identifier; -+ -+ FIXME("adapters %p, input_size %d, stub!\n", adapters, input_size); -+ -+ count = wined3d_get_adapter_count(wined3d); -+ -+ if (!adapters) return ADL_ERR_INVALID_PARAM; -+ if (input_size != count * sizeof(ADLAdapterInfo)) return ADL_ERR_INVALID_PARAM; -+ -+ memset(adapters, 0, input_size); -+ -+ for (i = 0; i < count; i++) -+ { -+ adapters[i].iSize = sizeof(ADLAdapterInfo); -+ adapters[i].iAdapterIndex = i; -+ -+ if (!get_adapter_identifier(i, &identifier)) -+ return ADL_ERR; -+ -+ adapters[i].iVendorID = convert_vendor_id(identifier.vendor_id); -+ } -+ -+ return ADL_OK; -+} -+ -+int WINAPI ADL_Display_DisplayInfo_Get(int adapter_index, int *num_displays, ADLDisplayInfo **info, int force_detect) -+{ -+ struct wined3d_adapter *adapter; -+ struct wined3d_output *output; -+ int i; -+ -+ FIXME("adapter %d, num_displays %p, info %p stub!\n", adapter_index, num_displays, info); -+ -+ if (info == NULL || num_displays == NULL) return ADL_ERR_NULL_POINTER; -+ -+ adapter = wined3d_get_adapter(wined3d, adapter_index); -+ if (adapter == NULL) return ADL_ERR_INVALID_PARAM; -+ -+ *num_displays = wined3d_adapter_get_output_count(adapter); -+ -+ if (*num_displays == 0) -+ return ADL_OK; -+ -+ *info = adl_malloc(*num_displays * sizeof(**info)); -+ memset(*info, 0, *num_displays * sizeof(**info)); -+ -+ for (i = 0; i < *num_displays; i++) -+ { -+ output = wined3d_adapter_get_output(adapter, i); -+ if (output == NULL) -+ return ADL_ERR; -+ -+ (*info)[i].displayID.iDisplayLogicalIndex = i; -+ (*info)[i].iDisplayInfoValue = ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED | ADL_DISPLAY_DISPLAYINFO_DISPLAYMAPPED; -+ (*info)[i].iDisplayInfoMask = (*info)[i].iDisplayInfoValue; -+ } -+ -+ return ADL_OK; -+} -+ -+int WINAPI ADL_Adapter_Crossfire_Caps(int adapter_index, int *preffered, int *num_comb, ADLCrossfireComb** comb) -+{ -+ FIXME("adapter %d, preffered %p, num_comb %p, comb %p stub!\n", adapter_index, preffered, num_comb, comb); -+ return ADL_ERR; -+} -+ -+int WINAPI ADL_Adapter_Crossfire_Get(int adapter_index, ADLCrossfireComb *comb, ADLCrossfireInfo *info) -+{ -+ FIXME("adapter %d, comb %p, info %p, stub!\n", adapter_index, comb, info); -+ return ADL_ERR; -+} -+ -+int WINAPI ADL_Adapter_ASICFamilyType_Get(int adapter_index, int *asic_type, int *valids) -+{ -+ struct wined3d_adapter_identifier identifier; -+ -+ FIXME("adapter %d, asic_type %p, valids %p, stub!\n", adapter_index, asic_type, valids); -+ -+ if (asic_type == NULL || valids == NULL) -+ return ADL_ERR_NULL_POINTER; -+ -+ if (!get_adapter_identifier(adapter_index, &identifier)) -+ return ADL_ERR_INVALID_ADL_IDX; -+ -+ if (identifier.vendor_id != VENDOR_AMD) -+ return ADL_ERR_NOT_SUPPORTED; -+ -+ *asic_type = ADL_ASIC_DISCRETE; -+ *valids = ADL_ASIC_MASK; -+ -+ return ADL_OK; -+} -+ -+static int get_max_clock(const char *clock, int default_value) -+{ -+ char path[MAX_PATH], line[256]; -+ FILE *file; -+ int drm_card, value = 0; -+ -+ for (drm_card = 0; drm_card < MAX_GPUS; drm_card++) -+ { -+ sprintf(path, "/sys/class/drm/card%d/device/pp_dpm_%s", drm_card, clock); -+ file = fopen(path, "r"); -+ -+ if (file == NULL) -+ continue; -+ -+ while (fgets(line, sizeof(line), file) != NULL) -+ { -+ char *number; -+ -+ number = strchr(line, ' '); -+ if (number == NULL) -+ { -+ WARN("pp_dpm_%s file has unexpected format\n", clock); -+ break; -+ } -+ -+ number++; -+ value = max(strtol(number, NULL, 0), value); -+ } -+ } -+ -+ if (value != 0) -+ return value; -+ -+ return default_value; -+} -+ -+/* documented in the "Linux Specific APIs" section, present and used on Windows */ -+/* the name and documentation suggests that this returns current freqs, but it's actually max */ -+int WINAPI ADL_Adapter_ObservedClockInfo_Get(int adapter_index, int *core_clock, int *memory_clock) -+{ -+ struct wined3d_adapter_identifier identifier; -+ -+ FIXME("adapter %d, core_clock %p, memory_clock %p, stub!\n", adapter_index, core_clock, memory_clock); -+ -+ if (core_clock == NULL || memory_clock == NULL) return ADL_ERR; -+ if (!get_adapter_identifier(adapter_index, &identifier)) return ADL_ERR; -+ if (identifier.vendor_id != VENDOR_AMD) return ADL_ERR_INVALID_ADL_IDX; -+ -+ /* default values based on RX580 */ -+ *core_clock = get_max_clock("sclk", 1350); -+ *memory_clock = get_max_clock("mclk", 2000); -+ -+ TRACE("*core_clock: %i, *memory_clock %i\n", *core_clock, *memory_clock); -+ -+ return ADL_OK; -+} -+ -+/* documented in the "Linux Specific APIs" section, present and used on Windows */ -+int WINAPI ADL_Adapter_MemoryInfo_Get(int adapter_index, ADLMemoryInfo *mem_info) -+{ -+ struct wined3d_adapter_identifier identifier; -+ -+ FIXME("adapter %d, mem_info %p stub!\n", adapter_index, mem_info); -+ -+ if (mem_info == NULL) return ADL_ERR_NULL_POINTER; -+ if (!get_adapter_identifier(adapter_index, &identifier)) return ADL_ERR_INVALID_ADL_IDX; -+ if (identifier.vendor_id != VENDOR_AMD) return ADL_ERR; -+ -+ mem_info->iMemorySize = identifier.video_memory; -+ mem_info->iMemoryBandwidth = 256000; /* not exposed on Linux, probably needs a lookup table */ -+ -+ TRACE("iMemoryBandwidth %lli, iMemorySize %lli\n", mem_info->iMemoryBandwidth, mem_info->iMemorySize); -+ return ADL_OK; -+} -+ -+int WINAPI ADL_Graphics_Platform_Get(int *platform) -+{ -+ struct wined3d_adapter_identifier identifier; -+ int count, i; -+ -+ FIXME("platform %p, stub!\n", platform); -+ -+ *platform = GRAPHICS_PLATFORM_UNKNOWN; -+ -+ count = wined3d_get_adapter_count(wined3d); -+ -+ for (i = 0; i < count; i ++) -+ { -+ if (!get_adapter_identifier(i, &identifier)) -+ continue; -+ -+ if (identifier.vendor_id == VENDOR_AMD) -+ *platform = GRAPHICS_PLATFORM_DESKTOP; -+ } -+ -+ /* NOTE: The real value can be obtained by doing: -+ * 1. ioctl(DRM_AMDGPU_INFO) with AMDGPU_INFO_DEV_INFO - dev_info.ids_flags & AMDGPU_IDS_FLAGS_FUSION -+ * 2. VkPhysicalDeviceType() if we ever switch to wined3d vk adapter implementation -+ */ -+ -+ return ADL_OK; - } diff --git a/patches/proton/21-proton-01_wolfenstein2_registry.patch b/patches/proton/21-proton-01_wolfenstein2_registry.patch deleted file mode 100755 index b46b60ccd..000000000 --- a/patches/proton/21-proton-01_wolfenstein2_registry.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 161926d7c122878231bc320a7ee7a2396634cd97 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 24 Jul 2018 13:33:15 -0500 -Subject: [PATCH] wine.inf: Set amd_ags_x64 to built-in for Wolfenstein 2 - ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 988e8598214..645b66c6dd9 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4397,6 +4397,8 @@ HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll",,"%16426%\Steam\steamcl - HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steamclient64.dll" - HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" - HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" -+HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" -+HKCU,Software\Wine\AppDefaults\Youngblood_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" diff --git a/patches/proton/22-proton-02_rdr2_registry.patch b/patches/proton/22-proton-02_rdr2_registry.patch deleted file mode 100755 index d38e898e6..000000000 --- a/patches/proton/22-proton-02_rdr2_registry.patch +++ /dev/null @@ -1,23 +0,0 @@ -From c71b813d33ec2ca21ae91467e3da976b8ea1b2ac Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Fri, 31 Jul 2020 15:33:57 -0700 -Subject: [PATCH] wine.inf: Set amd_ags_x64 to built-in for Red Dead Redemption - 2 - ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index f474157a4d3..a66b740442c 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4007,6 +4007,7 @@ HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steam - HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" - HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - HKCU,Software\Wine\AppDefaults\Youngblood_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" -+HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" - diff --git a/patches/proton/23-proton-03_nier_sekiro_ds3_registry.patch b/patches/proton/23-proton-03_nier_sekiro_ds3_registry.patch deleted file mode 100755 index 0cc0c097f..000000000 --- a/patches/proton/23-proton-03_nier_sekiro_ds3_registry.patch +++ /dev/null @@ -1,25 +0,0 @@ -From ac123a40c68f5cfa50dc40ed99015f27b0b88e09 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 8 Sep 2020 09:46:28 -0500 -Subject: [PATCH] HACK: wine.inf: Limit resolution count for some games - -These games have a bug where they crash with more than about 32 -resolutions. This happens even on Windows. ---- - loader/wine.inf.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 8bf517ef4fc..ea36defaa91 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4010,6 +4010,9 @@ HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" - HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - HKCU,Software\Wine\AppDefaults\Youngblood_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" -+HKCU,Software\Wine\AppDefaults\DarkSoulsIII.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" -+HKCU,Software\Wine\AppDefaults\sekiro.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" -+HKCU,Software\Wine\AppDefaults\NieRAutomata.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" diff --git a/patches/proton/24-proton-04_cod_registry.patch b/patches/proton/24-proton-04_cod_registry.patch deleted file mode 100755 index ecdc53287..000000000 --- a/patches/proton/24-proton-04_cod_registry.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 00c2f024af63e27508d025ba22bb776eb57fddaa Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 9 Sep 2020 11:03:09 -0500 -Subject: [PATCH] HACK: wine.inf: Enable builtin atiadlxx for Call of Duty - games. - -The games call several functions from this DLL to check driver version, -which we stub to some acceptable value to avoid warnings. ---- - loader/wine.inf.in | 6 ++++ - 1 file changed, 6 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index fd0e80230af..26275c4d459 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4404,6 +4404,12 @@ HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin, - HKCU,Software\Wine\AppDefaults\DarkSoulsIII.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" - HKCU,Software\Wine\AppDefaults\sekiro.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" - HKCU,Software\Wine\AppDefaults\NieRAutomata.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" -+HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\h1_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\h1_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\iw7_ship.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" diff --git a/patches/proton/25-proton-rdr2-fixes.patch b/patches/proton/25-proton-rdr2-fixes.patch deleted file mode 100644 index f2d923c58..000000000 --- a/patches/proton/25-proton-rdr2-fixes.patch +++ /dev/null @@ -1,190 +0,0 @@ -From 2ec8739c7440157e189b762b486433697fee06e3 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Wed, 5 Aug 2020 14:26:23 -0700 -Subject: [PATCH] HACK: ntdll: Support x86_64 syscall emulation for Red Dead - Redemption 2. - ---- - dlls/ntdll/unix/signal_x86_64.c | 125 +++++++++++++++++++++++++++++--- - 1 file changed, 115 insertions(+), 10 deletions(-) - -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 33ad0489006..66fadacf920 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -2368,6 +2368,63 @@ static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) - - ctx->uc_mcontext.gregs[REG_RIP] = *dispatcher_address; - } -+ -+unsigned int __wine_syscall_nr_NtClose; -+unsigned int __wine_syscall_nr_NtCreateFile; -+unsigned int __wine_syscall_nr_NtGetContextThread; -+unsigned int __wine_syscall_nr_NtQueryInformationProcess; -+unsigned int __wine_syscall_nr_NtQuerySystemInformation; -+unsigned int __wine_syscall_nr_NtQueryVirtualMemory; -+unsigned int __wine_syscall_nr_NtReadFile; -+unsigned int __wine_syscall_nr_NtWriteFile; -+ -+static void sigsys_handler_rdr2( int signal, siginfo_t *siginfo, void *sigcontext ) -+{ -+ ULONG64 *dispatcher_address = (ULONG64 *)((char *)user_shared_data + page_size); -+ ucontext_t *ctx = sigcontext; -+ void ***rsp; -+ -+ TRACE("SIGSYS, rax %#llx, rip %#llx.\n", ctx->uc_mcontext.gregs[REG_RAX], -+ ctx->uc_mcontext.gregs[REG_RIP]); -+ -+ rsp = (void ***)&ctx->uc_mcontext.gregs[REG_RSP]; -+ *rsp -= 1; -+ **rsp = (void *)(ctx->uc_mcontext.gregs[REG_RIP] + 0xb); -+ -+ ctx->uc_mcontext.gregs[REG_RIP] = *dispatcher_address; -+ -+ /* syscall numbers are for Windows 10 1809 (build 17763) */ -+ switch (ctx->uc_mcontext.gregs[REG_RAX]) -+ { -+ case 0x19: -+ ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtQueryInformationProcess; -+ break; -+ case 0x36: -+ ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtQuerySystemInformation; -+ break; -+ case 0xec: -+ ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtGetContextThread; -+ break; -+ case 0x55: -+ ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtCreateFile; -+ break; -+ case 0x08: -+ ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtWriteFile; -+ break; -+ case 0x06: -+ ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtReadFile; -+ break; -+ case 0x0f: -+ ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtClose; -+ break; -+ case 0x23: -+ ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtQueryVirtualMemory; -+ break; -+ default: -+ FIXME("Unhandled syscall %#llx.\n", ctx->uc_mcontext.gregs[REG_RAX]); -+ break; -+ } -+} - #endif - - #ifdef HAVE_SECCOMP -@@ -2428,31 +2486,79 @@ static void install_bpf(struct sigaction *sig_act) - BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), - BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), - }; -+ static struct sock_filter filter_rdr2[] = -+ { -+ /* Trap anything called from RDR2 or the launcher (0x140000000 - 0x150000000)*/ -+ /* > 0x140000000 */ -+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 0), -+ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x40000000 /*lsb*/, 0, 7), -+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 4), -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x1 /*msb*/, 0, 5), -+ -+ /* < 0x150000000 */ -+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 0), -+ BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, 0x50000000 /*lsb*/, 3, 0), -+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 4), -+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x1 /*msb*/, 0, 1), -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), -+ -+ /* Allow everything else */ -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -+ }; - struct syscall_frame *frame = amd64_thread_data()->syscall_frame; - struct sock_fprog prog; -+ BOOL rdr2 = FALSE; - NTSTATUS status; - - sig_act->sa_sigaction = sigsys_handler; -+ memset(&prog, 0, sizeof(prog)); -+ -+ { -+ const char *sgi = getenv("SteamGameId"); -+ if (sgi && (!strcmp(sgi, "1174180") || !strcmp(sgi, "1404210"))) -+ { -+ /* Use specific filter and signal handler for Red Dead Redemption 2 */ -+ prog.len = ARRAY_SIZE(filter_rdr2); -+ prog.filter = filter_rdr2; -+ sig_act->sa_sigaction = sigsys_handler_rdr2; -+ rdr2 = TRUE; -+ } -+ } -+ - sigaction(SIGSYS, sig_act, NULL); - - frame->syscall_flags = syscall_flags; - frame->syscall_table = KeServiceDescriptorTable; - -- if ((status = syscall(0xffff)) == STATUS_INVALID_PARAMETER) -+ if (rdr2) - { -- TRACE("Seccomp filters already installed.\n"); -- return; -+ int ret; -+ -+ if ((ret = prctl(PR_GET_SECCOMP, 0, NULL, 0, 0))) -+ { -+ if (ret == 2) -+ TRACE("Seccomp filters already installed.\n"); -+ else -+ ERR("Seccomp filters cannot be installed, ret %d, error %s.\n", ret, strerror(errno)); -+ return; -+ } - } -- if (status != -ENOSYS && (status != -1 || errno != ENOSYS)) -+ else - { -- ERR("Unexpected status %#x, errno %d.\n", status, errno); -- return; -+ if ((status = syscall(0xffff)) == STATUS_INVALID_PARAMETER) -+ { -+ TRACE("Seccomp filters already installed.\n"); -+ return; -+ } -+ if (status != -ENOSYS && (status != -1 || errno != ENOSYS)) -+ { -+ ERR("Unexpected status %#x, errno %d.\n", status, errno); -+ return; -+ } -+ prog.len = ARRAY_SIZE(filter); -+ prog.filter = filter; - } - -- memset(&prog, 0, sizeof(prog)); -- prog.len = ARRAY_SIZE(filter); -- prog.filter = filter; -- - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) - { - ERR("prctl(PR_SET_NO_NEW_PRIVS, ...): %s.\n", strerror(errno)); -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index a177ee862c4..df6f747b159 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -2411,7 +2411,7 @@ static void sigsys_handler_rdr2( int signal, siginfo_t *siginfo, void *sigcontex - - ctx->uc_mcontext.gregs[REG_RIP] = *dispatcher_address; - -- /* syscall numbers are for Windows 10 1809 (build 17763) */ -+ /* syscall numbers are for Windows 10 1909 (build 18363) */ - switch (ctx->uc_mcontext.gregs[REG_RAX]) - { - case 0x19: -@@ -2420,7 +2420,7 @@ static void sigsys_handler_rdr2( int signal, siginfo_t *siginfo, void *sigcontex - case 0x36: - ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtQuerySystemInformation; - break; -- case 0xec: -+ case 0xed: - ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtGetContextThread; - break; - case 0x55: diff --git a/patches/proton/28-proton-win10_default.patch b/patches/proton/28-proton-win10_default.patch deleted file mode 100755 index 33f778725..000000000 --- a/patches/proton/28-proton-win10_default.patch +++ /dev/null @@ -1,454 +0,0 @@ -From 982ed53412eb83693f4cedca4a051d8fddca354b Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 23 Jan 2020 09:14:56 -0600 -Subject: [PATCH] wine.inf: Set default Windows version to win10. - ---- - dlls/ntdll/version.c | 2 +- - loader/wine.inf.in | 24 ++++++++++++------------ - programs/winecfg/appdefaults.c | 2 +- - 3 files changed, 14 insertions(+), 14 deletions(-) - -diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c -index 61e48f6fbd0..875a33c5b2b 100644 ---- a/dlls/ntdll/version.c -+++ b/dlls/ntdll/version.c -@@ -483,7 +483,7 @@ void version_init(void) - const WCHAR *p, *appname = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; - WCHAR appversion[MAX_PATH+20]; - -- current_version = &VersionData[WIN7]; -+ current_version = &VersionData[WIN10]; - - RtlOpenCurrentUser( KEY_ALL_ACCESS, &root ); - attr.Length = sizeof(attr); -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 1aa0a37338b..99a4844eabe 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -3767,12 +3767,10 @@ HKLM,"System\CurrentControlSet\Services\Winsock\Parameters",,16 - HKLM,"System\CurrentControlSet\Services\Winsock2\Parameters\Protocol_Catalog9\Catalog_Entries",,16 - - [VersionInfo] --HKLM,%CurrentVersionNT%,"CurrentVersion",2,"6.1" --HKLM,%CurrentVersionNT%,"CurrentMajorVersionNumber",0x10001,6 --HKLM,%CurrentVersionNT%,"CurrentMinorVersionNumber",0x10001,1 --HKLM,%CurrentVersionNT%,"CSDVersion",2,"Service Pack 1" --HKLM,%CurrentVersionNT%,"CurrentBuild",2,"7601" --HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"7601" -+HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" -+HKLM,%CurrentVersionNT%,"CSDVersion",2,"" -+HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17134" -+HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17134" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" - HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -@@ -3779,16 +3779,16 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 --HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 7" -+HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" - HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" --HKLM,%Control%\Windows,"CSDVersion",0x10003,0x100 -+HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 - HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" - - [VersionInfo.ntamd64] --HKLM,%CurrentVersionNT%,"CurrentVersion",2,"6.1" --HKLM,%CurrentVersionNT%,"CSDVersion",2,"Service Pack 1" --HKLM,%CurrentVersionNT%,"CurrentBuild",2,"7601" --HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"7601" -+HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" -+HKLM,%CurrentVersionNT%,"CSDVersion",2,"" -+HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17134" -+HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17134" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" - HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -@@ -3797,9 +3797,9 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 --HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 7" -+HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" - HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" --HKLM,%Control%\Windows,"CSDVersion",0x10003,0x100 -+HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 - HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" - - [Wow64] -diff --git a/programs/winecfg/appdefaults.c b/programs/winecfg/appdefaults.c -index 6c4e6a49f26..1aea54adfb2 100644 ---- a/programs/winecfg/appdefaults.c -+++ b/programs/winecfg/appdefaults.c -@@ -74,7 +74,7 @@ static const struct win_version win_versions[] = - #endif - }; - --#define DEFAULT_WIN_VERSION L"win7" -+#define DEFAULT_WIN_VERSION L"win10" - - static const WCHAR szKey9x[] = L"Software\\Microsoft\\Windows\\CurrentVersion"; - static const WCHAR szKeyNT[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion"; -From b3ed562a02c30730a4472b966057d2c97ce294a7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 14 Jul 2020 18:43:17 +0200 -Subject: [PATCH] wine.inf: Bump CurrentBuild(Number) to 17763 (Win10 1809). - ---- - loader/wine.inf.in | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 0b014dce63c..12ec40f872e 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -3758,8 +3758,8 @@ HKLM,"System\CurrentControlSet\Services\Winsock2\Parameters\Protocol_Catalog9\Ca - [VersionInfo] - HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" - HKLM,%CurrentVersionNT%,"CSDVersion",2,"" --HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17134" --HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17134" -+HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17763" -+HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17763" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" - HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -@@ -3776,8 +3776,8 @@ HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" - [VersionInfo.ntamd64] - HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" - HKLM,%CurrentVersionNT%,"CSDVersion",2,"" --HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17134" --HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17134" -+HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17763" -+HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17763" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" - HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -From e9264df6e63b5df87d81e950675df7290ad43615 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Wed, 15 Jul 2020 14:57:28 -0500 -Subject: [PATCH] wineboot: On prefix upgrade, update win10 build number - -Some games (Death Stranding) require later build numbers than we had -shipped earlier. So fix it up on existing prefixes. ---- - programs/wineboot/wineboot.c | 38 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 38 insertions(+) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 569db5ee94d..a0a72040843 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -1451,6 +1451,43 @@ static void update_user_profile(void) - LocalFree(sid); - } - -+static void update_win_version(void) -+{ -+ static const WCHAR win10_buildW[] = L"17763"; -+ -+ HKEY cv_h; -+ DWORD type, sz; -+ WCHAR current_version[256]; -+ -+ if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion", -+ 0, KEY_ALL_ACCESS, &cv_h) == ERROR_SUCCESS){ -+ /* get the current windows version */ -+ sz = sizeof(current_version); -+ if(RegQueryValueExW(cv_h, L"CurrentVersion", NULL, &type, (BYTE *)current_version, &sz) == ERROR_SUCCESS && -+ type == REG_SZ){ -+ if(!wcscmp(current_version, L"10.0")){ -+ RegSetValueExW(cv_h, L"CurrentBuild", 0, REG_SZ, (const BYTE *)win10_buildW, sizeof(win10_buildW)); -+ RegSetValueExW(cv_h, L"CurrentBuildNumber", 0, REG_SZ, (const BYTE *)win10_buildW, sizeof(win10_buildW)); -+ } -+ } -+ RegCloseKey(cv_h); -+ } -+ -+ if(RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion", -+ 0, KEY_ALL_ACCESS, &cv_h) == ERROR_SUCCESS){ -+ /* get the current windows version */ -+ sz = sizeof(current_version); -+ if(RegQueryValueExW(cv_h, L"CurrentVersion", NULL, &type, (BYTE *)current_version, &sz) == ERROR_SUCCESS && -+ type == REG_SZ){ -+ if(!wcscmp(current_version, L"10.0")){ -+ RegSetValueExW(cv_h, L"CurrentBuild", 0, REG_SZ, (const BYTE *)win10_buildW, sizeof(win10_buildW)); -+ RegSetValueExW(cv_h, L"CurrentBuildNumber", 0, REG_SZ, (const BYTE *)win10_buildW, sizeof(win10_buildW)); -+ } -+ } -+ RegCloseKey(cv_h); -+ } -+} -+ - /* execute rundll32 on the wine.inf file if necessary */ - static void update_wineprefix( BOOL force ) - { -@@ -1496,6 +1533,7 @@ static void update_wineprefix( BOOL force ) - } - install_root_pnp_devices(); - update_user_profile(); -+ update_win_version(); - - WINE_MESSAGE( "wine: configuration in %s has been updated.\n", debugstr_w(prettyprint_configdir()) ); - } -From e3f3c07144cda0c4aa25a3d104ca76c17e36bfdf Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 14 Sep 2021 23:03:54 +0300 -Subject: [PATCH] Bump current build number to 18363 (Win10 1909). - -CW-Bug-ID: #19427 - -For DeathLoop. ---- - dlls/kernel32/version.rc | 8 ++++---- - dlls/kernelbase/version.c | 2 +- - dlls/ntdll/unix/signal_x86_64.c | 4 ++-- - loader/wine.inf.in | 8 ++++---- - programs/wineboot/wineboot.c | 2 +- - 5 files changed, 12 insertions(+), 12 deletions(-) - -diff --git a/dlls/kernel32/version.rc b/dlls/kernel32/version.rc -index b6002f51f7a..c58acb8a8b6 100644 ---- a/dlls/kernel32/version.rc -+++ b/dlls/kernel32/version.rc -@@ -26,9 +26,9 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT - #define WINE_FILENAME_STR "kernel32.dll" - - /* these values come from Windows 10 Version 1909 */ --#define WINE_FILEVERSION 10,0,18362,1350 --#define WINE_FILEVERSION_STR "10.0.18362.1350" --#define WINE_PRODUCTVERSION 10,0,18362,1350 --#define WINE_PRODUCTVERSION_STR "10.0.18362.1350" -+#define WINE_FILEVERSION 10,0,18363,900 -+#define WINE_FILEVERSION_STR "10.0.18363.900" -+#define WINE_PRODUCTVERSION 10,0,18363,900 -+#define WINE_PRODUCTVERSION_STR "10.0.18363.900" - - #include "wine/wine_common_ver.rc" -diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c -index bd878cb324d..febb78d94e9 100644 ---- a/dlls/kernelbase/version.c -+++ b/dlls/kernelbase/version.c -@@ -151,7 +151,7 @@ static const struct - }, - /* Windows 10 */ - { -- { 10, 0, 18362 }, -+ { 10, 0, 0x47bb }, - {0x8e0f7a12,0xbfb3,0x4fe8,{0xb9,0xa5,0x48,0xfd,0x50,0xa1,0x5a,0x9a}} - } - }; -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 4853db16e77..faba4be0b91 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -3970,8 +3970,8 @@ HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" - HKLM,%CurrentVersionNT%,"CurrentMajorVersionNumber",0x10001,10 - HKLM,%CurrentVersionNT%,"CurrentMinorVersionNumber",0x10001,0 - HKLM,%CurrentVersionNT%,"CSDVersion",2,"" --HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17763" --HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17763" -+HKLM,%CurrentVersionNT%,"CurrentBuild",2,"18363" -+HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"18363" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" - HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -@@ -3988,8 +3988,8 @@ HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" - [VersionInfo.ntamd64] - HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" - HKLM,%CurrentVersionNT%,"CSDVersion",2,"" --HKLM,%CurrentVersionNT%,"CurrentBuild",2,"17763" --HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"17763" -+HKLM,%CurrentVersionNT%,"CurrentBuild",2,"18363" -+HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"18363" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" - HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index f78d4bdae25..eb69a5941a9 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -1706,7 +1706,7 @@ static void update_user_profile(void) - - static void update_win_version(void) - { -- static const WCHAR win10_buildW[] = L"17763"; -+ static const WCHAR win10_buildW[] = L"18363"; - - HKEY cv_h; - DWORD type, sz; -From 7381437f853f4a1706ff80aa74860fc5366f2fd0 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 29 Sep 2021 14:39:06 +0300 -Subject: [PATCH] wine.inf: Add ReleaseId value to %CurrentVersionNT%. - -CW-Bug-Id: #19484 ---- - loader/wine.inf.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 2db2abab2d8..1cfe19dace6 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -3976,6 +3976,7 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 - HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" -+HKLM,%CurrentVersionNT%,"ReleaseId",,"1909" - HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" - HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 - HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" -@@ -3994,6 +3995,7 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 - HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" -+HKLM,%CurrentVersionNT%,"ReleaseId",,"1909" - HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" - HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 - HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" -From 2a13d89fe5453378c2f01717bce38f21ac008a77 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 14 Jan 2022 11:46:04 +0300 -Subject: [PATCH] Bump current build number to 19043 (Win10 2009). - ---- - dlls/kernel32/version.rc | 10 +++++----- - dlls/kernelbase/version.c | 2 +- - dlls/ntdll/unix/signal_x86_64.c | 4 ++-- - dlls/ntdll/version.c | 2 +- - loader/wine.inf.in | 14 ++++++++------ - programs/wineboot/wineboot.c | 2 +- - 6 files changed, 18 insertions(+), 16 deletions(-) - -diff --git a/dlls/kernel32/version.rc b/dlls/kernel32/version.rc -index c58acb8a8b6..f91262dfa8e 100644 ---- a/dlls/kernel32/version.rc -+++ b/dlls/kernel32/version.rc -@@ -25,10 +25,10 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT - #define WINE_FILEDESCRIPTION_STR "Wine kernel DLL" - #define WINE_FILENAME_STR "kernel32.dll" - --/* these values come from Windows 10 Version 1909 */ --#define WINE_FILEVERSION 10,0,18363,900 --#define WINE_FILEVERSION_STR "10.0.18363.900" --#define WINE_PRODUCTVERSION 10,0,18363,900 --#define WINE_PRODUCTVERSION_STR "10.0.18363.900" -+/* these values come from Windows 10 Version 2009 */ -+#define WINE_FILEVERSION 10,0,19043,1466 -+#define WINE_FILEVERSION_STR "10.0.19043.1466" -+#define WINE_PRODUCTVERSION 10,0,19043,1466 -+#define WINE_PRODUCTVERSION_STR "10.0.19043.1466" - - #include "wine/wine_common_ver.rc" -diff --git a/dlls/kernelbase/version.c b/dlls/kernelbase/version.c -index 7b84167d6a9..19631f8cc06 100644 ---- a/dlls/kernelbase/version.c -+++ b/dlls/kernelbase/version.c -@@ -158,7 +158,7 @@ static const struct - }, - /* Windows 10 */ - { -- { 10, 0, 0x47bb }, -+ { 10, 0, 0x4a63 }, - {0x8e0f7a12,0xbfb3,0x4fe8,{0xb9,0xa5,0x48,0xfd,0x50,0xa1,0x5a,0x9a}} - } - }; -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 34284b883b6..30c4d78e928 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -2435,7 +2435,7 @@ static void sigsys_handler_rdr2( int signal, siginfo_t *siginfo, void *sigcontex - - ctx->uc_mcontext.gregs[REG_RIP] = *dispatcher_address; - -- /* syscall numbers are for Windows 10 1909 (build 18363) */ -+ /* syscall numbers are for Windows 10 2009 (build 19043) */ - switch (ctx->uc_mcontext.gregs[REG_RAX]) - { - case 0x19: -@@ -2444,7 +2444,7 @@ static void sigsys_handler_rdr2( int signal, siginfo_t *siginfo, void *sigcontex - case 0x36: - ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtQuerySystemInformation; - break; -- case 0xed: -+ case 0xf2: - ctx->uc_mcontext.gregs[REG_RAX] = __wine_syscall_nr_NtGetContextThread; - break; - case 0x55: -diff --git a/dlls/ntdll/version.c b/dlls/ntdll/version.c -index 8ada78255d6..8099383e0ff 100644 ---- a/dlls/ntdll/version.c -+++ b/dlls/ntdll/version.c -@@ -167,7 +167,7 @@ static const RTL_OSVERSIONINFOEXW VersionData[NB_WINDOWS_VERSIONS] = - }, - /* WIN10 */ - { -- sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 18362, VER_PLATFORM_WIN32_NT, -+ sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 0x4a63, VER_PLATFORM_WIN32_NT, - L"", 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0 - }, - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index a23878697a9..641f6f80a1d 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -3968,8 +3968,8 @@ HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" - HKLM,%CurrentVersionNT%,"CurrentMajorVersionNumber",0x10001,10 - HKLM,%CurrentVersionNT%,"CurrentMinorVersionNumber",0x10001,0 - HKLM,%CurrentVersionNT%,"CSDVersion",2,"" --HKLM,%CurrentVersionNT%,"CurrentBuild",2,"18363" --HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"18363" -+HKLM,%CurrentVersionNT%,"CurrentBuild",2,"19043" -+HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"19043" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" - HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -@@ -3978,8 +3978,9 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 -+HKLM,%CurrentVersionNT%,"DisplayVersion",2,"21H1" - HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" --HKLM,%CurrentVersionNT%,"ReleaseId",,"1909" -+HKLM,%CurrentVersionNT%,"ReleaseId",,"2009" - HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" - HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 - HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" -@@ -3987,8 +3988,8 @@ HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" - [VersionInfo.ntamd64] - HKLM,%CurrentVersionNT%,"CurrentVersion",2,"10.0" - HKLM,%CurrentVersionNT%,"CSDVersion",2,"" --HKLM,%CurrentVersionNT%,"CurrentBuild",2,"18363" --HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"18363" -+HKLM,%CurrentVersionNT%,"CurrentBuild",2,"19043" -+HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"19043" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" - HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -@@ -3997,8 +3998,9 @@ HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 -+HKLM,%CurrentVersionNT%,"DisplayVersion",2,"21H1" - HKLM,%CurrentVersionNT%,"ProductName",2,"Microsoft Windows 10" --HKLM,%CurrentVersionNT%,"ReleaseId",,"1909" -+HKLM,%CurrentVersionNT%,"ReleaseId",,"2009" - HKLM,%Control%\ProductOptions,"ProductType",2,"WinNT" - HKLM,%Control%\Windows,"CSDVersion",0x10003,0x0 - HKLM,%Control%\Session Manager\Environment,"OS",2,"Windows_NT" -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 0e455223cb9..19d1af6f589 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -1621,7 +1621,7 @@ static void update_user_profile(void) - - static void update_win_version(void) - { -- static const WCHAR win10_buildW[] = L"18363"; -+ static const WCHAR win10_buildW[] = L"19043"; - - HKEY cv_h; - DWORD type, sz; diff --git a/patches/proton/29-proton-dxvk_config.patch b/patches/proton/29-proton-dxvk_config.patch deleted file mode 100755 index 33961a4c3..000000000 --- a/patches/proton/29-proton-dxvk_config.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 84d73a7fa55c13ed797b2b2f6cfb9071dceac800 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 21 Oct 2019 15:30:33 -0500 -Subject: [PATCH] wined3d: Use dxvk_config library to load DXVK options - ---- - dlls/wined3d/directx.c | 56 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 56 insertions(+) - -diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c -index 12b53f75774..6f132ea047a 100644 ---- a/dlls/wined3d/directx.c -+++ b/dlls/wined3d/directx.c -@@ -1326,11 +1326,44 @@ HRESULT CDECL wined3d_set_adapter_display_mode(struct wined3d *wined3d, - return WINED3D_OK; - } - -+/* from dxvk_config.h, not available at wine build time in Proton */ -+struct DXVKOptions { -+ int32_t customVendorId; -+ int32_t customDeviceId; -+ int32_t nvapiHack; -+}; -+static HRESULT (WINAPI *pDXVKGetOptions)(struct DXVKOptions *out_opts); -+static HMODULE dxvk_config_mod; -+ -+static BOOL WINAPI load_dxvk_config(INIT_ONCE *once, void *param, void **context) -+{ -+ dxvk_config_mod = LoadLibraryA("dxvk_config.dll"); -+ if(!dxvk_config_mod) -+ { -+ ERR_(winediag)("Couldn't load dxvk_config.dll, won't apply default DXVK config options\n"); -+ return TRUE; -+ } -+ -+ pDXVKGetOptions = (void*)GetProcAddress(dxvk_config_mod, "DXVKGetOptions"); -+ if(!pDXVKGetOptions) -+ { -+ ERR_(winediag)("dxvk_config doesn't have DXVKGetOptions?!\n"); -+ return TRUE; -+ } -+ -+ return TRUE; -+} -+ - HRESULT CDECL wined3d_adapter_get_identifier(const struct wined3d_adapter *adapter, - DWORD flags, struct wined3d_adapter_identifier *identifier) - { -+ static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; -+ struct DXVKOptions dxvk_opts; -+ - TRACE("adapter %p, flags %#x, identifier %p.\n", adapter, flags, identifier); - -+ InitOnceExecuteOnce(&init_once, load_dxvk_config, NULL, NULL); -+ - wined3d_mutex_lock(); - - wined3d_copy_name(identifier->driver, adapter->driver_info.name, identifier->driver_size); -@@ -1359,6 +1391,30 @@ HRESULT CDECL wined3d_get_adapter_identifier(const struct wined3d *wined3d, - identifier->driver_version.u.LowPart = adapter->driver_info.version_low; - identifier->vendor_id = adapter->driver_info.vendor; - identifier->device_id = adapter->driver_info.device; -+ -+ if(pDXVKGetOptions && pDXVKGetOptions(&dxvk_opts) == S_OK) -+ { -+ TRACE("got dxvk options:\n"); -+ TRACE("\tnvapiHack: %u\n", dxvk_opts.nvapiHack); -+ TRACE("\tcustomVendorId: 0x%04x\n", dxvk_opts.customVendorId); -+ TRACE("\tcustomDeviceId: 0x%04x\n", dxvk_opts.customDeviceId); -+ -+ /* logic from dxvk/src/dxgi/dxgi_adapter.cpp:DxgiAdapter::GetDesc2 */ -+ if (dxvk_opts.customVendorId >= 0) -+ identifier->vendor_id = dxvk_opts.customVendorId; -+ -+ if (dxvk_opts.customDeviceId >= 0) -+ identifier->device_id = dxvk_opts.customDeviceId; -+ -+ if (dxvk_opts.customVendorId < 0 && dxvk_opts.customDeviceId < 0 && -+ dxvk_opts.nvapiHack && adapter->driver_info.vendor == HW_VENDOR_NVIDIA) { -+ TRACE("NvAPI workaround enabled, reporting AMD GPU\n"); -+ identifier->vendor_id = HW_VENDOR_AMD; -+ identifier->device_id = CARD_AMD_RADEON_RX_480; -+ } -+ }else -+ WARN("failed to get DXVK options!\n"); -+ - identifier->subsystem_id = 0; - identifier->revision = 0; - identifier->device_identifier = IID_D3DDEVICE_D3DUID; - diff --git a/patches/proton/30-proton-mediafoundation_dllreg.patch b/patches/proton/30-proton-mediafoundation_dllreg.patch deleted file mode 100755 index dc9675436..000000000 --- a/patches/proton/30-proton-mediafoundation_dllreg.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 1fc78e8b3ea44a4edebe2ca5f5170ae948adc644 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 30 Jan 2020 10:16:19 -0600 -Subject: [PATCH] winegstreamer: HACK: Use a different gst registry file per - architecture - ---- - dlls/winegstreamer/wg_parser.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 013566b25e9..0a6cf927187 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1949,6 +1949,22 @@ static void init_gstreamer_once(void) - int argc = ARRAY_SIZE(args) - 1; - char **argv = args; - GError *err; -+ const char *e; -+ -+ if ((e = getenv("WINE_GST_REGISTRY_DIR"))) -+ { -+ char gst_reg[PATH_MAX]; -+#if defined(__x86_64__) -+ const char *arch = "/registry.x86_64.bin"; -+#elif defined(__i386__) -+ const char *arch = "/registry.i386.bin"; -+#else -+#error Bad arch -+#endif -+ strcpy(gst_reg, e); -+ strcat(gst_reg, arch); -+ setenv("GST_REGISTRY_1_0", gst_reg, 1); -+ } - - if (!gst_init_check(&argc, &argv, &err)) - { - -From 77946e9d0ff393ac66eda8d11a3aa22204d4ad53 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Tue, 28 Jan 2020 14:30:43 -0600 -Subject: [PATCH] winegstreamer: HACK: Try harder to register winegstreamer - filters. - ---- - dlls/quartz/filtergraph.c | 17 +++++++++++++++++ - dlls/winegstreamer/main.c | 2 ++ - 2 files changed, 19 insertions(+) - -diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c -index d20687c1b38..62d22f96cea 100644 ---- a/dlls/quartz/filtergraph.c -+++ b/dlls/quartz/filtergraph.c -@@ -5584,11 +5584,28 @@ static const IUnknownVtbl IInner_VTable = - FilterGraphInner_Release - }; - -+static BOOL CALLBACK register_winegstreamer_proc(INIT_ONCE *once, void *param, void **ctx) -+{ -+ HMODULE mod = LoadLibraryW(L"winegstreamer.dll"); -+ if (mod) -+ { -+ HRESULT (WINAPI *proc)(void) = (void *)GetProcAddress(mod, "DllRegisterServer"); -+ proc(); -+ FreeLibrary(mod); -+ } -+ return TRUE; -+} -+ - static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL threaded) - { -+ static INIT_ONCE once = INIT_ONCE_STATIC_INIT; - struct filter_graph *object; - HRESULT hr; - -+ /* HACK: our build system makes it difficult to load gstreamer on prefix -+ * creation, so it won't get registered. Do that here instead. */ -+ InitOnceExecuteOnce(&once, register_winegstreamer_proc, NULL, NULL); -+ - *out = NULL; - - if (!(object = calloc(1, sizeof(*object)))) -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index ac9a3201792..600ba090312 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -527,6 +527,8 @@ HRESULT WINAPI DllRegisterServer(void) - - TRACE(".\n"); - -+ init_gstreamer(); -+ - if (FAILED(hr = __wine_register_resources())) - return hr; - -From 5b64473d19136cddfad649b38e00e87ceaa76bb3 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 18 Dec 2020 14:08:04 -0600 -Subject: [PATCH] mfplat: Register winegstreamer interfaces on load - -See also "winegstreamer: HACK: Try harder to register winegstreamer -filters." ---- - dlls/mfplat/main.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c -index f36c960f852..47454310234 100644 ---- a/dlls/mfplat/main.c -+++ b/dlls/mfplat/main.c -@@ -1442,6 +1442,18 @@ HRESULT WINAPI MFTUnregister(CLSID clsid) - return S_OK; - } - -+static BOOL CALLBACK register_winegstreamer_proc(INIT_ONCE *once, void *param, void **ctx) -+{ -+ HMODULE mod = LoadLibraryW(L"winegstreamer.dll"); -+ if (mod) -+ { -+ HRESULT (WINAPI *proc)(void) = (void *)GetProcAddress(mod, "DllRegisterServer"); -+ proc(); -+ FreeLibrary(mod); -+ } -+ return TRUE; -+} -+ - /*********************************************************************** - * MFStartup (mfplat.@) - */ -@@ -1449,9 +1461,12 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags) - { - #define MF_VERSION_XP MAKELONG( MF_API_VERSION, 1 ) - #define MF_VERSION_WIN7 MAKELONG( MF_API_VERSION, 2 ) -+ static INIT_ONCE once = INIT_ONCE_STATIC_INIT; - - TRACE("%#lx, %#lx.\n", version, flags); - -+ InitOnceExecuteOnce(&once, register_winegstreamer_proc, NULL, NULL); -+ - if (version != MF_VERSION_XP && version != MF_VERSION_WIN7) - return MF_E_BAD_STARTUP_VERSION; - diff --git a/patches/proton/31-proton-mfplat-patches-valve.patch b/patches/proton/31-proton-mfplat-patches-valve.patch deleted file mode 100644 index 54cadb6f0..000000000 --- a/patches/proton/31-proton-mfplat-patches-valve.patch +++ /dev/null @@ -1,4884 +0,0 @@ -From a7abf29970fadc9493cae9c50d25487324f5c315 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 26 Jan 2022 21:24:07 +0100 -Subject: [PATCH] winegstreamer: Introduce new wg_transform struct. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/gst_private.h | 3 ++ - dlls/winegstreamer/main.c | 14 +++++++ - dlls/winegstreamer/unix_private.h | 31 ++++++++++++++ - dlls/winegstreamer/unixlib.h | 8 ++++ - dlls/winegstreamer/wg_parser.c | 20 +++++++-- - dlls/winegstreamer/wg_transform.c | 69 +++++++++++++++++++++++++++++++ - dlls/winegstreamer/wma_decoder.c | 20 +++++++++ - 8 files changed, 162 insertions(+), 4 deletions(-) - create mode 100644 dlls/winegstreamer/unix_private.h - create mode 100644 dlls/winegstreamer/wg_transform.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index c53e914e246..52295418f0f 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -13,6 +13,7 @@ C_SRCS = \ - mfplat.c \ - quartz_parser.c \ - wg_parser.c \ -+ wg_transform.c \ - wm_asyncreader.c \ - wm_reader.c \ - wm_syncreader.c \ -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 222bce3b2c7..df82b229143 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -96,6 +96,9 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) DECLSPEC_HIDDEN; - -+struct wg_transform *wg_transform_create(void) DECLSPEC_HIDDEN; -+void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; -+ - unsigned int wg_format_get_max_size(const struct wg_format *format); - - HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 260dd208e2f..f23fa3abcdf 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -254,6 +254,20 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); - } - -+struct wg_transform *wg_transform_create(void) -+{ -+ struct wg_transform_create_params params = {0}; -+ -+ if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) -+ return NULL; -+ return params.transform; -+} -+ -+void wg_transform_destroy(struct wg_transform *transform) -+{ -+ __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - if (reason == DLL_PROCESS_ATTACH) -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -new file mode 100644 -index 00000000000..375d33e7728 ---- /dev/null -+++ b/dlls/winegstreamer/unix_private.h -@@ -0,0 +1,31 @@ -+/* -+ * winegstreamer Unix library interface -+ * -+ * Copyright 2020-2021 Zebediah Figura 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 -+ */ -+ -+#ifndef __WINE_WINEGSTREAMER_UNIX_PRIVATE_H -+#define __WINE_WINEGSTREAMER_UNIX_PRIVATE_H -+ -+#include "unixlib.h" -+ -+extern bool init_gstreamer(void) DECLSPEC_HIDDEN; -+ -+extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; -+extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -+ -+#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 82bb534b938..c8b98da3a64 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -217,6 +217,11 @@ struct wg_parser_stream_seek_params - DWORD start_flags, stop_flags; - }; - -+struct wg_transform_create_params -+{ -+ struct wg_transform *transform; -+}; -+ - enum unix_funcs - { - unix_wg_parser_create, -@@ -250,6 +255,9 @@ enum unix_funcs - unix_wg_parser_stream_get_duration, - unix_wg_parser_stream_get_language, - unix_wg_parser_stream_seek, -+ -+ unix_wg_transform_create, -+ unix_wg_transform_destroy, - - unix_wg_parser_stream_drain, - }; -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 013566b25e9..ac8c5a2b95c 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -37,7 +37,7 @@ - #include "winternl.h" - #include "dshow.h" - --#include "unixlib.h" -+#include "unix_private.h" - - typedef enum - { -@@ -51,7 +51,7 @@ typedef enum - * debug logging instead of Wine debug logging. In order to be safe we forbid - * any use of Wine debug logging in this entire file. */ - --GST_DEBUG_CATEGORY_STATIC(wine); -+GST_DEBUG_CATEGORY(wine); - #define GST_CAT_DEFAULT wine - - typedef BOOL (*init_gst_cb)(struct wg_parser *parser); -@@ -1963,6 +1963,16 @@ static void init_gstreamer_once(void) - gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); - } - -+bool init_gstreamer(void) -+{ -+ static pthread_once_t init_once = PTHREAD_ONCE_INIT; -+ -+ if (pthread_once(&init_once, init_gstreamer_once)) -+ return false; -+ -+ return true; -+} -+ - static NTSTATUS wg_parser_create(void *args) - { - static const init_gst_cb init_funcs[] = -@@ -1973,11 +1983,10 @@ static NTSTATUS wg_parser_create(void *args) - [WG_PARSER_WAVPARSE] = wave_parser_init_gst, - }; - -- static pthread_once_t once = PTHREAD_ONCE_INIT; - struct wg_parser_create_params *params = args; - struct wg_parser *parser; - -- if (pthread_once(&once, init_gstreamer_once)) -+ if (!init_gstreamer()) - return E_FAIL; - - if (!(parser = calloc(1, sizeof(*parser)))) -@@ -2053,4 +2062,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - X(wg_parser_stream_get_duration), - X(wg_parser_stream_get_language), - X(wg_parser_stream_seek), -+ -+ X(wg_transform_create), -+ X(wg_transform_destroy), - - X(wg_parser_stream_drain), - }; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -new file mode 100644 -index 00000000000..822740da0d7 ---- /dev/null -+++ b/dlls/winegstreamer/wg_transform.c -@@ -0,0 +1,69 @@ -+/* -+ * GStreamer transform backend -+ * -+ * 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 -+ */ -+ -+#if 0 -+#pragma makedep unix -+#endif -+ -+#include "config.h" -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "winternl.h" -+#include "dshow.h" -+ -+#include "unix_private.h" -+ -+GST_DEBUG_CATEGORY_EXTERN(wine); -+#define GST_CAT_DEFAULT wine -+ -+struct wg_transform -+{ -+}; -+ -+NTSTATUS wg_transform_destroy(void *args) -+{ -+ struct wg_transform *transform = args; -+ -+ free(transform); -+ return S_OK; -+} -+ -+NTSTATUS wg_transform_create(void *args) -+{ -+ struct wg_transform_create_params *params = args; -+ struct wg_transform *transform; -+ -+ if (!init_gstreamer()) -+ return E_FAIL; -+ -+ if (!(transform = calloc(1, sizeof(*transform)))) -+ return E_OUTOFMEMORY; -+ -+ GST_INFO("Created winegstreamer transform %p.", transform); -+ params->transform = transform; -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index 847387d3c22..1544e8e4c9b 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -53,6 +53,8 @@ struct wma_decoder - LONG refcount; - IMFMediaType *input_type; - IMFMediaType *output_type; -+ -+ struct wg_transform *wg_transform; - }; - - static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) -@@ -56,6 +58,19 @@ static struct wma_decoder *impl_from_IMFTransform(IMFTransform *iface) - return CONTAINING_RECORD(iface, struct wma_decoder, IMFTransform_iface); - } - -+static HRESULT try_create_wg_transform(struct wma_decoder *decoder) -+{ -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); -+ -+ decoder->wg_transform = wg_transform_create(); -+ if (decoder->wg_transform) -+ return S_OK; -+ -+ WARN("Failed to create wg_transform.\n"); -+ return E_FAIL; -+} -+ - static HRESULT WINAPI wma_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) - { - struct wma_decoder *decoder = impl_from_IMFTransform(iface); -@@ -104,6 +119,8 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) - - if (!refcount) - { -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) -@@ -438,6 +455,9 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) - goto failed; - -+ if (FAILED(hr = try_create_wg_transform(decoder))) -+ goto failed; -+ - return S_OK; - - failed: -From 182c97dcfd8f52da51b5e59c661b6d9ed408b5f0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:02:52 +0100 -Subject: [PATCH] winegstreamer: Introduce new wg_encoded_format struct. - -And use it for decoder transform input types. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 84 ++++++++++++++++++++++++++++++++ - dlls/winegstreamer/unixlib.h | 25 ++++++++++ - dlls/winegstreamer/wma_decoder.c | 12 +++++ - 4 files changed, 122 insertions(+) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index df82b229143..cec52e976ec 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -120,6 +120,7 @@ extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN; - - IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) DECLSPEC_HIDDEN; - void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) DECLSPEC_HIDDEN; -+void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format) DECLSPEC_HIDDEN; - - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index a111bbe196d..61c7fe28a63 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -760,3 +760,87 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) - else - FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); - } -+ -+static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg_encoded_format *format, -+ UINT32 version) -+{ -+ UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; -+ BYTE codec_data[64]; -+ -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) -+ { -+ FIXME("Sample rate is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels))) -+ { -+ FIXME("Channel count is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_align))) -+ { -+ FIXME("Block alignment is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth))) -+ { -+ FIXME("Depth is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) -+ { -+ FIXME("Codec data is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) -+ { -+ FIXME("Bitrate is not set.\n"); -+ bytes_per_second = 0; -+ } -+ -+ format->encoded_type = WG_ENCODED_TYPE_WMA; -+ format->u.xwma.version = version; -+ format->u.xwma.bitrate = bytes_per_second * 8; -+ format->u.xwma.rate = rate; -+ format->u.xwma.depth = depth; -+ format->u.xwma.channels = channels; -+ format->u.xwma.block_align = block_align; -+ format->u.xwma.codec_data_len = codec_data_len; -+ memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); -+} -+ -+void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format) -+{ -+ GUID major_type, subtype; -+ -+ memset(format, 0, sizeof(*format)); -+ -+ if (FAILED(IMFMediaType_GetMajorType(type, &major_type))) -+ { -+ FIXME("Major type is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ { -+ FIXME("Subtype is not set.\n"); -+ return; -+ } -+ -+ if (IsEqualGUID(&major_type, &MFMediaType_Audio)) -+ { -+ if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1)) -+ mf_media_type_to_wg_encoded_format_wma(type, format, 1); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8)) -+ mf_media_type_to_wg_encoded_format_wma(type, format, 2); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9)) -+ mf_media_type_to_wg_encoded_format_wma(type, format, 3); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) -+ mf_media_type_to_wg_encoded_format_wma(type, format, 4); -+ else -+ FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); -+ } -+ else -+ { -+ FIXME("Unimplemented major type %s.\n", debugstr_guid(&major_type)); -+ } -+} -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index c8b98da3a64..ea46de4cce1 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -91,6 +91,31 @@ struct wg_format - } u; - }; - -+struct wg_encoded_format -+{ -+ enum wg_encoded_type -+ { -+ WG_ENCODED_TYPE_UNKNOWN, -+ WG_ENCODED_TYPE_WMA, -+ WG_ENCODED_TYPE_XMA, -+ } encoded_type; -+ -+ union -+ { -+ struct -+ { -+ uint32_t version; -+ uint32_t bitrate; -+ uint32_t rate; -+ uint32_t depth; -+ uint32_t channels; -+ uint32_t block_align; -+ uint32_t codec_data_len; -+ unsigned char codec_data[64]; -+ } xwma; -+ } u; -+}; -+ - enum wg_parser_event_type - { - WG_PARSER_EVENT_NONE = 0, -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index 1544e8e4c9b..2b543426524 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -64,8 +64,20 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) - - static HRESULT try_create_wg_transform(struct wma_decoder *decoder) - { -+ struct wg_encoded_format input_format; -+ struct wg_format output_format; -+ - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); -+ decoder->wg_transform = NULL; -+ -+ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); -+ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ mf_media_type_to_wg_format(decoder->output_type, &output_format); -+ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) -+ return MF_E_INVALIDMEDIATYPE; - - decoder->wg_transform = wg_transform_create(); - if (decoder->wg_transform) -From 4d41b5a70a95a76f1c4863f4bd1cbab7ca2cc9cb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:22:59 +0100 -Subject: [PATCH] winegstreamer: Create static pads on wg_transform struct. - -With caps created from the input / output formats. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/gst_private.h | 3 +- - dlls/winegstreamer/main.c | 9 ++- - dlls/winegstreamer/unix_private.h | 1 + - dlls/winegstreamer/unixlib.h | 2 + - dlls/winegstreamer/wg_parser.c | 2 +- - dlls/winegstreamer/wg_transform.c | 93 +++++++++++++++++++++++++++++++ - dlls/winegstreamer/wma_decoder.c | 2 +- - 7 files changed, 107 insertions(+), 5 deletions(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index cec52e976ec..5d198f57dc7 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -96,7 +96,8 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) DECLSPEC_HIDDEN; - --struct wg_transform *wg_transform_create(void) DECLSPEC_HIDDEN; -+struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, -+ const struct wg_format *output_format) DECLSPEC_HIDDEN; - void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; - - unsigned int wg_format_get_max_size(const struct wg_format *format); -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index f23fa3abcdf..6dfa9eb5c82 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -254,9 +254,14 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); - } - --struct wg_transform *wg_transform_create(void) -+struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, -+ const struct wg_format *output_format) - { -- struct wg_transform_create_params params = {0}; -+ struct wg_transform_create_params params = -+ { -+ .input_format = input_format, -+ .output_format = output_format, -+ }; - - if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) - return NULL; -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index 375d33e7728..38349eb5e8d 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -24,6 +24,7 @@ - #include "unixlib.h" - - extern bool init_gstreamer(void) DECLSPEC_HIDDEN; -+extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; - - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index ea46de4cce1..96cda2e25aa 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -245,6 +245,8 @@ struct wg_parser_stream_seek_params - struct wg_transform_create_params - { - struct wg_transform *transform; -+ const struct wg_encoded_format *input_format; -+ const struct wg_format *output_format; - }; - - enum unix_funcs -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index ac8c5a2b95c..e7e80ecfddf 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -463,7 +463,7 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) - return caps; - } - --static GstCaps *wg_format_to_caps(const struct wg_format *format) -+GstCaps *wg_format_to_caps(const struct wg_format *format) - { - switch (format->major_type) - { -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 822740da0d7..146cdd87ae7 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -42,12 +42,77 @@ GST_DEBUG_CATEGORY_EXTERN(wine); - - struct wg_transform - { -+ GstPad *my_src, *my_sink; - }; - -+static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) -+{ -+ GstBuffer *buffer; -+ GstCaps *caps; -+ -+ if (format->encoded_type == WG_ENCODED_TYPE_WMA) -+ caps = gst_caps_new_empty_simple("audio/x-wma"); -+ else -+ caps = gst_caps_new_empty_simple("audio/x-xma"); -+ -+ if (format->u.xwma.version) -+ gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); -+ if (format->u.xwma.bitrate) -+ gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.xwma.bitrate, NULL); -+ if (format->u.xwma.rate) -+ gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.xwma.rate, NULL); -+ if (format->u.xwma.depth) -+ gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.xwma.depth, NULL); -+ if (format->u.xwma.channels) -+ gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.xwma.channels, NULL); -+ if (format->u.xwma.block_align) -+ gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.xwma.block_align, NULL); -+ -+ if (format->u.xwma.codec_data_len) -+ { -+ buffer = gst_buffer_new_and_alloc(format->u.xwma.codec_data_len); -+ gst_buffer_fill(buffer, 0, format->u.xwma.codec_data, format->u.xwma.codec_data_len); -+ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); -+ gst_buffer_unref(buffer); -+ } -+ -+ return caps; -+} -+ -+static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format) -+{ -+ switch (format->encoded_type) -+ { -+ case WG_ENCODED_TYPE_UNKNOWN: -+ return NULL; -+ case WG_ENCODED_TYPE_WMA: -+ case WG_ENCODED_TYPE_XMA: -+ return wg_format_to_caps_xwma(format); -+ } -+ assert(0); -+ return NULL; -+} -+ -+static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) -+{ -+ struct wg_transform *transform = gst_pad_get_element_private(pad); -+ -+ GST_INFO("transform %p, buffer %p.", transform, buffer); -+ -+ gst_buffer_unref(buffer); -+ -+ return GST_FLOW_OK; -+} -+ - NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; - -+ if (transform->my_sink) -+ g_object_unref(transform->my_sink); -+ if (transform->my_src) -+ g_object_unref(transform->my_src); -+ - free(transform); - return S_OK; - } -@@ -55,7 +120,11 @@ NTSTATUS wg_transform_destroy(void *args) - NTSTATUS wg_transform_create(void *args) - { - struct wg_transform_create_params *params = args; -+ struct wg_encoded_format input_format = *params->input_format; -+ struct wg_format output_format = *params->output_format; -+ GstCaps *src_caps, *sink_caps; - struct wg_transform *transform; -+ GstPadTemplate *template; - - if (!init_gstreamer()) - return E_FAIL; -@@ -63,7 +132,31 @@ NTSTATUS wg_transform_create(void *args) - if (!(transform = calloc(1, sizeof(*transform)))) - return E_OUTOFMEMORY; - -+ src_caps = wg_encoded_format_to_caps(&input_format); -+ assert(src_caps); -+ sink_caps = wg_format_to_caps(&output_format); -+ assert(sink_caps); -+ -+ template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); -+ assert(template); -+ transform->my_src = gst_pad_new_from_template(template, "src"); -+ g_object_unref(template); -+ assert(transform->my_src); -+ -+ template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); -+ assert(template); -+ transform->my_sink = gst_pad_new_from_template(template, "sink"); -+ g_object_unref(template); -+ assert(transform->my_sink); -+ -+ gst_pad_set_element_private(transform->my_sink, transform); -+ gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); -+ - GST_INFO("Created winegstreamer transform %p.", transform); - params->transform = transform; -+ -+ gst_caps_unref(src_caps); -+ gst_caps_unref(sink_caps); -+ - return S_OK; - } -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index 2b543426524..db6c8a677f6 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -79,7 +79,7 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - -- decoder->wg_transform = wg_transform_create(); -+ decoder->wg_transform = wg_transform_create(&input_format, &output_format); - if (decoder->wg_transform) - return S_OK; - -From fc86c0b5360ddc02071ea5cca2b95d2c8df8309e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:24:27 +0100 -Subject: [PATCH] winegstreamer: Lookup, create and link a decoder element. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/wg_transform.c | 140 +++++++++++++++++++++++++++++- - 1 file changed, 138 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 146cdd87ae7..a436d8316dd 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -42,7 +42,9 @@ GST_DEBUG_CATEGORY_EXTERN(wine); - - struct wg_transform - { -+ GstElement *container; - GstPad *my_src, *my_sink; -+ GstPad *their_sink, *their_src; - }; - - static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) -@@ -108,6 +110,22 @@ NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; - -+ if (transform->container) -+ gst_element_set_state(transform->container, GST_STATE_NULL); -+ -+ if (transform->their_src && transform->my_sink) -+ gst_pad_unlink(transform->their_src, transform->my_sink); -+ if (transform->their_sink && transform->my_src) -+ gst_pad_unlink(transform->my_src, transform->their_sink); -+ -+ if (transform->their_sink) -+ g_object_unref(transform->their_sink); -+ if (transform->their_src) -+ g_object_unref(transform->their_src); -+ -+ if (transform->container) -+ g_object_unref(transform->container); -+ - if (transform->my_sink) - g_object_unref(transform->my_sink); - if (transform->my_src) -@@ -117,14 +135,85 @@ NTSTATUS wg_transform_destroy(void *args) - return S_OK; - } - -+static GstElement *try_create_transform(GstCaps *src_caps, GstCaps *sink_caps) -+{ -+ GstElement *element = NULL; -+ GList *tmp, *transforms; -+ gchar *type; -+ -+ transforms = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_ANY, -+ GST_RANK_MARGINAL); -+ -+ tmp = gst_element_factory_list_filter(transforms, src_caps, GST_PAD_SINK, FALSE); -+ gst_plugin_feature_list_free(transforms); -+ transforms = tmp; -+ -+ tmp = gst_element_factory_list_filter(transforms, sink_caps, GST_PAD_SRC, FALSE); -+ gst_plugin_feature_list_free(transforms); -+ transforms = tmp; -+ -+ transforms = g_list_sort(transforms, gst_plugin_feature_rank_compare_func); -+ for (tmp = transforms; tmp != NULL && element == NULL; tmp = tmp->next) -+ { -+ type = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(tmp->data)); -+ element = gst_element_factory_create(GST_ELEMENT_FACTORY(tmp->data), NULL); -+ if (!element) -+ GST_WARNING("Failed to create %s element.", type); -+ } -+ gst_plugin_feature_list_free(transforms); -+ -+ if (element) -+ GST_INFO("Created %s element %p.", type, element); -+ else -+ { -+ gchar *src_str = gst_caps_to_string(src_caps), *sink_str = gst_caps_to_string(sink_caps); -+ GST_WARNING("Failed to create transform matching caps %s / %s.", src_str, sink_str); -+ g_free(sink_str); -+ g_free(src_str); -+ } -+ -+ return element; -+} -+ -+static bool transform_append_element(struct wg_transform *transform, GstElement *element, -+ GstElement **first, GstElement **last) -+{ -+ gchar *name = gst_element_get_name(element); -+ -+ if (!gst_bin_add(GST_BIN(transform->container), element)) -+ { -+ GST_ERROR("Failed to add %s element to bin.", name); -+ g_free(name); -+ return false; -+ } -+ -+ if (*last && !gst_element_link(*last, element)) -+ { -+ GST_ERROR("Failed to link %s element.", name); -+ g_free(name); -+ return false; -+ } -+ -+ GST_INFO("Created %s element %p.", name, element); -+ g_free(name); -+ -+ if (!*first) -+ *first = element; -+ -+ *last = element; -+ return true; -+} -+ - NTSTATUS wg_transform_create(void *args) - { - struct wg_transform_create_params *params = args; - struct wg_encoded_format input_format = *params->input_format; - struct wg_format output_format = *params->output_format; -- GstCaps *src_caps, *sink_caps; -+ GstElement *first = NULL, *last = NULL, *element; - struct wg_transform *transform; -+ GstCaps *src_caps, *sink_caps; - GstPadTemplate *template; -+ int ret; - - if (!init_gstreamer()) - return E_FAIL; -@@ -137,6 +226,24 @@ NTSTATUS wg_transform_create(void *args) - sink_caps = wg_format_to_caps(&output_format); - assert(sink_caps); - -+ transform->container = gst_bin_new("wg_transform"); -+ assert(transform->container); -+ -+ if (!(element = try_create_transform(src_caps, sink_caps)) || -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ -+ if (!(transform->their_sink = gst_element_get_static_pad(first, "sink"))) -+ { -+ GST_ERROR("Failed to find target sink pad."); -+ goto failed; -+ } -+ if (!(transform->their_src = gst_element_get_static_pad(last, "src"))) -+ { -+ GST_ERROR("Failed to find target src pad."); -+ goto failed; -+ } -+ - template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); - assert(template); - transform->my_src = gst_pad_new_from_template(template, "src"); -@@ -152,11 +259,40 @@ NTSTATUS wg_transform_create(void *args) - gst_pad_set_element_private(transform->my_sink, transform); - gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); - -+ if ((ret = gst_pad_link(transform->my_src, transform->their_sink)) < 0) -+ { -+ GST_ERROR("Failed to link sink pads, error %d.", ret); -+ goto failed; -+ } -+ if ((ret = gst_pad_link(transform->their_src, transform->my_sink)) < 0) -+ { -+ GST_ERROR("Failed to link source pads, error %d.", ret); -+ goto failed; -+ } -+ -+ if (!(ret = gst_pad_set_active(transform->my_sink, 1))) -+ GST_WARNING("Failed to activate my_sink."); -+ if (!(ret = gst_pad_set_active(transform->my_src, 1))) -+ GST_WARNING("Failed to activate my_src."); -+ -+ gst_element_set_state(transform->container, GST_STATE_PAUSED); -+ ret = gst_element_get_state(transform->container, NULL, NULL, -1); -+ if (ret == GST_STATE_CHANGE_FAILURE) -+ { -+ GST_ERROR("Failed to play stream.\n"); -+ goto failed; -+ } -+ - GST_INFO("Created winegstreamer transform %p.", transform); - params->transform = transform; - -+failed: - gst_caps_unref(src_caps); - gst_caps_unref(sink_caps); - -- return S_OK; -+ if (params->transform) -+ return S_OK; -+ -+ wg_transform_destroy(transform); -+ return E_FAIL; - } -From b2444dde8ad804accd68eec6af8e254c1ff6d866 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:25:20 +0100 -Subject: [PATCH] winegstreamer: Send stream-start and caps events on creation. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/wg_transform.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index a436d8316dd..d87b8cfa2c4 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -213,6 +213,7 @@ NTSTATUS wg_transform_create(void *args) - struct wg_transform *transform; - GstCaps *src_caps, *sink_caps; - GstPadTemplate *template; -+ GstSegment *segment; - int ret; - - if (!init_gstreamer()) -@@ -283,6 +284,30 @@ NTSTATUS wg_transform_create(void *args) - goto failed; - } - -+ if (!gst_pad_push_event(transform->my_src, gst_event_new_stream_start("stream"))) -+ { -+ GST_ERROR("Failed to send stream-start."); -+ goto failed; -+ } -+ -+ if (!gst_pad_push_event(transform->my_src, gst_event_new_caps(src_caps))) -+ { -+ GST_ERROR("Failed to set stream caps."); -+ goto failed; -+ } -+ -+ segment = gst_segment_new(); -+ gst_segment_init(segment, GST_FORMAT_TIME); -+ segment->start = 0; -+ segment->stop = -1; -+ ret = gst_pad_push_event(transform->my_src, gst_event_new_segment(segment)); -+ gst_segment_free(segment); -+ if (!ret) -+ { -+ GST_ERROR("Failed to start new segment."); -+ goto failed; -+ } -+ - GST_INFO("Created winegstreamer transform %p.", transform); - params->transform = transform; - - -From 0254d2b54694435894b7f2d305b7863727632253 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:25:58 +0100 -Subject: [PATCH] winegstreamer: Add an audioconverter and audioresampler - elements. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/unix_private.h | 1 + - dlls/winegstreamer/wg_parser.c | 2 +- - dlls/winegstreamer/wg_transform.c | 23 +++++++++++++++++++++-- - 3 files changed, 23 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index 38349eb5e8d..e6b0f3636f7 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -24,6 +24,7 @@ - #include "unixlib.h" - - extern bool init_gstreamer(void) DECLSPEC_HIDDEN; -+extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; - extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; - - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index e7e80ecfddf..c19ff2ab4ed 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1092,7 +1092,7 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - } - } - --static GstElement *create_element(const char *name, const char *plugin_set) -+GstElement *create_element(const char *name, const char *plugin_set) - { - GstElement *element; - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index d87b8cfa2c4..d96923594e2 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -210,9 +210,10 @@ NTSTATUS wg_transform_create(void *args) - struct wg_encoded_format input_format = *params->input_format; - struct wg_format output_format = *params->output_format; - GstElement *first = NULL, *last = NULL, *element; -+ GstCaps *raw_caps, *src_caps, *sink_caps; - struct wg_transform *transform; -- GstCaps *src_caps, *sink_caps; - GstPadTemplate *template; -+ const gchar *media_type; - GstSegment *segment; - int ret; - -@@ -226,14 +227,31 @@ NTSTATUS wg_transform_create(void *args) - assert(src_caps); - sink_caps = wg_format_to_caps(&output_format); - assert(sink_caps); -+ media_type = gst_structure_get_name(gst_caps_get_structure(sink_caps, 0)); -+ raw_caps = gst_caps_new_empty_simple(media_type); -+ assert(raw_caps); - - transform->container = gst_bin_new("wg_transform"); - assert(transform->container); - -- if (!(element = try_create_transform(src_caps, sink_caps)) || -+ if (!(element = try_create_transform(src_caps, raw_caps)) || - !transform_append_element(transform, element, &first, &last)) - goto failed; - -+ switch (output_format.major_type) -+ { -+ case WG_MAJOR_TYPE_AUDIO: -+ if (!(element = create_element("audioconvert", "base")) || -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ if (!(element = create_element("audioresample", "base")) || -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ break; -+ default: -+ break; -+ } -+ - if (!(transform->their_sink = gst_element_get_static_pad(first, "sink"))) - { - GST_ERROR("Failed to find target sink pad."); -@@ -312,6 +330,7 @@ NTSTATUS wg_transform_create(void *args) - params->transform = transform; - - failed: -+ gst_caps_unref(raw_caps); - gst_caps_unref(src_caps); - gst_caps_unref(sink_caps); - -From 13979069d466f0ec837c5bc57e5aff0076d8757d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:28:54 +0100 -Subject: [PATCH] winegstreamer: Implement WMA decoder ProcessInput. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/main.c | 12 +++++++++ - dlls/winegstreamer/unix_private.h | 1 + - dlls/winegstreamer/unixlib.h | 9 +++++++ - dlls/winegstreamer/wg_parser.c | 2 ++ - dlls/winegstreamer/wg_transform.c | 22 ++++++++++++++++ - dlls/winegstreamer/wma_decoder.c | 43 +++++++++++++++++++++++++++++-- - 8 files changed, 88 insertions(+), 8 deletions(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 5d198f57dc7..0fb8aee70ba 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -99,6 +99,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, - const struct wg_format *output_format) DECLSPEC_HIDDEN; - void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; -+HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) DECLSPEC_HIDDEN; - - unsigned int wg_format_get_max_size(const struct wg_format *format); - -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 6dfa9eb5c82..b315d0ce7c1 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -273,6 +273,18 @@ void wg_transform_destroy(struct wg_transform *transform) - __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); - } - -+HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) -+{ -+ struct wg_transform_push_data_params params = -+ { -+ .transform = transform, -+ .data = data, -+ .size = size, -+ }; -+ -+ return __wine_unix_call(unix_handle, unix_wg_transform_push_data, ¶ms); -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - if (reason == DLL_PROCESS_ATTACH) -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index e6b0f3636f7..baa7f81926c 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -29,5 +29,6 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE - - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -+extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; - - #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 96cda2e25aa..da283196ff3 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -249,6 +249,13 @@ struct wg_transform_create_params - const struct wg_format *output_format; - }; - -+struct wg_transform_push_data_params -+{ -+ struct wg_transform *transform; -+ const void *data; -+ UINT32 size; -+}; -+ - enum unix_funcs - { - unix_wg_parser_create, -@@ -287,6 +294,8 @@ enum unix_funcs - unix_wg_transform_destroy, - - unix_wg_parser_stream_drain, -+ -+ unix_wg_transform_push_data, - }; - - #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index c19ff2ab4ed..64c53c6ac98 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -2056,4 +2056,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - X(wg_transform_destroy), - - X(wg_parser_stream_drain), -+ -+ X(wg_transform_push_data), - }; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index d96923594e2..2137c4c8821 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -34,6 +34,7 @@ - - #include "winternl.h" - #include "dshow.h" -+#include "mferror.h" - - #include "unix_private.h" - -@@ -340,3 +341,24 @@ NTSTATUS wg_transform_create(void *args) - wg_transform_destroy(transform); - return E_FAIL; - } -+ -+NTSTATUS wg_transform_push_data(void *args) -+{ -+ struct wg_transform_push_data_params *params = args; -+ struct wg_transform *transform = params->transform; -+ GstBuffer *buffer; -+ GstFlowReturn ret; -+ -+ buffer = gst_buffer_new_and_alloc(params->size); -+ gst_buffer_fill(buffer, 0, params->data, params->size); -+ -+ ret = gst_pad_push(transform->my_src, buffer); -+ if (ret) -+ { -+ GST_ERROR("Failed to push buffer %d", ret); -+ return MF_E_NOTACCEPTING; -+ } -+ -+ GST_INFO("Pushed %u bytes", params->size); -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index db6c8a677f6..c9472bde019 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -54,6 +54,7 @@ struct wma_decoder - IMFMediaType *input_type; - IMFMediaType *output_type; - -+ IMFSample *input_sample; - struct wg_transform *wg_transform; - }; - -@@ -131,6 +132,8 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) - - if (!refcount) - { -+ if (decoder->input_sample) -+ IMFSample_Release(decoder->input_sample); - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) -@@ -480,8 +483,44 @@ static HRESULT WINAPI wma_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAG - - static HRESULT WINAPI wma_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("iface %p, id %u, sample %p, flags %#x stub!\n", iface, id, sample, flags); -- return E_NOTIMPL; -+ struct wma_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaBuffer *media_buffer; -+ MFT_INPUT_STREAM_INFO info; -+ UINT32 buffer_size; -+ BYTE *buffer; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %u, sample %p, flags %#x.\n", iface, id, sample, flags); -+ -+ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (decoder->input_sample) -+ return MF_E_NOTACCEPTING; -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_GetCurrentLength(media_buffer, &buffer_size))) -+ return hr; -+ -+ if (!(buffer_size = (buffer_size / info.cbSize) * info.cbSize)) -+ return S_OK; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, NULL))) -+ goto done; -+ -+ if (SUCCEEDED(hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size))) -+ IMFSample_AddRef((decoder->input_sample = sample)); -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; - } - - static HRESULT WINAPI wma_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -From e12af1d2882e9291038dddee1928a53f443841f3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:31:44 +0100 -Subject: [PATCH] winegstreamer: Implement WMA decoder ProcessOutput. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/main.c | 11 +++++ - dlls/winegstreamer/unix_private.h | 1 + - dlls/winegstreamer/unixlib.h | 19 ++++++++ - dlls/winegstreamer/wg_parser.c | 1 + - dlls/winegstreamer/wg_transform.c | 76 ++++++++++++++++++++++++++++++- - dlls/winegstreamer/wma_decoder.c | 59 +++++++++++++++++++++++- - 8 files changed, 169 insertions(+), 18 deletions(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 0fb8aee70ba..ead2bac4edd 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -100,6 +100,7 @@ struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_f - const struct wg_format *output_format) DECLSPEC_HIDDEN; - void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; - HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) DECLSPEC_HIDDEN; -+HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) DECLSPEC_HIDDEN; - - unsigned int wg_format_get_max_size(const struct wg_format *format); - -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index b315d0ce7c1..3533fd59104 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -285,6 +285,17 @@ HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, - return __wine_unix_call(unix_handle, unix_wg_transform_push_data, ¶ms); - } - -+HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) -+{ -+ struct wg_transform_read_data_params params = -+ { -+ .transform = transform, -+ .sample = sample, -+ }; -+ -+ return __wine_unix_call(unix_handle, unix_wg_transform_read_data, ¶ms); -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - if (reason == DLL_PROCESS_ATTACH) -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index baa7f81926c..1b055436ba5 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -30,5 +30,6 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; -+extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; - - #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index da283196ff3..e7d80147fe5 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -256,6 +256,24 @@ struct wg_transform_push_data_params - UINT32 size; - }; - -+enum wg_sample_flags -+{ -+ WG_SAMPLE_FLAG_INCOMPLETE = 1, -+}; -+ -+struct wg_sample -+{ -+ UINT32 flags; -+ BYTE *data; -+ UINT32 size; -+}; -+ -+struct wg_transform_read_data_params -+{ -+ struct wg_transform *transform; -+ struct wg_sample *sample; -+}; -+ - enum unix_funcs - { - unix_wg_parser_create, -@@ -307,6 +325,7 @@ enum unix_funcs - unix_wg_parser_stream_drain, - - unix_wg_transform_push_data, -+ unix_wg_transform_read_data, - }; - - #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 64c53c6ac98..19c2c661253 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -2058,4 +2058,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - X(wg_parser_stream_drain), - - X(wg_transform_push_data), -+ X(wg_transform_read_data), - }; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 2137c4c8821..1f8b35920b4 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -38,14 +38,24 @@ - - #include "unix_private.h" - -+#include "wine/list.h" -+ - GST_DEBUG_CATEGORY_EXTERN(wine); - #define GST_CAT_DEFAULT wine - -+struct wg_transform_sample -+{ -+ struct list entry; -+ GstSample *sample; -+}; -+ - struct wg_transform - { - GstElement *container; - GstPad *my_src, *my_sink; - GstPad *their_sink, *their_src; -+ pthread_mutex_t mutex; -+ struct list samples; - }; - - static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) -@@ -99,17 +109,29 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format - static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) - { - struct wg_transform *transform = gst_pad_get_element_private(pad); -+ struct wg_transform_sample *sample; - - GST_INFO("transform %p, buffer %p.", transform, buffer); - -- gst_buffer_unref(buffer); -+ if (!(sample = malloc(sizeof(*sample)))) -+ GST_ERROR("Failed to allocate transform sample entry"); -+ else -+ { -+ pthread_mutex_lock(&transform->mutex); -+ if (!(sample->sample = gst_sample_new(buffer, NULL, NULL, NULL))) -+ GST_ERROR("Failed to allocate transform sample"); -+ list_add_tail(&transform->samples, &sample->entry); -+ pthread_mutex_unlock(&transform->mutex); -+ } - -+ gst_buffer_unref(buffer); - return GST_FLOW_OK; - } - - NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; -+ struct wg_transform_sample *sample, *next; - - if (transform->container) - gst_element_set_state(transform->container, GST_STATE_NULL); -@@ -132,6 +154,13 @@ NTSTATUS wg_transform_destroy(void *args) - if (transform->my_src) - g_object_unref(transform->my_src); - -+ LIST_FOR_EACH_ENTRY_SAFE(sample, next, &transform->samples, struct wg_transform_sample, entry) -+ { -+ gst_sample_unref(sample->sample); -+ list_remove(&sample->entry); -+ free(sample); -+ } -+ - free(transform); - return S_OK; - } -@@ -224,6 +253,8 @@ NTSTATUS wg_transform_create(void *args) - if (!(transform = calloc(1, sizeof(*transform)))) - return E_OUTOFMEMORY; - -+ list_init(&transform->samples); -+ - src_caps = wg_encoded_format_to_caps(&input_format); - assert(src_caps); - sink_caps = wg_format_to_caps(&output_format); -@@ -362,3 +393,46 @@ NTSTATUS wg_transform_push_data(void *args) - GST_INFO("Pushed %u bytes", params->size); - return S_OK; - } -+ -+NTSTATUS wg_transform_read_data(void *args) -+{ -+ struct wg_transform_read_data_params *params = args; -+ struct wg_transform *transform = params->transform; -+ struct wg_sample *read_sample = params->sample; -+ struct wg_transform_sample *transform_sample; -+ GstBuffer *buffer; -+ struct list *head; -+ GstMapInfo info; -+ -+ pthread_mutex_lock(&transform->mutex); -+ if (!(head = list_head(&transform->samples))) -+ { -+ pthread_mutex_unlock(&transform->mutex); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ transform_sample = LIST_ENTRY(head, struct wg_transform_sample, entry); -+ buffer = gst_sample_get_buffer(transform_sample->sample); -+ -+ gst_buffer_map(buffer, &info, GST_MAP_READ); -+ if (read_sample->size > info.size) -+ read_sample->size = info.size; -+ memcpy(read_sample->data, info.data, read_sample->size); -+ gst_buffer_unmap(buffer, &info); -+ -+ if (info.size > read_sample->size) -+ { -+ read_sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE; -+ gst_buffer_resize(buffer, read_sample->size, -1); -+ } -+ else -+ { -+ gst_sample_unref(transform_sample->sample); -+ list_remove(&transform_sample->entry); -+ free(transform_sample); -+ } -+ pthread_mutex_unlock(&transform->mutex); -+ -+ GST_INFO("Read %u bytes, flags %#x", read_sample->size, read_sample->flags); -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index c9472bde019..cac345be269 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -526,8 +526,60 @@ static HRESULT WINAPI wma_decoder_ProcessInput(IMFTransform *iface, DWORD id, IM - static HRESULT WINAPI wma_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("iface %p, flags %#x, count %u, samples %p, status %p stub!\n", iface, flags, count, samples, status); -- return E_NOTIMPL; -+ struct wma_decoder *decoder = impl_from_IMFTransform(iface); -+ struct wg_sample wg_sample = {0}; -+ IMFMediaBuffer *media_buffer; -+ MFT_OUTPUT_STREAM_INFO info; -+ HRESULT hr; -+ -+ TRACE("iface %p, flags %#x, count %u, samples %p, status %p.\n", iface, flags, count, samples, status); -+ -+ if (count > 1) -+ { -+ FIXME("Not implemented count %u\n", count); -+ return E_NOTIMPL; -+ } -+ -+ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *status = 0; -+ samples[0].dwStatus = 0; -+ if (!samples[0].pSample) -+ { -+ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &wg_sample.size, NULL))) -+ goto done; -+ -+ if (wg_sample.size < info.cbSize) -+ hr = MF_E_BUFFERTOOSMALL; -+ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -+ { -+ if (wg_sample.flags & WG_SAMPLE_FLAG_INCOMPLETE) -+ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; -+ } -+ else -+ { -+ if (decoder->input_sample) -+ IMFSample_Release(decoder->input_sample); -+ decoder->input_sample = NULL; -+ } -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; - } - - static const IMFTransformVtbl wma_decoder_vtbl = -From 6cdb3ff4adb3495d9bec127397c277aca0e19205 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:32:39 +0100 -Subject: [PATCH] winegstreamer: Support XMAudio2 input format in WMA decoder. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/mfplat.c | 18 +++++++++++------- - dlls/winegstreamer/wg_transform.c | 10 ++++++++-- - dlls/winegstreamer/wma_decoder.c | 3 +++ - 3 files changed, 22 insertions(+), 9 deletions(-) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 61c7fe28a63..55287eec5a8 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -29,6 +29,8 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -+DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); -+ - struct video_processor - { - IMFTransform IMFTransform_iface; -@@ -761,8 +763,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) - FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); - } - --static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg_encoded_format *format, -- UINT32 version) -+static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct wg_encoded_format *format, -+ enum wg_encoded_type encoded_type, UINT32 version) - { - UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; - BYTE codec_data[64]; -@@ -798,7 +800,7 @@ static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg - bytes_per_second = 0; - } - -- format->encoded_type = WG_ENCODED_TYPE_WMA; -+ format->encoded_type = encoded_type; - format->u.xwma.version = version; - format->u.xwma.bitrate = bytes_per_second * 8; - format->u.xwma.rate = rate; -@@ -829,13 +831,15 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - if (IsEqualGUID(&major_type, &MFMediaType_Audio)) - { - if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1)) -- mf_media_type_to_wg_encoded_format_wma(type, format, 1); -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 1); - else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8)) -- mf_media_type_to_wg_encoded_format_wma(type, format, 2); -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 2); - else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9)) -- mf_media_type_to_wg_encoded_format_wma(type, format, 3); -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 3); - else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) -- mf_media_type_to_wg_encoded_format_wma(type, format, 4); -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 4); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_XMA, 2); - else - FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); - } -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 1f8b35920b4..256e77429a0 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -64,12 +64,18 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) - GstCaps *caps; - - if (format->encoded_type == WG_ENCODED_TYPE_WMA) -+ { - caps = gst_caps_new_empty_simple("audio/x-wma"); -+ if (format->u.xwma.version) -+ gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); -+ } - else -+ { - caps = gst_caps_new_empty_simple("audio/x-xma"); -+ if (format->u.xwma.version) -+ gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, format->u.xwma.version, NULL); -+ } - -- if (format->u.xwma.version) -- gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); - if (format->u.xwma.bitrate) - gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.xwma.bitrate, NULL); - if (format->u.xwma.rate) -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index cac345be269..d6ae7d93a39 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -30,12 +30,15 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -+DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); -+ - static const GUID *wma_decoder_input_types[] = - { - &MEDIASUBTYPE_MSAUDIO1, - &MFAudioFormat_WMAudioV8, - &MFAudioFormat_WMAudioV9, - &MFAudioFormat_WMAudio_Lossless, -+ &MFAudioFormat_XMAudio2, - }; - static const GUID *wma_decoder_output_types[] = - { - -From 1beb998df6007991345072dc64e498fb47a75681 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 18 Jan 2022 13:09:07 +0100 -Subject: [PATCH] winegstreamer: Introduce new H264 decoder transform stub. - -As a remplacement for the previously added transform. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/h264_decoder.c | 279 ++++++++++++++++++++++++++++++ - dlls/winegstreamer/mfplat.c | 27 +++ - 4 files changed, 308 insertions(+) - create mode 100644 dlls/winegstreamer/h264_decoder.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 52295418f0f..b8c61a316a0 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -10,6 +10,7 @@ C_SRCS = \ - audioconvert.c \ - colorconvert.c \ - decode_transform.c \ -+ h264_decoder.c \ - main.c \ - media_source.c \ - mfplat.c \ -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index ead2bac4edd..7a0078fe2f4 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -128,6 +128,7 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; - - HRESULT wma_decoder_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; -+HRESULT h264_decoder_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - HRESULT color_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -new file mode 100644 -index 00000000000..5db72c55151 ---- /dev/null -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -0,0 +1,279 @@ -+/* H264 Decoder Transform -+ * -+ * 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 -+ */ -+ -+#include "gst_private.h" -+ -+#include "mfapi.h" -+#include "mferror.h" -+#include "mfobjects.h" -+#include "mftransform.h" -+#include "wmcodecdsp.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -+ -+struct h264_decoder -+{ -+ IMFTransform IMFTransform_iface; -+ LONG refcount; -+}; -+ -+static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -+{ -+ return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); -+} -+ -+static HRESULT WINAPI h264_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) -+{ -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ -+ TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); -+ -+ if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMFTransform)) -+ *out = &decoder->IMFTransform_iface; -+ else -+ { -+ *out = NULL; -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); -+ return E_NOINTERFACE; -+ } -+ -+ IUnknown_AddRef((IUnknown *)*out); -+ return S_OK; -+} -+ -+static ULONG WINAPI h264_decoder_AddRef(IMFTransform *iface) -+{ -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ ULONG refcount = InterlockedIncrement(&decoder->refcount); -+ -+ TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); -+ -+ return refcount; -+} -+ -+static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) -+{ -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ ULONG refcount = InterlockedDecrement(&decoder->refcount); -+ -+ TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); -+ -+ if (!refcount) -+ free(decoder); -+ -+ return refcount; -+} -+ -+static HRESULT WINAPI h264_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, -+ DWORD *output_minimum, DWORD *output_maximum) -+{ -+ FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n", -+ iface, input_minimum, input_maximum, output_minimum, output_maximum); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -+{ -+ FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, -+ DWORD output_size, DWORD *outputs) -+{ -+ FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p stub!\n", -+ iface, input_size, inputs, output_size, outputs); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -+{ -+ FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -+{ -+ FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -+{ -+ FIXME("iface %p, attributes %p stub!\n", iface, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) -+{ -+ FIXME("iface %p, id %#lx stub!\n", iface, id); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -+{ -+ FIXME("iface %p, streams %lu, ids %p stub!\n", iface, streams, ids); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -+{ -+ FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) -+{ -+ FIXME("iface %p, flags %p stub!\n", iface, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -+{ -+ FIXME("iface %p, lower %s, upper %s stub!\n", iface, -+ wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -+{ -+ FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -+{ -+ FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -+{ -+ FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -+{ -+ FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); -+ return E_NOTIMPL; -+} -+ -+static const IMFTransformVtbl h264_decoder_vtbl = -+{ -+ h264_decoder_QueryInterface, -+ h264_decoder_AddRef, -+ h264_decoder_Release, -+ h264_decoder_GetStreamLimits, -+ h264_decoder_GetStreamCount, -+ h264_decoder_GetStreamIDs, -+ h264_decoder_GetInputStreamInfo, -+ h264_decoder_GetOutputStreamInfo, -+ h264_decoder_GetAttributes, -+ h264_decoder_GetInputStreamAttributes, -+ h264_decoder_GetOutputStreamAttributes, -+ h264_decoder_DeleteInputStream, -+ h264_decoder_AddInputStreams, -+ h264_decoder_GetInputAvailableType, -+ h264_decoder_GetOutputAvailableType, -+ h264_decoder_SetInputType, -+ h264_decoder_SetOutputType, -+ h264_decoder_GetInputCurrentType, -+ h264_decoder_GetOutputCurrentType, -+ h264_decoder_GetInputStatus, -+ h264_decoder_GetOutputStatus, -+ h264_decoder_SetOutputBounds, -+ h264_decoder_ProcessEvent, -+ h264_decoder_ProcessMessage, -+ h264_decoder_ProcessInput, -+ h264_decoder_ProcessOutput, -+}; -+ -+HRESULT h264_decoder_create(REFIID riid, void **ret) -+{ -+ struct h264_decoder *decoder; -+ -+ TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); -+ -+ if (!(decoder = calloc(1, sizeof(*decoder)))) -+ return E_OUTOFMEMORY; -+ -+ decoder->IMFTransform_iface.lpVtbl = &h264_decoder_vtbl; -+ decoder->refcount = 1; -+ -+ *ret = &decoder->IMFTransform_iface; -+ TRACE("Created decoder %p\n", *ret); -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index e1d7a52cc99..6bdf700d5ba 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -401,11 +401,6 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a - - static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}}; - --static HRESULT h264_decoder_create(REFIID riid, void **ret) --{ -- return decode_transform_create(riid, ret, DECODER_TYPE_H264); --} -- - static HRESULT aac_decoder_create(REFIID riid, void **ret) - { - return decode_transform_create(riid, ret, DECODER_TYPE_AAC); -@@ -566,7 +561,7 @@ mfts[] = - color_converter_supported_types, - }, - { -- &CLSID_MSAACDecMFT, -+ &CLSID_MSH264DecoderMFT, - &MFT_CATEGORY_VIDEO_DECODER, - h264_decoderW, - MFT_ENUM_FLAG_SYNCMFT, -From d4187ea663f81ccd58e4a9ed671bc2731cdea6c7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 18 Jan 2022 13:33:36 +0100 -Subject: [PATCH] winegstreamer: Return S_OK from H264 decoder GetAttributes. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 5db72c55151..f46d6d77f8e 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -120,7 +120,8 @@ static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWOR - static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) - { - FIXME("iface %p, attributes %p stub!\n", iface, attributes); -- return E_NOTIMPL; -+ -+ return MFCreateAttributes(attributes, 0); - } - - static HRESULT WINAPI h264_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -From a13f8c564234866ae0365c695eee5b01c0ecc302 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 18 Jan 2022 13:33:36 +0100 -Subject: [PATCH] winegstreamer: Return S_OK from H264 decoder ProcessMessage. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index f46d6d77f8e..55f40ad7660 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -216,7 +216,7 @@ static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, I - static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -- return E_NOTIMPL; -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -From aef0b019c04fd73c735f54b34f74fec5d15ec5d2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:54:51 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder SetInputType. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 37 +++++++++++++++++++++++++++++-- - 1 file changed, 35 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 55f40ad7660..e0634bedcaa 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -30,10 +30,16 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -+static const GUID *h264_decoder_input_types[] = -+{ -+ &MFVideoFormat_H264, -+}; -+ - struct h264_decoder - { - IMFTransform IMFTransform_iface; - LONG refcount; -+ IMFMediaType *input_type; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -78,7 +84,11 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) - TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); - - if (!refcount) -+ { -+ if (decoder->input_type) -+ IMFMediaType_Release(decoder->input_type); - free(decoder); -+ } - - return refcount; - } -@@ -166,8 +176,31 @@ static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, D - - static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ GUID major, subtype; -+ HRESULT hr; -+ ULONG i; -+ -+ TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return E_INVALIDARG; -+ -+ if (!IsEqualGUID(&major, &MFMediaType_Video)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i) -+ if (IsEqualGUID(&subtype, h264_decoder_input_types[i])) -+ break; -+ if (i == ARRAY_SIZE(h264_decoder_input_types)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (decoder->input_type) -+ IMFMediaType_Release(decoder->input_type); -+ IMFMediaType_AddRef((decoder->input_type = type)); -+ -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -From d9b859997b6fc2d5d7348205fc2e511c328a9873 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:55:30 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder GetOutputAvailableType. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 141 +++++++++++++++++++++++++++++- - 1 file changed, 138 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index e0634bedcaa..78bf317c36f 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -34,6 +34,14 @@ static const GUID *h264_decoder_input_types[] = - { - &MFVideoFormat_H264, - }; -+static const GUID *h264_decoder_output_types[] = -+{ -+ &MFVideoFormat_NV12, -+ &MFVideoFormat_YV12, -+ &MFVideoFormat_IYUV, -+ &MFVideoFormat_I420, -+ &MFVideoFormat_YUY2, -+}; - - struct h264_decoder - { -@@ -47,6 +55,103 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) - return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); - } - -+static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) -+{ -+ UINT32 value, width, height; -+ UINT64 value64; -+ GUID subtype; -+ HRESULT hr; -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_SIZE, &value64))) -+ value64 = (UINT64)1920 << 32 | 1080; -+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, value64))) -+ return hr; -+ } -+ width = value64 >> 32; -+ height = value64; -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_RATE, &value64))) -+ value64 = (UINT64)30000 << 32 | 1001; -+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, value64))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64))) -+ value64 = (UINT64)1 << 32 | 1; -+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, value64))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_SAMPLE_SIZE, &value))) -+ { -+ if (IsEqualGUID(&subtype, &MFVideoFormat_YUY2)) -+ value = width * height * 2; -+ else -+ value = width * height * 3 / 2; -+ } -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_DEFAULT_STRIDE, &value))) -+ { -+ if (IsEqualGUID(&subtype, &MFVideoFormat_YUY2)) -+ value = width * 2; -+ else -+ value = width; -+ } -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) -+ value = MFVideoInterlace_MixedInterlaceOrProgressive; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) -+ value = 1; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) -+ value = 0; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) -+ value = 1; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) -+ return hr; -+ } -+ -+ return S_OK; -+} -+ - static HRESULT WINAPI h264_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) - { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); -@@ -170,8 +275,38 @@ static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DW - static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaType *media_type; -+ const GUID *output_type; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); -+ -+ if (!decoder->input_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *type = NULL; -+ -+ if (index >= ARRAY_SIZE(h264_decoder_output_types)) -+ return MF_E_NO_MORE_TYPES; -+ output_type = h264_decoder_output_types[index]; -+ -+ if (FAILED(hr = MFCreateMediaType(&media_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) -+ goto done; -+ -+ hr = fill_output_media_type(media_type, NULL); -+ -+done: -+ if (SUCCEEDED(hr)) -+ IMFMediaType_AddRef((*type = media_type)); -+ -+ IMFMediaType_Release(media_type); -+ return hr; - } - - static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -@@ -184,7 +319,7 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, I - TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - - if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -- FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - return E_INVALIDARG; - - if (!IsEqualGUID(&major, &MFMediaType_Video)) -From 2ce8f6c136202c16eb903220a2730942b00ae52c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:55:46 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder GetInputAvailableType. - -Required by Shadow Warrior 2. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 23 +++++++++++++++++++++-- - 1 file changed, 21 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 78bf317c36f..7aca79e7a86 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -268,8 +268,27 @@ static HRESULT WINAPI h264_decoder_AddInputStreams(IMFTransform *iface, DWORD st - static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -- return E_NOTIMPL; -+ IMFMediaType *media_type; -+ const GUID *subtype; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); -+ -+ *type = NULL; -+ -+ if (index >= ARRAY_SIZE(h264_decoder_input_types)) -+ return MF_E_NO_MORE_TYPES; -+ subtype = h264_decoder_input_types[index]; -+ -+ if (FAILED(hr = MFCreateMediaType(&media_type))) -+ return hr; -+ -+ if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) && -+ SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype))) -+ IMFMediaType_AddRef((*type = media_type)); -+ -+ IMFMediaType_Release(media_type); -+ return hr; - } - - static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -From 14706e4f94cb61177826ac8970e796fc1f572fb4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:56:08 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder SetOutputType. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 39 +++++++++++++++++++++++++++++-- - 1 file changed, 37 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 7aca79e7a86..2cfc1ac0d05 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -48,6 +48,7 @@ struct h264_decoder - IMFTransform IMFTransform_iface; - LONG refcount; - IMFMediaType *input_type; -+ IMFMediaType *output_type; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -192,6 +193,8 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) - { - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); -+ if (decoder->output_type) -+ IMFMediaType_Release(decoder->output_type); - free(decoder); - } - -@@ -350,6 +353,12 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, I - if (i == ARRAY_SIZE(h264_decoder_input_types)) - return MF_E_INVALIDMEDIATYPE; - -+ if (decoder->output_type) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - IMFMediaType_AddRef((decoder->input_type = type)); -@@ -359,8 +368,34 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, I - - static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ GUID major, subtype; -+ HRESULT hr; -+ ULONG i; -+ -+ TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); -+ -+ if (!decoder->input_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (!IsEqualGUID(&major, &MFMediaType_Video)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i) -+ if (IsEqualGUID(&subtype, h264_decoder_output_types[i])) -+ break; -+ if (i == ARRAY_SIZE(h264_decoder_output_types)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (decoder->output_type) -+ IMFMediaType_Release(decoder->output_type); -+ IMFMediaType_AddRef((decoder->output_type = type)); -+ -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -From da890b23a3504ee9afca1a12a4c29680f33eb458 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:56:23 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder GetInputStreamInfo. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 2cfc1ac0d05..1ccb5f39908 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -225,8 +225,20 @@ static HRESULT WINAPI h264_decoder_GetStreamIDs(IMFTransform *iface, DWORD input - - static HRESULT WINAPI h264_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) - { -- FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ -+ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); -+ -+ if (!decoder->input_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ info->hnsMaxLatency = 0; -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; -+ info->cbSize = 0x1000; -+ info->cbMaxLookahead = 0; -+ info->cbAlignment = 0; -+ -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -From 62f0f599b09103652c63d0f1d73eb8ac875ff440 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:56:35 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder GetOutputStreamInfo. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 21 +++++++++++++++++++-- - 1 file changed, 19 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 1ccb5f39908..eadb28cdaaa 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -243,8 +243,25 @@ static HRESULT WINAPI h264_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD - - static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) - { -- FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaType *media_type; -+ UINT32 sample_size; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); -+ -+ if (!decoder->input_type || !decoder->output_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ media_type = decoder->output_type; -+ -+ info->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; -+ if (FAILED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &sample_size))) -+ sample_size = 1920 * 1080 * 2; -+ info->cbSize = sample_size; -+ info->cbAlignment = 0; -+ -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -From 24312f557589df704155d6870e5e680df87b11ca Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:33:39 +0100 -Subject: [PATCH] winegstreamer: Add H264 encoded format support in - wg_transform. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 36 +++++++++++++++++- - dlls/winegstreamer/mfplat.c | 37 ++++++++++++++++++ - dlls/winegstreamer/unixlib.h | 8 ++++ - dlls/winegstreamer/wg_transform.c | 63 +++++++++++++++++++++++++++++++ - 4 files changed, 143 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index eadb28cdaaa..b7de097fc7d 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -49,6 +49,8 @@ struct h264_decoder - LONG refcount; - IMFMediaType *input_type; - IMFMediaType *output_type; -+ -+ struct wg_transform *wg_transform; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -56,6 +58,30 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) - return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); - } - -+static HRESULT try_create_wg_transform(struct h264_decoder *decoder) -+{ -+ struct wg_encoded_format input_format; -+ struct wg_format output_format; -+ -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); -+ -+ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); -+ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ mf_media_type_to_wg_format(decoder->output_type, &output_format); -+ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ decoder->wg_transform = wg_transform_create(&input_format, &output_format); -+ if (decoder->wg_transform) -+ return S_OK; -+ -+ WARN("Failed to create H264 wg_transform.\n"); -+ return E_FAIL; -+} -+ - static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) - { - UINT32 value, width, height; -@@ -191,6 +217,8 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) - - if (!refcount) - { -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) -@@ -424,7 +452,13 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, - IMFMediaType_Release(decoder->output_type); - IMFMediaType_AddRef((decoder->output_type = type)); - -- return S_OK; -+ if (FAILED(hr = try_create_wg_transform(decoder))) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ -+ return hr; - } - - static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 67c11ce75d7..4ff174a2083 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -838,6 +838,36 @@ static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct w - memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); - } - -+static void mf_media_type_to_wg_encoded_format_h264(IMFMediaType *type, struct wg_encoded_format *format) -+{ -+ UINT64 frame_rate, frame_size; -+ UINT32 profile, level; -+ -+ format->encoded_type = WG_ENCODED_TYPE_H264; -+ format->u.h264.width = 0; -+ format->u.h264.height = 0; -+ format->u.h264.fps_n = 1; -+ format->u.h264.fps_d = 1; -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) -+ { -+ format->u.h264.width = (UINT32)(frame_size >> 32); -+ format->u.h264.height = (UINT32)frame_size; -+ } -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) -+ { -+ format->u.h264.fps_n = (UINT32)(frame_rate >> 32); -+ format->u.h264.fps_d = (UINT32)frame_rate; -+ } -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) -+ format->u.h264.profile = profile; -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) -+ format->u.h264.level = level; -+} -+ - void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format) - { - GUID major_type, subtype; -@@ -870,6 +900,13 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - else - FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); - } -+ else if (IsEqualGUID(&major_type, &MFMediaType_Video)) -+ { -+ if (IsEqualGUID(&subtype, &MFVideoFormat_H264)) -+ mf_media_type_to_wg_encoded_format_h264(type, format); -+ else -+ FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); -+ } - else - { - FIXME("Unimplemented major type %s.\n", debugstr_guid(&major_type)); -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index e7d80147fe5..7892e2813fc 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -98,6 +98,7 @@ struct wg_encoded_format - WG_ENCODED_TYPE_UNKNOWN, - WG_ENCODED_TYPE_WMA, - WG_ENCODED_TYPE_XMA, -+ WG_ENCODED_TYPE_H264, - } encoded_type; - - union -@@ -113,6 +114,13 @@ struct wg_encoded_format - uint32_t codec_data_len; - unsigned char codec_data[64]; - } xwma; -+ struct -+ { -+ int32_t width, height; -+ uint32_t fps_n, fps_d; -+ uint32_t profile; -+ uint32_t level; -+ } h264; - } u; - }; - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 256e77429a0..2956ddf753b 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -98,6 +98,64 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) - return caps; - } - -+static GstCaps *wg_format_to_caps_h264(const struct wg_encoded_format *format) -+{ -+ const char *profile, *level; -+ GstCaps *caps; -+ -+ caps = gst_caps_new_empty_simple("video/x-h264"); -+ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); -+ gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL); -+ -+ if (format->u.h264.width) -+ gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.h264.width, NULL); -+ if (format->u.h264.height) -+ gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.h264.height, NULL); -+ if (format->u.h264.fps_n || format->u.h264.fps_d) -+ gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.h264.fps_n, format->u.h264.fps_d, NULL); -+ -+ switch (format->u.h264.profile) -+ { -+ case /* eAVEncH264VProfile_Main */ 77: profile = "main"; break; -+ case /* eAVEncH264VProfile_High */ 100: profile = "high"; break; -+ case /* eAVEncH264VProfile_444 */ 244: profile = "high-4:4:4"; break; -+ default: -+ GST_ERROR("Unrecognized H.264 profile attribute %u.", format->u.h264.profile); -+ /* fallthrough */ -+ case 0: profile = NULL; -+ } -+ if (profile) -+ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); -+ -+ switch (format->u.h264.level) -+ { -+ case /* eAVEncH264VLevel1 */ 10: level = "1"; break; -+ case /* eAVEncH264VLevel1_1 */ 11: level = "1.1"; break; -+ case /* eAVEncH264VLevel1_2 */ 12: level = "1.2"; break; -+ case /* eAVEncH264VLevel1_3 */ 13: level = "1.3"; break; -+ case /* eAVEncH264VLevel2 */ 20: level = "2"; break; -+ case /* eAVEncH264VLevel2_1 */ 21: level = "2.1"; break; -+ case /* eAVEncH264VLevel2_2 */ 22: level = "2.2"; break; -+ case /* eAVEncH264VLevel3 */ 30: level = "3"; break; -+ case /* eAVEncH264VLevel3_1 */ 31: level = "3.1"; break; -+ case /* eAVEncH264VLevel3_2 */ 32: level = "3.2"; break; -+ case /* eAVEncH264VLevel4 */ 40: level = "4"; break; -+ case /* eAVEncH264VLevel4_1 */ 41: level = "4.1"; break; -+ case /* eAVEncH264VLevel4_2 */ 42: level = "4.2"; break; -+ case /* eAVEncH264VLevel5 */ 50: level = "5"; break; -+ case /* eAVEncH264VLevel5_1 */ 51: level = "5.1"; break; -+ case /* eAVEncH264VLevel5_2 */ 52: level = "5.2"; break; -+ default: -+ GST_ERROR("Unrecognized H.264 level attribute %u.", format->u.h264.level); -+ /* fallthrough */ -+ case 0: level = NULL; -+ } -+ if (level) -+ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); -+ -+ return caps; -+} -+ - static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format) - { - switch (format->encoded_type) -@@ -107,6 +165,8 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format - case WG_ENCODED_TYPE_WMA: - case WG_ENCODED_TYPE_XMA: - return wg_format_to_caps_xwma(format); -+ case WG_ENCODED_TYPE_H264: -+ return wg_format_to_caps_h264(format); - } - assert(0); - return NULL; -@@ -286,7 +346,10 @@ NTSTATUS wg_transform_create(void *args) - !transform_append_element(transform, element, &first, &last)) - goto failed; - break; -+ case WG_MAJOR_TYPE_VIDEO: -+ break; - default: -+ assert(0); - break; - } - -From 5a8875b0c253f433a3c381a6ad342ef48b0d9a6b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:56:47 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder ProcessInput. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 30 ++++++++++++++++++++++++++++-- - 1 file changed, 28 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index b7de097fc7d..268262a0f18 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -506,8 +506,34 @@ static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSA - - static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaBuffer *media_buffer; -+ MFT_INPUT_STREAM_INFO info; -+ DWORD buffer_size; -+ BYTE *buffer; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); -+ -+ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &buffer_size))) -+ goto done; -+ -+ hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size); -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; - } - - static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -From e6a374bd7eba342a3501477e774ea7e58dd7f58f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:57:10 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder ProcessOutput. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 50 +++++++++++++++++++++++++++++-- - 1 file changed, 48 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 268262a0f18..44d55ae061f 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -539,8 +539,54 @@ static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, I - static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ struct wg_sample wg_sample = {0}; -+ IMFMediaBuffer *media_buffer; -+ MFT_OUTPUT_STREAM_INFO info; -+ DWORD buffer_size; -+ HRESULT hr; -+ -+ TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); -+ -+ if (count > 1) -+ { -+ FIXME("Not implemented count %lu\n", count); -+ return E_NOTIMPL; -+ } -+ -+ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *status = 0; -+ samples[0].dwStatus = 0; -+ if (!samples[0].pSample) -+ { -+ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &buffer_size, NULL))) -+ goto done; -+ wg_sample.size = buffer_size; -+ -+ if (wg_sample.size < info.cbSize) -+ hr = MF_E_BUFFERTOOSMALL; -+ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -+ hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ if (FAILED(hr)) -+ IMFMediaBuffer_SetCurrentLength(media_buffer, 0); -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; - } - - static const IMFTransformVtbl h264_decoder_vtbl = -From 1f577e3a9cdff29b907ee9bbf999427146c7a0b2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:34:12 +0100 -Subject: [PATCH] winegstreamer: Add timestamps and duration to H264 decoded - samples. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 6 ++++++ - dlls/winegstreamer/unixlib.h | 4 ++++ - dlls/winegstreamer/wg_transform.c | 11 +++++++++++ - 3 files changed, 21 insertions(+) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 44d55ae061f..69e747f1dc0 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -578,7 +578,13 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - if (wg_sample.size < info.cbSize) - hr = MF_E_BUFFERTOOSMALL; - else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -+ { -+ if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_PTS) -+ IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); -+ if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) -+ IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); - hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); -+ } - - IMFMediaBuffer_Unlock(media_buffer); - -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 7892e2813fc..5890780c64c 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -267,6 +267,8 @@ struct wg_transform_push_data_params - enum wg_sample_flags - { - WG_SAMPLE_FLAG_INCOMPLETE = 1, -+ WG_SAMPLE_FLAG_HAS_PTS = 2, -+ WG_SAMPLE_FLAG_HAS_DURATION = 4, - }; - - struct wg_sample -@@ -274,6 +276,8 @@ struct wg_sample - UINT32 flags; - BYTE *data; - UINT32 size; -+ /* pts and duration are in 100-nanosecond units. */ -+ ULONGLONG pts, duration; - }; - - struct wg_transform_read_data_params -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 2956ddf753b..93e777ba39a 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -489,6 +489,17 @@ NTSTATUS wg_transform_read_data(void *args) - memcpy(read_sample->data, info.data, read_sample->size); - gst_buffer_unmap(buffer, &info); - -+ if (buffer->pts != GST_CLOCK_TIME_NONE) -+ { -+ read_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; -+ read_sample->pts = buffer->pts / 100; -+ } -+ if (buffer->duration != GST_CLOCK_TIME_NONE) -+ { -+ read_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; -+ read_sample->duration = buffer->duration / 100; -+ } -+ - if (info.size > read_sample->size) - { - read_sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE; -From 5519610d889b79df7109ab8fe0c0002de9d78eeb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:57:36 +0100 -Subject: [PATCH] winegstreamer: Support dynamic wg_transform video format - change. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 26 ++++++++++++- - dlls/winegstreamer/unix_private.h | 2 + - dlls/winegstreamer/unixlib.h | 1 + - dlls/winegstreamer/wg_parser.c | 4 +- - dlls/winegstreamer/wg_transform.c | 61 ++++++++++++++++++++++++++++++- - 5 files changed, 89 insertions(+), 5 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 69e747f1dc0..219790128da 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -51,6 +51,7 @@ struct h264_decoder - IMFMediaType *output_type; - - struct wg_transform *wg_transform; -+ struct wg_format wg_format; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -378,7 +379,7 @@ static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, D - if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) - goto done; - -- hr = fill_output_media_type(media_type, NULL); -+ hr = fill_output_media_type(media_type, decoder->output_type); - - done: - if (SUCCEEDED(hr)) -@@ -427,6 +428,7 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, - { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - GUID major, subtype; -+ BOOL identical; - HRESULT hr; - ULONG i; - -@@ -449,7 +451,13 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, - return MF_E_INVALIDMEDIATYPE; - - if (decoder->output_type) -+ { -+ if (SUCCEEDED(hr = IMFMediaType_Compare(decoder->output_type, (IMFAttributes *)type, -+ MF_ATTRIBUTES_MATCH_THEIR_ITEMS, &identical)) && identical) -+ return S_OK; - IMFMediaType_Release(decoder->output_type); -+ } -+ - IMFMediaType_AddRef((decoder->output_type = type)); - - if (FAILED(hr = try_create_wg_transform(decoder))) -@@ -543,6 +551,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - struct wg_sample wg_sample = {0}; - IMFMediaBuffer *media_buffer; - MFT_OUTPUT_STREAM_INFO info; -+ IMFMediaType *media_type; - DWORD buffer_size; - HRESULT hr; - -@@ -575,6 +584,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - goto done; - wg_sample.size = buffer_size; - -+ wg_sample.format = &decoder->wg_format; - if (wg_sample.size < info.cbSize) - hr = MF_E_BUFFERTOOSMALL; - else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -@@ -585,6 +595,20 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); - hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); - } -+ else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) -+ { -+ media_type = mf_media_type_from_wg_format(&decoder->wg_format); -+ IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, wg_sample.size); -+ IMFMediaType_DeleteItem(media_type, &MF_MT_FRAME_RATE); -+ IMFMediaType_DeleteItem(decoder->output_type, &MF_MT_DEFAULT_STRIDE); -+ fill_output_media_type(media_type, decoder->output_type); -+ -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = media_type; -+ -+ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; -+ *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; -+ } - - IMFMediaBuffer_Unlock(media_buffer); - -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index 1b055436ba5..88566ab1db5 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -26,6 +26,8 @@ - extern bool init_gstreamer(void) DECLSPEC_HIDDEN; - extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; - extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; -+extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; -+extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; - - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 5890780c64c..2e9625fed4e 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -278,6 +278,7 @@ struct wg_sample - UINT32 size; - /* pts and duration are in 100-nanosecond units. */ - ULONGLONG pts, duration; -+ struct wg_format *format; - }; - - struct wg_transform_read_data_params -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 19c2c661253..9e1fc5d1357 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -308,7 +308,7 @@ static void wg_format_from_caps_video_cinepak(struct wg_format *format, const Gs - format->u.video.fps_d = fps_d; - } - --static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) -+void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) - { - const GstStructure *structure = gst_caps_get_structure(caps, 0); - const char *name = gst_structure_get_name(structure); -@@ -478,7 +478,7 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) - return NULL; - } - --static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) -+bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) - { - if (a->major_type != b->major_type) - return false; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 93e777ba39a..df37b4e8543 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -56,6 +56,7 @@ struct wg_transform - GstPad *their_sink, *their_src; - pthread_mutex_t mutex; - struct list samples; -+ GstCaps *sink_caps; - }; - - static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) -@@ -184,7 +185,7 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst - else - { - pthread_mutex_lock(&transform->mutex); -- if (!(sample->sample = gst_sample_new(buffer, NULL, NULL, NULL))) -+ if (!(sample->sample = gst_sample_new(buffer, transform->sink_caps, NULL, NULL))) - GST_ERROR("Failed to allocate transform sample"); - list_add_tail(&transform->samples, &sample->entry); - pthread_mutex_unlock(&transform->mutex); -@@ -194,6 +195,38 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst - return GST_FLOW_OK; - } - -+static gboolean transform_sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) -+{ -+ struct wg_transform *transform = gst_pad_get_element_private(pad); -+ -+ GST_INFO("transform %p, type \"%s\".", transform, GST_EVENT_TYPE_NAME(event)); -+ -+ switch (event->type) -+ { -+ case GST_EVENT_CAPS: -+ { -+ GstCaps *caps; -+ gchar *str; -+ -+ gst_event_parse_caps(event, &caps); -+ str = gst_caps_to_string(caps); -+ GST_WARNING("Got caps \"%s\".", str); -+ g_free(str); -+ -+ pthread_mutex_lock(&transform->mutex); -+ gst_caps_unref(transform->sink_caps); -+ transform->sink_caps = gst_caps_ref(caps); -+ pthread_mutex_unlock(&transform->mutex); -+ break; -+ } -+ default: -+ GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event)); -+ } -+ -+ gst_event_unref(event); -+ return TRUE; -+} -+ - NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; -@@ -311,7 +344,7 @@ NTSTATUS wg_transform_create(void *args) - GstPadTemplate *template; - const gchar *media_type; - GstSegment *segment; -- int ret; -+ int i, ret; - - if (!init_gstreamer()) - return E_FAIL; -@@ -329,6 +362,7 @@ NTSTATUS wg_transform_create(void *args) - raw_caps = gst_caps_new_empty_simple(media_type); - assert(raw_caps); - -+ transform->sink_caps = gst_caps_copy(sink_caps); - transform->container = gst_bin_new("wg_transform"); - assert(transform->container); - -@@ -347,6 +381,12 @@ NTSTATUS wg_transform_create(void *args) - goto failed; - break; - case WG_MAJOR_TYPE_VIDEO: -+ if (!(element = create_element("videoconvert", "base")) || -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ for (i = 0; i < gst_caps_get_size(sink_caps); ++i) -+ gst_structure_remove_fields(gst_caps_get_structure(sink_caps, i), -+ "width", "height", NULL); - break; - default: - assert(0); -@@ -377,6 +417,7 @@ NTSTATUS wg_transform_create(void *args) - assert(transform->my_sink); - - gst_pad_set_element_private(transform->my_sink, transform); -+ gst_pad_set_event_function(transform->my_sink, transform_sink_event_cb); - gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); - - if ((ret = gst_pad_link(transform->my_src, transform->their_sink)) < 0) -@@ -469,9 +510,11 @@ NTSTATUS wg_transform_read_data(void *args) - struct wg_transform *transform = params->transform; - struct wg_sample *read_sample = params->sample; - struct wg_transform_sample *transform_sample; -+ struct wg_format buffer_format; - GstBuffer *buffer; - struct list *head; - GstMapInfo info; -+ GstCaps *caps; - - pthread_mutex_lock(&transform->mutex); - if (!(head = list_head(&transform->samples))) -@@ -483,6 +526,20 @@ NTSTATUS wg_transform_read_data(void *args) - transform_sample = LIST_ENTRY(head, struct wg_transform_sample, entry); - buffer = gst_sample_get_buffer(transform_sample->sample); - -+ if (read_sample->format) -+ { -+ if (!(caps = gst_sample_get_caps(transform_sample->sample))) -+ caps = transform->sink_caps; -+ wg_format_from_caps(&buffer_format, caps); -+ if (!wg_format_compare(read_sample->format, &buffer_format)) -+ { -+ *read_sample->format = buffer_format; -+ read_sample->size = gst_buffer_get_size(buffer); -+ pthread_mutex_unlock(&transform->mutex); -+ return MF_E_TRANSFORM_STREAM_CHANGE; -+ } -+ } -+ - gst_buffer_map(buffer, &info, GST_MAP_READ); - if (read_sample->size > info.size) - read_sample->size = info.size; -From 653649989217881800aa20f66f209ef4825e2d38 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:58:20 +0100 -Subject: [PATCH] winegstreamer: Fixup H264 decoder NV12 plane alignment. - -To match what native does. Many games that use the H264 decoder directly -rely on this as they hardcode various aspects of the alignment in their -logic (and each game a different one). - -Note: There may be a way to have it done by GStreamer, as libav natively -decode H264 into aligned planes, but somehow and somewhere in the chain -the planes are re-aligned. - -Hard Reset Redux crashes if MF_MT_MINIMUM_DISPLAY_APERTURE attribute is -set (and it doesn't need it as its videos are 720p). - -For: Call of Duty III, Shadow Warrior 2. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 40 +++++++++++++++++++++++++++++++ - 1 file changed, 40 insertions(+) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 219790128da..66ecfad84de 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -86,6 +86,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) - static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) - { - UINT32 value, width, height; -+ MFVideoArea aperture = {0}; - UINT64 value64; - GUID subtype; - HRESULT hr; -@@ -177,6 +178,17 @@ static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *de - return hr; - } - -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))) -+ { -+ if (default_type && SUCCEEDED(hr = IMFMediaType_GetBlob(default_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, -+ (BYTE *)&aperture, sizeof(aperture), NULL))) -+ { -+ if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, -+ (BYTE *)&aperture, sizeof(aperture)))) -+ return hr; -+ } -+ } -+ - return S_OK; - } - -@@ -551,7 +563,9 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - struct wg_sample wg_sample = {0}; - IMFMediaBuffer *media_buffer; - MFT_OUTPUT_STREAM_INFO info; -+ MFVideoArea aperture = {0}; - IMFMediaType *media_type; -+ UINT32 align, offset; - DWORD buffer_size; - HRESULT hr; - -@@ -593,6 +607,17 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); - if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) - IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); -+ -+ if (decoder->wg_format.u.video.format == WG_VIDEO_FORMAT_NV12 && -+ (align = decoder->wg_format.u.video.height & 15)) -+ { -+ offset = decoder->wg_format.u.video.width * decoder->wg_format.u.video.height; -+ align = (16 - align) * decoder->wg_format.u.video.width; -+ memmove(wg_sample.data + offset + align, wg_sample.data + offset, -+ wg_sample.size - offset); -+ wg_sample.size += align; -+ } -+ - hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); - } - else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) -@@ -603,6 +628,21 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - IMFMediaType_DeleteItem(decoder->output_type, &MF_MT_DEFAULT_STRIDE); - fill_output_media_type(media_type, decoder->output_type); - -+ if (decoder->wg_format.u.video.format == WG_VIDEO_FORMAT_NV12 && -+ (align = decoder->wg_format.u.video.height & 15)) -+ { -+ aperture.Area.cx = decoder->wg_format.u.video.width; -+ aperture.Area.cy = decoder->wg_format.u.video.height; -+ IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, -+ (BYTE *)&aperture, sizeof(aperture)); -+ -+ aperture.Area.cy += 16 - align; -+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, -+ (UINT64)aperture.Area.cx << 32 | aperture.Area.cy); -+ IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, -+ aperture.Area.cx * aperture.Area.cy * 3 / 2); -+ } -+ - IMFMediaType_Release(decoder->output_type); - decoder->output_type = media_type; - -From 3f86ff74c2a8a82913bbb35d9ee4f90eca855976 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 21:46:08 +0100 -Subject: [PATCH] winegstreamer: Use an optional h264parse wg_transform - element. - -Required for Mortal Kombat 11. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/wg_transform.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index df37b4e8543..e3b7d8ed056 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -366,6 +366,17 @@ NTSTATUS wg_transform_create(void *args) - transform->container = gst_bin_new("wg_transform"); - assert(transform->container); - -+ switch (input_format.encoded_type) -+ { -+ case WG_ENCODED_TYPE_H264: -+ if ((element = create_element("h264parse", "base")) && -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ break; -+ default: -+ break; -+ } -+ - if (!(element = try_create_transform(src_caps, raw_caps)) || - !transform_append_element(transform, element, &first, &last)) - goto failed; -From bc56611bc058a0b6bd6c517d35055d5e78826b29 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:58:32 +0100 -Subject: [PATCH] HACK: winegstreamer: Fake H264 timestamps if framerate cannot - be trusted. - -Fixes MK11 video framerate. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 12 ++++++++++++ - dlls/winegstreamer/wg_transform.c | 10 ++++++++-- - 2 files changed, 20 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 66ecfad84de..ba6e681890b 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -52,6 +52,7 @@ struct h264_decoder - - struct wg_transform *wg_transform; - struct wg_format wg_format; -+ ULONGLONG last_pts; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -75,6 +76,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - -+ decoder->last_pts = 0; - decoder->wg_transform = wg_transform_create(&input_format, &output_format); - if (decoder->wg_transform) - return S_OK; -@@ -567,6 +569,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - IMFMediaType *media_type; - UINT32 align, offset; - DWORD buffer_size; -+ UINT64 framerate; - HRESULT hr; - - TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); -@@ -603,6 +606,15 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - hr = MF_E_BUFFERTOOSMALL; - else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) - { -+ if (!(wg_sample.flags & (WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION))) -+ { -+ IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &framerate); -+ wg_sample.pts = decoder->last_pts; -+ wg_sample.duration = (UINT64)10000000 * (UINT32)framerate / (framerate >> 32); -+ wg_sample.flags |= (WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION); -+ decoder->last_pts += wg_sample.duration; -+ } -+ - if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_PTS) - IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); - if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index e3b7d8ed056..1c9dc6f72bb 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -522,6 +522,7 @@ NTSTATUS wg_transform_read_data(void *args) - struct wg_sample *read_sample = params->sample; - struct wg_transform_sample *transform_sample; - struct wg_format buffer_format; -+ bool broken_timestamp = false; - GstBuffer *buffer; - struct list *head; - GstMapInfo info; -@@ -549,6 +550,11 @@ NTSTATUS wg_transform_read_data(void *args) - pthread_mutex_unlock(&transform->mutex); - return MF_E_TRANSFORM_STREAM_CHANGE; - } -+ -+ if (buffer_format.major_type == WG_MAJOR_TYPE_VIDEO -+ && buffer_format.u.video.fps_n <= 1 -+ && buffer_format.u.video.fps_d <= 1) -+ broken_timestamp = true; - } - - gst_buffer_map(buffer, &info, GST_MAP_READ); -@@ -557,12 +563,12 @@ NTSTATUS wg_transform_read_data(void *args) - memcpy(read_sample->data, info.data, read_sample->size); - gst_buffer_unmap(buffer, &info); - -- if (buffer->pts != GST_CLOCK_TIME_NONE) -+ if (buffer->pts != GST_CLOCK_TIME_NONE && !broken_timestamp) - { - read_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; - read_sample->pts = buffer->pts / 100; - } -- if (buffer->duration != GST_CLOCK_TIME_NONE) -+ if (buffer->duration != GST_CLOCK_TIME_NONE && !broken_timestamp) - { - read_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; - read_sample->duration = buffer->duration / 100; -From 700febaaa6cfa82a10625bc48e780d365aa2f006 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 8 Feb 2022 11:21:39 +0100 -Subject: [PATCH] winegstreamer: Reset internal format on BEGIN_STREAMING - message. - -In order to regenerate a MF_E_TRANSFORM_STREAM_CHANGE status on next -successful ProcessOutput. CoD: Black Ops 3 depends on this, or crashes -if MF_E_TRANSFORM_STREAM_CHANGE isn't returned when the campaign intro -video begins to play. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index ba6e681890b..ede0bd36bce 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -522,7 +522,19 @@ static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, I - - static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -+ -+ switch (message) -+ { -+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: -+ memset(&decoder->wg_format, 0, sizeof(decoder->wg_format)); -+ break; -+ default: -+ break; -+ } -+ - return S_OK; - } - -From 36f27ef3ce2e9226724eaa4e31843ae436897217 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:36:32 +0100 -Subject: [PATCH] winegstreamer: Reimplement AAC decoder using wg_transform. - -For Call of Duty III, possibly others. This will need to be split. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/aac_decoder.c | 622 ++++++++++++++++++++++++++++++ - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 73 ++++ - dlls/winegstreamer/unixlib.h | 8 + - dlls/winegstreamer/wg_transform.c | 48 +++ - 6 files changed, 753 insertions(+) - create mode 100644 dlls/winegstreamer/aac_decoder.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index b8c61a316a0..71d741519f2 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -7,6 +7,7 @@ EXTRAINCL = $(GSTREAMER_CFLAGS) - EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) - - C_SRCS = \ -+ aac_decoder.c \ - audioconvert.c \ - h264_decoder.c \ - main.c \ -diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c -new file mode 100644 -index 00000000000..3b3383a52ab ---- /dev/null -+++ b/dlls/winegstreamer/aac_decoder.c -@@ -0,0 +1,622 @@ -+/* AAC Decoder Transform -+ * -+ * 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 -+ */ -+ -+#include "gst_private.h" -+ -+#include "mfapi.h" -+#include "mferror.h" -+#include "mfobjects.h" -+#include "mftransform.h" -+#include "wmcodecdsp.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -+ -+static const GUID *aac_decoder_input_types[] = -+{ -+ &MFAudioFormat_AAC, -+}; -+static const GUID *aac_decoder_output_types[] = -+{ -+ &MFAudioFormat_PCM, -+ &MFAudioFormat_Float, -+}; -+ -+struct aac_decoder -+{ -+ IMFTransform IMFTransform_iface; -+ LONG refcount; -+ IMFMediaType *input_type; -+ IMFMediaType *output_type; -+ -+ IMFSample *input_sample; -+ struct wg_transform *wg_transform; -+}; -+ -+static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) -+{ -+ return CONTAINING_RECORD(iface, struct aac_decoder, IMFTransform_iface); -+} -+ -+static void try_create_wg_transform(struct aac_decoder *decoder) -+{ -+ struct wg_encoded_format input_format; -+ struct wg_format output_format; -+ -+ if (!decoder->input_type || !decoder->output_type) -+ return; -+ -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); -+ -+ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); -+ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN) -+ return; -+ -+ mf_media_type_to_wg_format(decoder->output_type, &output_format); -+ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) -+ return; -+ -+ decoder->wg_transform = wg_transform_create(&input_format, &output_format); -+ if (!decoder->wg_transform) -+ WARN("Failed to create wg_transform.\n"); -+} -+ -+static HRESULT WINAPI aac_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ -+ TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); -+ -+ if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMFTransform)) -+ *out = &decoder->IMFTransform_iface; -+ else -+ { -+ *out = NULL; -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); -+ return E_NOINTERFACE; -+ } -+ -+ IUnknown_AddRef((IUnknown *)*out); -+ return S_OK; -+} -+ -+static ULONG WINAPI aac_decoder_AddRef(IMFTransform *iface) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ ULONG refcount = InterlockedIncrement(&decoder->refcount); -+ -+ TRACE("iface %p increasing refcount to %u.\n", decoder, refcount); -+ -+ return refcount; -+} -+ -+static ULONG WINAPI aac_decoder_Release(IMFTransform *iface) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ ULONG refcount = InterlockedDecrement(&decoder->refcount); -+ -+ TRACE("iface %p decreasing refcount to %u.\n", decoder, refcount); -+ -+ if (!refcount) -+ { -+ if (decoder->input_sample) -+ IMFSample_Release(decoder->input_sample); -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); -+ if (decoder->input_type) -+ IMFMediaType_Release(decoder->input_type); -+ if (decoder->output_type) -+ IMFMediaType_Release(decoder->output_type); -+ free(decoder); -+ } -+ -+ return refcount; -+} -+ -+static HRESULT WINAPI aac_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, -+ DWORD *output_minimum, DWORD *output_maximum) -+{ -+ FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n", -+ iface, input_minimum, input_maximum, output_minimum, output_maximum); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -+{ -+ FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, -+ DWORD output_size, DWORD *outputs) -+{ -+ FIXME("iface %p, input_size %u, inputs %p, output_size %u, outputs %p stub!\n", -+ iface, input_size, inputs, output_size, outputs); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ UINT32 block_alignment; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %u, info %p.\n", iface, id, info); -+ -+ if (!decoder->input_type || !decoder->output_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) -+ return hr; -+ -+ info->hnsMaxLatency = 0; -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES|MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER -+ |MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE|MFT_INPUT_STREAM_HOLDS_BUFFERS; -+ info->cbSize = 0; -+ info->cbMaxLookahead = 0; -+ info->cbAlignment = 0; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ UINT32 channel_count, block_alignment; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %u, info %p.\n", iface, id, info); -+ -+ if (!decoder->input_type || !decoder->output_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) -+ return hr; -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) -+ return hr; -+ -+ info->dwFlags = 0; -+ info->cbSize = 0x1800 * block_alignment * channel_count; -+ info->cbAlignment = 0; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI aac_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -+{ -+ FIXME("iface %p, attributes %p stub!\n", iface, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("iface %p, id %u, attributes %p stub!\n", iface, id, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("iface %p, id %u, attributes %p stub!\n", iface, id, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) -+{ -+ FIXME("iface %p, id %u stub!\n", iface, id); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -+{ -+ FIXME("iface %p, streams %u, ids %p stub!\n", iface, streams, ids); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("iface %p, id %u, index %u, type %p stub!\n", iface, id, index, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ UINT32 channel_count, sample_size, sample_rate, block_alignment; -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaType *media_type; -+ const GUID *output_type; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %u, index %u, type %p.\n", iface, id, index, type); -+ -+ if (!decoder->input_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *type = NULL; -+ -+ if (index >= ARRAY_SIZE(aac_decoder_output_types)) -+ return MF_E_NO_MORE_TYPES; -+ index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; -+ output_type = aac_decoder_output_types[index]; -+ -+ if (FAILED(hr = MFCreateMediaType(&media_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) -+ goto done; -+ -+ if (IsEqualGUID(output_type, &MFAudioFormat_Float)) -+ sample_size = 32; -+ else if (IsEqualGUID(output_type, &MFAudioFormat_PCM)) -+ sample_size = 16; -+ else -+ { -+ FIXME("Subtype %s not implemented!\n", debugstr_guid(output_type)); -+ hr = E_NOTIMPL; -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample_rate))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, sample_rate))) -+ goto done; -+ -+ block_alignment = sample_size * channel_count / 8; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, sample_rate * block_alignment))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) -+ goto done; -+ -+done: -+ if (SUCCEEDED(hr)) -+ IMFMediaType_AddRef((*type = media_type)); -+ -+ IMFMediaType_Release(media_type); -+ return hr; -+} -+ -+static HRESULT WINAPI aac_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ MF_ATTRIBUTE_TYPE item_type; -+ GUID major, subtype; -+ HRESULT hr; -+ ULONG i; -+ -+ TRACE("iface %p, id %u, type %p, flags %#x.\n", iface, id, type, flags); -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (!IsEqualGUID(&major, &MFMediaType_Audio)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(aac_decoder_input_types); ++i) -+ if (IsEqualGUID(&subtype, aac_decoder_input_types[i])) -+ break; -+ if (i == ARRAY_SIZE(aac_decoder_input_types)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_USER_DATA, &item_type)) || -+ item_type != MF_ATTRIBUTE_BLOB) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (!decoder->input_type && FAILED(hr = MFCreateMediaType(&decoder->input_type))) -+ return hr; -+ -+ if (decoder->output_type) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ -+ return IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->input_type); -+} -+ -+static HRESULT WINAPI aac_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ MF_ATTRIBUTE_TYPE item_type; -+ ULONG i, sample_size; -+ GUID major, subtype; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %u, type %p, flags %#x.\n", iface, id, type, flags); -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (!IsEqualGUID(&major, &MFMediaType_Audio)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(aac_decoder_output_types); ++i) -+ if (IsEqualGUID(&subtype, aac_decoder_output_types[i])) -+ break; -+ if (i == ARRAY_SIZE(aac_decoder_output_types)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (IsEqualGUID(&subtype, &MFAudioFormat_Float)) -+ sample_size = 32; -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_PCM)) -+ sample_size = 16; -+ else -+ { -+ FIXME("Subtype %s not implemented!\n", debugstr_guid(&subtype)); -+ hr = E_NOTIMPL; -+ return hr; -+ } -+ -+ if (FAILED(IMFMediaType_SetUINT32(decoder->input_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (!decoder->output_type && FAILED(hr = MFCreateMediaType(&decoder->output_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) -+ return hr; -+ -+ try_create_wg_transform(decoder); -+ return S_OK; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("iface %p, id %u, type %p stub!\n", iface, id, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("iface %p, id %u, type %p stub!\n", iface, id, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -+{ -+ FIXME("iface %p, id %u, flags %p stub!\n", iface, id, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) -+{ -+ FIXME("iface %p, flags %p stub!\n", iface, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -+{ -+ FIXME("iface %p, lower %s, upper %s stub!\n", iface, -+ wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -+{ -+ FIXME("iface %p, id %u, event %p stub!\n", iface, id, event); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -+{ -+ FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -+ return S_OK; -+} -+ -+static HRESULT WINAPI aac_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaBuffer *media_buffer; -+ MFT_INPUT_STREAM_INFO info; -+ UINT32 buffer_size; -+ BYTE *buffer; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %u, sample %p, flags %#x.\n", iface, id, sample, flags); -+ -+ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (decoder->input_sample) -+ return MF_E_NOTACCEPTING; -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &buffer_size))) -+ goto done; -+ -+ if (SUCCEEDED(hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size))) -+ IMFSample_AddRef((decoder->input_sample = sample)); -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; -+} -+ -+static HRESULT WINAPI aac_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ struct wg_sample wg_sample = {0}; -+ IMFMediaBuffer *media_buffer; -+ MFT_OUTPUT_STREAM_INFO info; -+ UINT32 buffer_size; -+ HRESULT hr; -+ -+ TRACE("iface %p, flags %#x, count %u, samples %p, status %p.\n", iface, flags, count, samples, status); -+ -+ if (count > 1) -+ { -+ FIXME("Not implemented count %u\n", count); -+ return E_NOTIMPL; -+ } -+ -+ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *status = 0; -+ samples[0].dwStatus = 0; -+ if (!samples[0].pSample) -+ { -+ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &wg_sample.size, NULL))) -+ goto done; -+ wg_sample.size = buffer_size; -+ -+ if (wg_sample.size < info.cbSize) -+ hr = MF_E_BUFFERTOOSMALL; -+ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -+ { -+ if (wg_sample.flags & WG_SAMPLE_FLAG_INCOMPLETE) -+ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; -+ } -+ else -+ { -+ if (decoder->input_sample) -+ IMFSample_Release(decoder->input_sample); -+ decoder->input_sample = NULL; -+ } -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; -+} -+ -+static const IMFTransformVtbl aac_decoder_vtbl = -+{ -+ aac_decoder_QueryInterface, -+ aac_decoder_AddRef, -+ aac_decoder_Release, -+ aac_decoder_GetStreamLimits, -+ aac_decoder_GetStreamCount, -+ aac_decoder_GetStreamIDs, -+ aac_decoder_GetInputStreamInfo, -+ aac_decoder_GetOutputStreamInfo, -+ aac_decoder_GetAttributes, -+ aac_decoder_GetInputStreamAttributes, -+ aac_decoder_GetOutputStreamAttributes, -+ aac_decoder_DeleteInputStream, -+ aac_decoder_AddInputStreams, -+ aac_decoder_GetInputAvailableType, -+ aac_decoder_GetOutputAvailableType, -+ aac_decoder_SetInputType, -+ aac_decoder_SetOutputType, -+ aac_decoder_GetInputCurrentType, -+ aac_decoder_GetOutputCurrentType, -+ aac_decoder_GetInputStatus, -+ aac_decoder_GetOutputStatus, -+ aac_decoder_SetOutputBounds, -+ aac_decoder_ProcessEvent, -+ aac_decoder_ProcessMessage, -+ aac_decoder_ProcessInput, -+ aac_decoder_ProcessOutput, -+}; -+ -+HRESULT aac_decoder_create(REFIID riid, void **ret) -+{ -+ struct aac_decoder *decoder; -+ -+ TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); -+ -+ if (!(decoder = calloc(1, sizeof(*decoder)))) -+ return E_OUTOFMEMORY; -+ -+ decoder->IMFTransform_iface.lpVtbl = &aac_decoder_vtbl; -+ decoder->refcount = 1; -+ -+ *ret = &decoder->IMFTransform_iface; -+ TRACE("Created decoder %p\n", *ret); -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 00fa2553d9a..0834de8bcab 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -127,6 +127,7 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; - -+HRESULT aac_decoder_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - HRESULT wma_decoder_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - HRESULT h264_decoder_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 4ff174a2083..008e95d46bf 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -30,6 +30,7 @@ - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - - DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); -+DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC, WAVE_FORMAT_RAW_AAC1); - - struct video_processor - { -@@ -401,11 +401,6 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a - - static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}}; - --static HRESULT aac_decoder_create(REFIID riid, void **ret) --{ -- return decode_transform_create(riid, ret, DECODER_TYPE_AAC); --} -- - static const struct class_object - { - const GUID *clsid; -@@ -838,6 +864,51 @@ static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct w - memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); - } - -+static void mf_media_type_to_wg_encoded_format_aac(IMFMediaType *type, struct wg_encoded_format *format) -+{ -+ UINT32 codec_data_len, payload_type, profile_level_indication; -+ BYTE codec_data[64]; -+ -+ /* Audio specific config is stored at after HEAACWAVEINFO in MF_MT_USER_DATA -+ * https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-heaacwaveformat -+ */ -+ struct -+ { -+ WORD payload_type; -+ WORD profile_level_indication; -+ WORD type; -+ WORD reserved1; -+ DWORD reserved2; -+ } *aac_info = (void *)codec_data; -+ -+ if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) -+ { -+ FIXME("Codec data is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &payload_type))) -+ { -+ FIXME("AAC payload type is not set.\n"); -+ payload_type = aac_info->payload_type; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &profile_level_indication))) -+ { -+ FIXME("AAC provile level indication is not set.\n"); -+ profile_level_indication = aac_info->profile_level_indication; -+ } -+ -+ format->encoded_type = WG_ENCODED_TYPE_AAC; -+ format->u.aac.payload_type = payload_type; -+ format->u.aac.profile_level_indication = profile_level_indication; -+ format->u.aac.codec_data_len = 0; -+ -+ if (codec_data_len > sizeof(*aac_info)) -+ { -+ format->u.aac.codec_data_len = codec_data_len - sizeof(*aac_info); -+ memcpy(format->u.aac.codec_data, codec_data + sizeof(*aac_info), codec_data_len - sizeof(*aac_info)); -+ } -+} -+ - static void mf_media_type_to_wg_encoded_format_h264(IMFMediaType *type, struct wg_encoded_format *format) - { - UINT64 frame_rate, frame_size; -@@ -897,6 +968,8 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 4); - else if (IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) - mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_XMA, 2); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) -+ mf_media_type_to_wg_encoded_format_aac(type, format); - else - FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); - } -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 2e9625fed4e..1566748def5 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -98,6 +98,7 @@ struct wg_encoded_format - WG_ENCODED_TYPE_UNKNOWN, - WG_ENCODED_TYPE_WMA, - WG_ENCODED_TYPE_XMA, -+ WG_ENCODED_TYPE_AAC, - WG_ENCODED_TYPE_H264, - } encoded_type; - -@@ -115,6 +116,13 @@ struct wg_encoded_format - unsigned char codec_data[64]; - } xwma; - struct -+ { -+ uint32_t payload_type; -+ uint32_t profile_level_indication; -+ uint32_t codec_data_len; -+ unsigned char codec_data[64]; -+ } aac; -+ struct - { - int32_t width, height; - uint32_t fps_n, fps_d; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 1c9dc6f72bb..775ac14e6a5 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -99,6 +99,52 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) - return caps; - } - -+static GstCaps *wg_format_to_caps_aac(const struct wg_encoded_format *format) -+{ -+ const char *profile, *level, *stream_format; -+ GstBuffer *buffer; -+ GstCaps *caps; -+ -+ caps = gst_caps_new_empty_simple("audio/mpeg"); -+ gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); -+ -+ switch (format->u.aac.payload_type) -+ { -+ case 0: stream_format = "raw"; break; -+ case 1: stream_format = "adts"; break; -+ case 2: stream_format = "adif"; break; -+ case 3: stream_format = "loas"; break; -+ default: stream_format = "raw"; break; -+ } -+ if (stream_format) -+ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, stream_format, NULL); -+ -+ switch (format->u.aac.profile_level_indication) -+ { -+ case 0x29: profile = "lc"; level = "2"; break; -+ case 0x2A: profile = "lc"; level = "4"; break; -+ case 0x2B: profile = "lc"; level = "5"; break; -+ default: -+ GST_FIXME("Unrecognized profile-level-indication %u\n", format->u.aac.profile_level_indication); -+ /* fallthrough */ -+ case 0x00: case 0xFE: profile = level = NULL; break; /* unspecified */ -+ } -+ if (profile) -+ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); -+ if (level) -+ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); -+ -+ if (format->u.aac.codec_data_len) -+ { -+ buffer = gst_buffer_new_and_alloc(format->u.aac.codec_data_len); -+ gst_buffer_fill(buffer, 0, format->u.aac.codec_data, format->u.aac.codec_data_len); -+ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); -+ gst_buffer_unref(buffer); -+ } -+ -+ return caps; -+} -+ - static GstCaps *wg_format_to_caps_h264(const struct wg_encoded_format *format) - { - const char *profile, *level; -@@ -166,6 +212,8 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format - case WG_ENCODED_TYPE_WMA: - case WG_ENCODED_TYPE_XMA: - return wg_format_to_caps_xwma(format); -+ case WG_ENCODED_TYPE_AAC: -+ return wg_format_to_caps_aac(format); - case WG_ENCODED_TYPE_H264: - return wg_format_to_caps_h264(format); - } -From 7ec3158fe73bbe005f18c67f4c2c6c0f9dd14334 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 24 Jan 2022 00:46:03 -0500 -Subject: [PATCH] winegstreamer: After failing to create decodebin parser, try - protonvideoconv. - ---- - dlls/winegstreamer/wg_parser.c | 69 +++++++++++++++++++++++++++++++++- - 1 file changed, 68 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 0db0519ff98..178c47d5d32 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -91,6 +91,8 @@ struct wg_parser - - bool unlimited_buffering; - struct wg_format input_format; -+ -+ bool use_mediaconv; - }; - - struct wg_parser_stream -@@ -943,6 +945,34 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, - return GST_AUTOPLUG_SELECT_TRY; - } - -+static gint find_videoconv_cb(gconstpointer a, gconstpointer b) -+{ -+ const GValue *val_a = a, *val_b = b; -+ GstElementFactory *factory_a = g_value_get_object(val_a), *factory_b = g_value_get_object(val_b); -+ const char *name_a = gst_element_factory_get_longname(factory_a), *name_b = gst_element_factory_get_longname(factory_b); -+ -+ if (!strcmp(name_a, "Proton video converter")) -+ return -1; -+ if (!strcmp(name_b, "Proton video converter")) -+ return 1; -+ return 0; -+} -+ -+static GValueArray *autoplug_sort_cb(GstElement *bin, GstPad *pad, -+ GstCaps *caps, GValueArray *factories, gpointer user) -+{ -+ struct wg_parser *parser = user; -+ GValueArray *ret = g_value_array_copy(factories); -+ -+ if (!parser->use_mediaconv) -+ return NULL; -+ -+ GST_DEBUG("parser %p.", parser); -+ -+ g_value_array_sort(ret, find_videoconv_cb); -+ return ret; -+} -+ - static void no_more_pads_cb(GstElement *element, gpointer user) - { - struct wg_parser *parser = user; -@@ -1801,9 +1831,12 @@ static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode - return FALSE; - } - -+static BOOL decodebin_parser_init_gst(struct wg_parser *parser); -+ - static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer user) - { - struct wg_parser *parser = user; -+ const GstStructure *structure; - gchar *dbg_info = NULL; - GError *err = NULL; - -@@ -1838,6 +1871,21 @@ static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer use - pthread_cond_signal(&parser->init_cond); - break; - -+ case GST_MESSAGE_ELEMENT: -+ structure = gst_message_get_structure(msg); -+ if (gst_structure_has_name(structure, "missing-plugin")) -+ { -+ pthread_mutex_lock(&parser->mutex); -+ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) -+ { -+ GST_WARNING("Autoplugged element failed to initialise, trying again with protonvideoconvert."); -+ parser->error = true; -+ pthread_cond_signal(&parser->init_cond); -+ } -+ pthread_mutex_unlock(&parser->mutex); -+ } -+ break; -+ - default: - break; - } -@@ -1976,6 +2024,7 @@ static NTSTATUS wg_parser_connect(void *args) - { - const struct wg_parser_connect_params *params = args; - struct wg_parser *parser = params->parser; -+ bool use_mediaconv = false; - unsigned int i; - HRESULT hr; - int ret; -@@ -1993,9 +2042,16 @@ static NTSTATUS wg_parser_connect(void *args) - if (!parser->pull_mode) - gst_pad_set_active(parser->my_src, 1); - ret = gst_element_get_state(parser->container, NULL, NULL, -1); -+ - if (ret == GST_STATE_CHANGE_FAILURE) - { -- GST_ERROR("Failed to play stream.\n"); -+ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst && parser->pull_mode) -+ { -+ GST_WARNING("Failed to play media, trying again with protonvideoconvert."); -+ use_mediaconv = true; -+ } -+ else -+ GST_ERROR("Failed to play stream.\n"); - goto out; - } - -@@ -2005,6 +2061,8 @@ static NTSTATUS wg_parser_connect(void *args) - pthread_cond_wait(&parser->init_cond, &parser->mutex); - if (parser->error) - { -+ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) -+ use_mediaconv = true; - pthread_mutex_unlock(&parser->mutex); - goto out; - } -@@ -2113,6 +2171,14 @@ static NTSTATUS wg_parser_connect(void *args) - pthread_mutex_unlock(&parser->mutex); - pthread_cond_signal(&parser->read_cond); - -+ if (use_mediaconv) -+ { -+ parser->use_mediaconv = true; -+ hr = wg_parser_connect(args); -+ parser->use_mediaconv = false; -+ return hr; -+ } -+ - return E_FAIL; - } - -@@ -2227,6 +2293,7 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) - g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); - g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); - g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); -+ g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); - g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); - - parser->their_sink = gst_element_get_static_pad(element, "sink"); -From 62f18137cb5ff9b468079d7d1f26a512bdb66c90 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 15 Feb 2022 10:51:42 +0100 -Subject: [PATCH] fixup! winegstreamer: After failing to create decodebin - parser, try protonvideoconv. - ---- - dlls/winegstreamer/wg_parser.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 89a64339413..337953db78d 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -30,6 +30,7 @@ - #include - #include - -+#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30 - #include - #include - #include -From 90c099fcb690675226493994c445df025ad00076 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Mon, 7 Feb 2022 17:19:31 -0600 -Subject: [PATCH] winegstreamer: Release stream_cs on error in stream_thread(). - -This fixes a deadlock when trying to skip video in Persona 4 Golden. - -Signed-off-by: Zebediah Figura -Signed-off-by: Alexandre Julliard -(cherry picked from commit fc5719e4c57079b19bde8d169bf0b55194649e73) ---- - dlls/winegstreamer/wm_asyncreader.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c -index aa15a5a77f9..12b63cd4ac1 100644 ---- a/dlls/winegstreamer/wm_asyncreader.c -+++ b/dlls/winegstreamer/wm_asyncreader.c -@@ -146,6 +146,7 @@ static DWORD WINAPI stream_thread(void *arg) - else if (hr != NS_E_NO_MORE_SAMPLES) - { - ERR("Failed to get sample, hr %#x.\n", hr); -+ LeaveCriticalSection(&reader->stream_cs); - return 0; - } - } -From e55e47086014d7a7be94da17b4be7cf312e8ad80 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Fri, 4 Feb 2022 16:44:54 -0600 -Subject: [PATCH] HACK: winegstreamer: Report BGRx for Persona 4 Golden. - ---- - dlls/winegstreamer/wm_reader.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index ab49045ddab..8d004662599 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -1508,6 +1508,17 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) - * Shadowgrounds provides wmv3 video and assumes that the initial - * video type will be BGR. */ - stream->format.u.video.format = WG_VIDEO_FORMAT_BGR; -+ { -+ /* HACK: Persona 4 Golden tries to read compressed samples, and -+ * then autoplug them via quartz to a filter that only accepts -+ * BGRx. This is not trivial to implement. Return BGRx from the -+ * wmvcore reader for now. */ -+ -+ const char *id = getenv("SteamGameId"); -+ -+ if (id && !strcmp(id, "1113000")) -+ stream->format.u.video.format = WG_VIDEO_FORMAT_BGRx; -+ } - } - wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL); - } -From 3e920115088e5320e7615ccb3fbe8403cc41e497 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Thu, 28 Oct 2021 17:46:32 -0500 -Subject: [PATCH] winegstreamer: Use unlimited buffering for the WM reader - objects. - ---- - dlls/winegstreamer/wm_reader.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index 8d004662599..594b16e318b 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -1455,7 +1455,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) - HRESULT hr; - WORD i; - -- if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) -+ if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) - return E_OUTOFMEMORY; - - reader->wg_parser = wg_parser; -From fbf46aeef3db5b3a9a58441ab6fd62501c183afb Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Thu, 28 Oct 2021 17:47:48 -0500 -Subject: [PATCH] HACK: winegstreamer: Report streams in reverse order for - wmvcore. - ---- - dlls/winegstreamer/wm_reader.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index 594b16e318b..905ce7306c8 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -1484,7 +1484,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) - { - struct wm_stream *stream = &reader->streams[i]; - -- stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i); -+ stream->wg_stream = wg_parser_get_stream(reader->wg_parser, reader->stream_count - i - 1); - stream->reader = reader; - stream->index = i; - stream->selection = WMT_ON; -diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c -index 0267381a44b..c397c241a57 100644 ---- a/dlls/mfplat/main.c -+++ b/dlls/mfplat/main.c -@@ -9094,6 +9095,7 @@ static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl = - HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager) - { - struct dxgi_device_manager *object; -+ const char *sgi = getenv("SteamGameId"); - const char *do_not_create = getenv("WINE_DO_NOT_CREATE_DXGI_DEVICE_MANAGER"); - - TRACE("%p, %p.\n", token, manager); -@@ -9103,7 +9105,18 @@ HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **man - * #19126 is solved. Returning a DXGI device manager also breaks - * Age of Empires Definitive Edition - this gameid should be removed - * once CW bug #19741 is solved. */ -- if (do_not_create && do_not_create[0] != '\0') -+ if (sgi && ( -+ strcmp(sgi, "305620") == 0 || /* The Long Dark */ -+ strcmp(sgi, "1110100") == 0 || /* Power Rangers: Battle for the Grid */ -+ strcmp(sgi, "1452500") == 0 || /* The Good Life */ -+ strcmp(sgi, "1741410") == 0 || /* The Good Life Demo */ -+ strcmp(sgi, "983970") == 0 || /* Haven */ -+ strcmp(sgi, "585420") == 0 || /* Trailmakers */ -+ strcmp(sgi, "684450") == 0 || /* Surviving the Aftermath */ -+ strcmp(sgi, "1017900") == 0 || /* Age of Empires: Definitive Edition */ -+ strcmp(sgi, "1331440") == 0 || /* FUSER */ -+ (do_not_create && do_not_create[0] != '\0') -+ )) - { - FIXME("stubbing out\n"); - return E_NOTIMPL; diff --git a/patches/proton/31-proton-mfplat-patches.patch b/patches/proton/31-proton-mfplat-patches.patch deleted file mode 100644 index a3c5e4fa6..000000000 --- a/patches/proton/31-proton-mfplat-patches.patch +++ /dev/null @@ -1,14556 +0,0 @@ -From d5d8ad87856a5b6737cb3343bcb521dbade62716 Mon Sep 17 00:00:00 2001 -From: Thomas Crider -Date: Sat, 19 Feb 2022 16:58:07 -0700 -Subject: [PATCH 1/4] Revert "winegstreamer: Create static pads on wg_transform - struct." - -This reverts commit 71bf5b24d7efabfcacfa707198efc4be0da3e446. ---- - dlls/winegstreamer/gst_private.h | 3 +- - dlls/winegstreamer/main.c | 9 ++---- - dlls/winegstreamer/unixlib.h | 2 -- - dlls/winegstreamer/wg_format.c | 40 ++---------------------- - dlls/winegstreamer/wg_transform.c | 51 +------------------------------ - dlls/winegstreamer/wma_decoder.c | 2 +- - 6 files changed, 7 insertions(+), 100 deletions(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index a63daaf04b9..8bc9f838d29 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -96,8 +96,7 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); - --struct wg_transform *wg_transform_create(const struct wg_format *input_format, -- const struct wg_format *output_format); -+struct wg_transform *wg_transform_create(void); - void wg_transform_destroy(struct wg_transform *transform); - - unsigned int wg_format_get_max_size(const struct wg_format *format); -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index f85e9995525..f23fa3abcdf 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -254,14 +254,9 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); - } - --struct wg_transform *wg_transform_create(const struct wg_format *input_format, -- const struct wg_format *output_format) -+struct wg_transform *wg_transform_create(void) - { -- struct wg_transform_create_params params = -- { -- .input_format = input_format, -- .output_format = output_format, -- }; -+ struct wg_transform_create_params params = {0}; - - if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) - return NULL; -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 4adbb694766..8e3f5e84bfb 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -232,8 +232,6 @@ struct wg_parser_stream_seek_params - struct wg_transform_create_params - { - struct wg_transform *transform; -- const struct wg_format *input_format; -- const struct wg_format *output_format; - }; - - enum unix_funcs -diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c -index 40b9acfefff..8f771bb8abd 100644 ---- a/dlls/winegstreamer/wg_format.c -+++ b/dlls/winegstreamer/wg_format.c -@@ -394,43 +394,6 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) - return caps; - } - --static GstCaps *wg_format_to_caps_wma(const struct wg_format *format) --{ -- GstBuffer *buffer; -- GstCaps *caps; -- -- if (!(caps = gst_caps_new_empty_simple("audio/x-wma"))) -- return NULL; -- if (format->u.wma.version) -- gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.wma.version, NULL); -- -- if (format->u.wma.bitrate) -- gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.wma.bitrate, NULL); -- if (format->u.wma.rate) -- gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.wma.rate, NULL); -- if (format->u.wma.depth) -- gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.wma.depth, NULL); -- if (format->u.wma.channels) -- gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.wma.channels, NULL); -- if (format->u.wma.block_align) -- gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.wma.block_align, NULL); -- -- if (format->u.wma.codec_data_len) -- { -- if (!(buffer = gst_buffer_new_and_alloc(format->u.wma.codec_data_len))) -- { -- gst_caps_unref(caps); -- return NULL; -- } -- -- gst_buffer_fill(buffer, 0, format->u.wma.codec_data, format->u.wma.codec_data_len); -- gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); -- gst_buffer_unref(buffer); -- } -- -- return caps; --} -- - GstCaps *wg_format_to_caps(const struct wg_format *format) - { - switch (format->major_type) -@@ -438,7 +401,8 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) - case WG_MAJOR_TYPE_UNKNOWN: - return NULL; - case WG_MAJOR_TYPE_WMA: -- return wg_format_to_caps_wma(format); -+ GST_FIXME("WMA format not implemented!\n"); -+ return NULL; - case WG_MAJOR_TYPE_AUDIO: - return wg_format_to_caps_audio(format); - case WG_MAJOR_TYPE_VIDEO: -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index e4545774428..2f225e5bc55 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -44,29 +44,13 @@ GST_DEBUG_CATEGORY_EXTERN(wine); - - struct wg_transform - { -- GstPad *my_src, *my_sink; -+ int dummy; - }; - --static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) --{ -- struct wg_transform *transform = gst_pad_get_element_private(pad); -- -- GST_INFO("transform %p, buffer %p.", transform, buffer); -- -- gst_buffer_unref(buffer); -- -- return GST_FLOW_OK; --} -- - NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; - -- if (transform->my_sink) -- g_object_unref(transform->my_sink); -- if (transform->my_src) -- g_object_unref(transform->my_src); -- - free(transform); - return STATUS_SUCCESS; - } -@@ -74,10 +58,6 @@ NTSTATUS wg_transform_destroy(void *args) - NTSTATUS wg_transform_create(void *args) - { - struct wg_transform_create_params *params = args; -- struct wg_format output_format = *params->output_format; -- struct wg_format input_format = *params->input_format; -- GstCaps *src_caps = NULL, *sink_caps = NULL; -- GstPadTemplate *template = NULL; - struct wg_transform *transform; - NTSTATUS status; - -@@ -89,38 +69,9 @@ NTSTATUS wg_transform_create(void *args) - if (!(transform = calloc(1, sizeof(*transform)))) - goto done; - -- if (!(src_caps = wg_format_to_caps(&input_format))) -- goto done; -- if (!(sink_caps = wg_format_to_caps(&output_format))) -- goto done; -- -- if (!(template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps))) -- goto done; -- if (!(transform->my_src = gst_pad_new_from_template(template, "src"))) -- goto done; -- g_object_unref(template); -- template = NULL; -- -- if (!(template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps))) -- goto done; -- if (!(transform->my_sink = gst_pad_new_from_template(template, "sink"))) -- goto done; -- g_object_unref(template); -- template = NULL; -- -- gst_pad_set_element_private(transform->my_sink, transform); -- gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); -- - status = STATUS_SUCCESS; - - done: -- if (template) -- g_object_unref(template); -- if (sink_caps) -- gst_caps_unref(sink_caps); -- if (src_caps) -- gst_caps_unref(src_caps); -- - if (status) - { - GST_ERROR("Failed to create winegstreamer transform."); -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index 6c198706944..b14261706a7 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -78,7 +78,7 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - -- if (!(decoder->wg_transform = wg_transform_create(&input_format, &output_format))) -+ if (!(decoder->wg_transform = wg_transform_create())) - return E_FAIL; - - return S_OK; --- -2.34.1 - -From 6dcd010c38461b1e2b9bfb30e425e63f8f58e4ae Mon Sep 17 00:00:00 2001 -From: Thomas Crider -Date: Sat, 19 Feb 2022 16:58:23 -0700 -Subject: [PATCH 2/4] Revert "winegstreamer: Introduce new wg_transform - struct." - -This reverts commit 51a262d368afca3ec1edf50a850dbd5339194280. ---- - dlls/winegstreamer/Makefile.in | 1 - - dlls/winegstreamer/gst_private.h | 3 -- - dlls/winegstreamer/main.c | 14 ----- - dlls/winegstreamer/unix_private.h | 5 -- - dlls/winegstreamer/unixlib.h | 8 --- - dlls/winegstreamer/wg_parser.c | 13 +---- - dlls/winegstreamer/wg_transform.c | 88 ------------------------------- - dlls/winegstreamer/wma_decoder.c | 11 ---- - 8 files changed, 2 insertions(+), 141 deletions(-) - delete mode 100644 dlls/winegstreamer/wg_transform.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 0bcdb3eec65..d9805e3d797 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -14,7 +14,6 @@ C_SRCS = \ - quartz_parser.c \ - wg_format.c \ - wg_parser.c \ -- wg_transform.c \ - wm_asyncreader.c \ - wm_reader.c \ - wm_syncreader.c \ -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 8bc9f838d29..3584f465218 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -96,9 +96,6 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); - --struct wg_transform *wg_transform_create(void); --void wg_transform_destroy(struct wg_transform *transform); -- - unsigned int wg_format_get_max_size(const struct wg_format *format); - - HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out); -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index f23fa3abcdf..260dd208e2f 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -254,20 +254,6 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); - } - --struct wg_transform *wg_transform_create(void) --{ -- struct wg_transform_create_params params = {0}; -- -- if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) -- return NULL; -- return params.transform; --} -- --void wg_transform_destroy(struct wg_transform *transform) --{ -- __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); --} -- - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - if (reason == DLL_PROCESS_ATTACH) -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index f9c4da2f6ea..b483638403d 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -25,13 +25,8 @@ - - #include - --extern bool init_gstreamer(void) DECLSPEC_HIDDEN; -- - extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; - extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; - extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; - --extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; --extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -- - #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 8e3f5e84bfb..45ec606fc6a 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -229,11 +229,6 @@ struct wg_parser_stream_seek_params - DWORD start_flags, stop_flags; - }; - --struct wg_transform_create_params --{ -- struct wg_transform *transform; --}; -- - enum unix_funcs - { - unix_wg_parser_create, -@@ -262,9 +257,6 @@ enum unix_funcs - - unix_wg_parser_stream_get_duration, - unix_wg_parser_stream_seek, -- -- unix_wg_transform_create, -- unix_wg_transform_destroy, - }; - - #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 5a2e970a4dd..a73685a2e69 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1570,13 +1570,6 @@ static void init_gstreamer_once(void) - gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); - } - --bool init_gstreamer(void) --{ -- static pthread_once_t init_once = PTHREAD_ONCE_INIT; -- -- return !pthread_once(&init_once, init_gstreamer_once); --} -- - static NTSTATUS wg_parser_create(void *args) - { - static const init_gst_cb init_funcs[] = -@@ -1587,10 +1580,11 @@ static NTSTATUS wg_parser_create(void *args) - [WG_PARSER_WAVPARSE] = wave_parser_init_gst, - }; - -+ static pthread_once_t once = PTHREAD_ONCE_INIT; - struct wg_parser_create_params *params = args; - struct wg_parser *parser; - -- if (!init_gstreamer()) -+ if (pthread_once(&once, init_gstreamer_once)) - return E_FAIL; - - if (!(parser = calloc(1, sizeof(*parser)))) -@@ -1657,7 +1651,4 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - - X(wg_parser_stream_get_duration), - X(wg_parser_stream_seek), -- -- X(wg_transform_create), -- X(wg_transform_destroy), - }; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -deleted file mode 100644 -index 2f225e5bc55..00000000000 ---- a/dlls/winegstreamer/wg_transform.c -+++ /dev/null -@@ -1,88 +0,0 @@ --/* -- * GStreamer transform backend -- * -- * 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 -- */ -- --#if 0 --#pragma makedep unix --#endif -- --#include "config.h" -- --#include --#include --#include -- --#include --#include --#include -- --#include "ntstatus.h" --#define WIN32_NO_STATUS --#include "winternl.h" --#include "dshow.h" -- --#include "unix_private.h" -- --GST_DEBUG_CATEGORY_EXTERN(wine); --#define GST_CAT_DEFAULT wine -- --struct wg_transform --{ -- int dummy; --}; -- --NTSTATUS wg_transform_destroy(void *args) --{ -- struct wg_transform *transform = args; -- -- free(transform); -- return STATUS_SUCCESS; --} -- --NTSTATUS wg_transform_create(void *args) --{ -- struct wg_transform_create_params *params = args; -- struct wg_transform *transform; -- NTSTATUS status; -- -- if (!init_gstreamer()) -- return STATUS_UNSUCCESSFUL; -- -- status = STATUS_NO_MEMORY; -- -- if (!(transform = calloc(1, sizeof(*transform)))) -- goto done; -- -- status = STATUS_SUCCESS; -- --done: -- if (status) -- { -- GST_ERROR("Failed to create winegstreamer transform."); -- if (transform) -- wg_transform_destroy(transform); -- } -- else -- { -- GST_INFO("Created winegstreamer transform %p.", transform); -- params->transform = transform; -- } -- -- return status; --} -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index b14261706a7..31f735a5b1d 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -53,8 +53,6 @@ struct wma_decoder - LONG refcount; - IMFMediaType *input_type; - IMFMediaType *output_type; -- -- struct wg_transform *wg_transform; - }; - - static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) -@@ -66,10 +64,6 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) - { - struct wg_format input_format, output_format; - -- if (decoder->wg_transform) -- wg_transform_destroy(decoder->wg_transform); -- decoder->wg_transform = NULL; -- - mf_media_type_to_wg_format(decoder->input_type, &input_format); - if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; -@@ -78,9 +72,6 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - -- if (!(decoder->wg_transform = wg_transform_create())) -- return E_FAIL; -- - return S_OK; - } - -@@ -128,8 +119,6 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) - - if (!refcount) - { -- if (decoder->wg_transform) -- wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) --- -2.34.1 - -From cfb590abfb385973218b2da4cace4c2e8d3d6649 Mon Sep 17 00:00:00 2001 -From: Thomas Crider -Date: Sat, 19 Feb 2022 16:58:47 -0700 -Subject: [PATCH 3/4] Revert "winegstreamer: Introduce new WG_MAJOR_TYPE_WMA - major type." - -This reverts commit 76e2883c4ace29279dce8ea58787871046227b1a. ---- - dlls/winegstreamer/mfplat.c | 109 ++++++----------------------- - dlls/winegstreamer/quartz_parser.c | 8 --- - dlls/winegstreamer/unixlib.h | 12 ---- - dlls/winegstreamer/wg_format.c | 7 -- - dlls/winegstreamer/wm_reader.c | 8 --- - dlls/winegstreamer/wma_decoder.c | 18 ----- - 6 files changed, 21 insertions(+), 141 deletions(-) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 9b3fc429d32..a111bbe196d 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -635,10 +635,6 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) - case WG_MAJOR_TYPE_UNKNOWN: - return NULL; - -- case WG_MAJOR_TYPE_WMA: -- FIXME("WMA format not implemented!\n"); -- return NULL; -- - case WG_MAJOR_TYPE_AUDIO: - return mf_media_type_from_wg_format_audio(format); - -@@ -650,11 +646,17 @@ IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format) - return NULL; - } - --static void mf_media_type_to_wg_format_audio(IMFMediaType *type, const GUID *subtype, struct wg_format *format) -+static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_format *format) - { - UINT32 rate, channels, channel_mask, depth; - unsigned int i; -+ GUID subtype; - -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ { -+ FIXME("Subtype is not set.\n"); -+ return; -+ } - if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) - { - FIXME("Sample rate is not set.\n"); -@@ -690,20 +692,26 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, const GUID *sub - - for (i = 0; i < ARRAY_SIZE(audio_formats); ++i) - { -- if (IsEqualGUID(subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) -+ if (IsEqualGUID(&subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) - { - format->u.audio.format = audio_formats[i].format; - return; - } - } -- FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(subtype), depth); -+ FIXME("Unrecognized audio subtype %s, depth %u.\n", debugstr_guid(&subtype), depth); - } - --static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *subtype, struct wg_format *format) -+static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_format *format) - { - UINT64 frame_rate, frame_size; - unsigned int i; -+ GUID subtype; - -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ { -+ FIXME("Subtype is not set.\n"); -+ return; -+ } - if (FAILED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) - { - FIXME("Frame size is not set.\n"); -@@ -724,80 +732,18 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, const GUID *sub - - for (i = 0; i < ARRAY_SIZE(video_formats); ++i) - { -- if (IsEqualGUID(subtype, video_formats[i].subtype)) -+ if (IsEqualGUID(&subtype, video_formats[i].subtype)) - { - format->u.video.format = video_formats[i].format; - return; - } - } -- FIXME("Unrecognized video subtype %s.\n", debugstr_guid(subtype)); --} -- --static void mf_media_type_to_wg_format_wma(IMFMediaType *type, const GUID *subtype, struct wg_format *format) --{ -- UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; -- BYTE codec_data[64]; -- UINT32 version; -- -- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) -- { -- FIXME("Sample rate is not set.\n"); -- return; -- } -- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels))) -- { -- FIXME("Channel count is not set.\n"); -- return; -- } -- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_align))) -- { -- FIXME("Block alignment is not set.\n"); -- return; -- } -- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth))) -- { -- FIXME("Depth is not set.\n"); -- return; -- } -- if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) -- { -- FIXME("Codec data is not set.\n"); -- return; -- } -- if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) -- { -- FIXME("Bitrate is not set.\n"); -- bytes_per_second = 0; -- } -- -- if (IsEqualGUID(subtype, &MEDIASUBTYPE_MSAUDIO1)) -- version = 1; -- else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV8)) -- version = 2; -- else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudioV9)) -- version = 3; -- else if (IsEqualGUID(subtype, &MFAudioFormat_WMAudio_Lossless)) -- version = 4; -- else -- { -- assert(0); -- return; -- } -- -- format->major_type = WG_MAJOR_TYPE_WMA; -- format->u.wma.version = version; -- format->u.wma.bitrate = bytes_per_second * 8; -- format->u.wma.rate = rate; -- format->u.wma.depth = depth; -- format->u.wma.channels = channels; -- format->u.wma.block_align = block_align; -- format->u.wma.codec_data_len = codec_data_len; -- memcpy(format->u.wma.codec_data, codec_data, codec_data_len); -+ FIXME("Unrecognized video subtype %s.\n", debugstr_guid(&subtype)); - } - - void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) - { -- GUID major_type, subtype; -+ GUID major_type; - - memset(format, 0, sizeof(*format)); - -@@ -806,24 +752,11 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) - FIXME("Major type is not set.\n"); - return; - } -- if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -- { -- FIXME("Subtype is not set.\n"); -- return; -- } - - if (IsEqualGUID(&major_type, &MFMediaType_Audio)) -- { -- if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1) || -- IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8) || -- IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9) || -- IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) -- mf_media_type_to_wg_format_wma(type, &subtype, format); -- else -- mf_media_type_to_wg_format_audio(type, &subtype, format); -- } -+ mf_media_type_to_wg_format_audio(type, format); - else if (IsEqualGUID(&major_type, &MFMediaType_Video)) -- mf_media_type_to_wg_format_video(type, &subtype, format); -+ mf_media_type_to_wg_format_video(type, format); - else - FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); - } -diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c -index e06c55ccfe0..45313ebda27 100644 ---- a/dlls/winegstreamer/quartz_parser.c -+++ b/dlls/winegstreamer/quartz_parser.c -@@ -319,10 +319,6 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) - break; - } - -- case WG_MAJOR_TYPE_WMA: -- FIXME("WMA format not implemented!\n"); -- return 0; -- - case WG_MAJOR_TYPE_UNKNOWN: - FIXME("Cannot guess maximum sample size for unknown format.\n"); - return 0; -@@ -417,10 +413,6 @@ bool amt_from_wg_format(AM_MEDIA_TYPE *mt, const struct wg_format *format, bool - case WG_MAJOR_TYPE_UNKNOWN: - return false; - -- case WG_MAJOR_TYPE_WMA: -- FIXME("WMA format not implemented!\n"); -- return false; -- - case WG_MAJOR_TYPE_AUDIO: - return amt_from_wg_format_audio(mt, format); - -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 45ec606fc6a..82bb534b938 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -37,7 +37,6 @@ struct wg_format - WG_MAJOR_TYPE_UNKNOWN, - WG_MAJOR_TYPE_VIDEO, - WG_MAJOR_TYPE_AUDIO, -- WG_MAJOR_TYPE_WMA, - } major_type; - - union -@@ -89,17 +88,6 @@ struct wg_format - uint32_t channel_mask; /* In WinMM format. */ - uint32_t rate; - } audio; -- struct -- { -- uint32_t version; -- uint32_t bitrate; -- uint32_t rate; -- uint32_t depth; -- uint32_t channels; -- uint32_t block_align; -- uint32_t codec_data_len; -- unsigned char codec_data[64]; -- } wma; - } u; - }; - -diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c -index 8f771bb8abd..8952acc1c2e 100644 ---- a/dlls/winegstreamer/wg_format.c -+++ b/dlls/winegstreamer/wg_format.c -@@ -400,9 +400,6 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) - { - case WG_MAJOR_TYPE_UNKNOWN: - return NULL; -- case WG_MAJOR_TYPE_WMA: -- GST_FIXME("WMA format not implemented!\n"); -- return NULL; - case WG_MAJOR_TYPE_AUDIO: - return wg_format_to_caps_audio(format); - case WG_MAJOR_TYPE_VIDEO: -@@ -422,10 +419,6 @@ bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) - case WG_MAJOR_TYPE_UNKNOWN: - return false; - -- case WG_MAJOR_TYPE_WMA: -- GST_FIXME("WMA format not implemented!\n"); -- return false; -- - case WG_MAJOR_TYPE_AUDIO: - return a->u.audio.format == b->u.audio.format - && a->u.audio.channels == b->u.audio.channels -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index 01518c6b9a8..d40afb66afd 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -1687,9 +1687,6 @@ HRESULT wm_reader_get_output_format_count(struct wm_reader *reader, DWORD output - *count = ARRAY_SIZE(video_formats); - break; - -- case WG_MAJOR_TYPE_WMA: -- FIXME("WMA format not implemented!\n"); -- /* fallthrough */ - case WG_MAJOR_TYPE_AUDIO: - case WG_MAJOR_TYPE_UNKNOWN: - *count = 1; -@@ -1736,9 +1733,6 @@ HRESULT wm_reader_get_output_format(struct wm_reader *reader, DWORD output, - format.u.audio.format = WG_AUDIO_FORMAT_S16LE; - break; - -- case WG_MAJOR_TYPE_WMA: -- FIXME("WMA format not implemented!\n"); -- break; - case WG_MAJOR_TYPE_UNKNOWN: - break; - } -@@ -1814,8 +1808,6 @@ static const char *get_major_type_string(enum wg_major_type type) - return "video"; - case WG_MAJOR_TYPE_UNKNOWN: - return "unknown"; -- case WG_MAJOR_TYPE_WMA: -- return "wma"; - } - assert(0); - return NULL; -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index 31f735a5b1d..78316059052 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -60,21 +60,6 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) - return CONTAINING_RECORD(iface, struct wma_decoder, IUnknown_inner); - } - --static HRESULT try_create_wg_transform(struct wma_decoder *decoder) --{ -- struct wg_format input_format, output_format; -- -- mf_media_type_to_wg_format(decoder->input_type, &input_format); -- if (input_format.major_type == WG_MAJOR_TYPE_UNKNOWN) -- return MF_E_INVALIDMEDIATYPE; -- -- mf_media_type_to_wg_format(decoder->output_type, &output_format); -- if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) -- return MF_E_INVALIDMEDIATYPE; -- -- return S_OK; --} -- - static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) - { - struct wma_decoder *decoder = impl_from_IUnknown(iface); -@@ -453,9 +438,6 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) - goto failed; - -- if (FAILED(hr = try_create_wg_transform(decoder))) -- goto failed; -- - return S_OK; - - failed: --- -2.34.1 - -From 07044e3029529ddaf34ac334aa7ffea8c9f90478 Mon Sep 17 00:00:00 2001 -From: Thomas Crider -Date: Sat, 19 Feb 2022 16:59:35 -0700 -Subject: [PATCH 4/4] Revert "winegstreamer: Move format helpers to a dedicated - source." - -This reverts commit a288b94831bcd9ef65c23475d8499e53fea69c18. ---- - dlls/winegstreamer/Makefile.in | 1 - - dlls/winegstreamer/unix_private.h | 32 --- - dlls/winegstreamer/wg_format.c | 436 ------------------------------ - dlls/winegstreamer/wg_parser.c | 397 ++++++++++++++++++++++++++- - 4 files changed, 395 insertions(+), 471 deletions(-) - delete mode 100644 dlls/winegstreamer/unix_private.h - delete mode 100644 dlls/winegstreamer/wg_format.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index d9805e3d797..c53e914e246 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -12,7 +12,6 @@ C_SRCS = \ - media_source.c \ - mfplat.c \ - quartz_parser.c \ -- wg_format.c \ - wg_parser.c \ - wm_asyncreader.c \ - wm_reader.c \ -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -deleted file mode 100644 -index b483638403d..00000000000 ---- a/dlls/winegstreamer/unix_private.h -+++ /dev/null -@@ -1,32 +0,0 @@ --/* -- * winegstreamer Unix library interface -- * -- * Copyright 2020-2021 Zebediah Figura 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 -- */ -- --#ifndef __WINE_WINEGSTREAMER_UNIX_PRIVATE_H --#define __WINE_WINEGSTREAMER_UNIX_PRIVATE_H -- --#include "unixlib.h" -- --#include -- --extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; --extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; --extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; -- --#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ -diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c -deleted file mode 100644 -index 8952acc1c2e..00000000000 ---- a/dlls/winegstreamer/wg_format.c -+++ /dev/null -@@ -1,436 +0,0 @@ --/* -- * GStreamer format helpers -- * -- * Copyright 2010 Maarten Lankhorst for CodeWeavers -- * Copyright 2010 Aric Stewart for CodeWeavers -- * Copyright 2019-2020 Zebediah Figura -- * -- * 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 -- */ -- --#if 0 --#pragma makedep unix --#endif -- --#include "config.h" -- --#include --#include --#include -- --#include --#include --#include -- --#include "winternl.h" --#include "dshow.h" -- --#include "unix_private.h" -- --GST_DEBUG_CATEGORY_EXTERN(wine); --#define GST_CAT_DEFAULT wine -- --static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) --{ -- switch (format) -- { -- case GST_AUDIO_FORMAT_U8: -- return WG_AUDIO_FORMAT_U8; -- case GST_AUDIO_FORMAT_S16LE: -- return WG_AUDIO_FORMAT_S16LE; -- case GST_AUDIO_FORMAT_S24LE: -- return WG_AUDIO_FORMAT_S24LE; -- case GST_AUDIO_FORMAT_S32LE: -- return WG_AUDIO_FORMAT_S32LE; -- case GST_AUDIO_FORMAT_F32LE: -- return WG_AUDIO_FORMAT_F32LE; -- case GST_AUDIO_FORMAT_F64LE: -- return WG_AUDIO_FORMAT_F64LE; -- default: -- return WG_AUDIO_FORMAT_UNKNOWN; -- } --} -- --static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position) --{ -- static const uint32_t position_map[] = -- { -- SPEAKER_FRONT_LEFT, -- SPEAKER_FRONT_RIGHT, -- SPEAKER_FRONT_CENTER, -- SPEAKER_LOW_FREQUENCY, -- SPEAKER_BACK_LEFT, -- SPEAKER_BACK_RIGHT, -- SPEAKER_FRONT_LEFT_OF_CENTER, -- SPEAKER_FRONT_RIGHT_OF_CENTER, -- SPEAKER_BACK_CENTER, -- 0, -- SPEAKER_SIDE_LEFT, -- SPEAKER_SIDE_RIGHT, -- SPEAKER_TOP_FRONT_LEFT, -- SPEAKER_TOP_FRONT_RIGHT, -- SPEAKER_TOP_FRONT_CENTER, -- SPEAKER_TOP_CENTER, -- SPEAKER_TOP_BACK_LEFT, -- SPEAKER_TOP_BACK_RIGHT, -- 0, -- 0, -- SPEAKER_TOP_BACK_CENTER, -- }; -- -- if (position == GST_AUDIO_CHANNEL_POSITION_MONO) -- return SPEAKER_FRONT_CENTER; -- -- if (position >= 0 && position < ARRAY_SIZE(position_map)) -- return position_map[position]; -- return 0; --} -- --static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info) --{ -- uint32_t mask = 0, position; -- unsigned int i; -- -- for (i = 0; i < GST_AUDIO_INFO_CHANNELS(info); ++i) -- { -- if (!(position = wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info, i)))) -- { -- GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info, i)); -- return 0; -- } -- /* Make sure it's also in WinMM order. WinMM mandates that channels be -- * ordered, as it were, from least to most significant SPEAKER_* bit. -- * Hence we fail if the current channel was already specified, or if any -- * higher bit was already specified. */ -- if (mask & ~(position - 1)) -- { -- GST_WARNING("Unsupported channel order."); -- return 0; -- } -- mask |= position; -- } -- return mask; --} -- --static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info) --{ -- format->major_type = WG_MAJOR_TYPE_AUDIO; -- format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info)); -- format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info); -- format->u.audio.channel_mask = wg_channel_mask_from_gst(info); -- format->u.audio.rate = GST_AUDIO_INFO_RATE(info); --} -- --static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) --{ -- switch (format) -- { -- case GST_VIDEO_FORMAT_BGRA: -- return WG_VIDEO_FORMAT_BGRA; -- case GST_VIDEO_FORMAT_BGRx: -- return WG_VIDEO_FORMAT_BGRx; -- case GST_VIDEO_FORMAT_BGR: -- return WG_VIDEO_FORMAT_BGR; -- case GST_VIDEO_FORMAT_RGB15: -- return WG_VIDEO_FORMAT_RGB15; -- case GST_VIDEO_FORMAT_RGB16: -- return WG_VIDEO_FORMAT_RGB16; -- case GST_VIDEO_FORMAT_AYUV: -- return WG_VIDEO_FORMAT_AYUV; -- case GST_VIDEO_FORMAT_I420: -- return WG_VIDEO_FORMAT_I420; -- case GST_VIDEO_FORMAT_NV12: -- return WG_VIDEO_FORMAT_NV12; -- case GST_VIDEO_FORMAT_UYVY: -- return WG_VIDEO_FORMAT_UYVY; -- case GST_VIDEO_FORMAT_YUY2: -- return WG_VIDEO_FORMAT_YUY2; -- case GST_VIDEO_FORMAT_YV12: -- return WG_VIDEO_FORMAT_YV12; -- case GST_VIDEO_FORMAT_YVYU: -- return WG_VIDEO_FORMAT_YVYU; -- default: -- return WG_VIDEO_FORMAT_UNKNOWN; -- } --} -- --static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info) --{ -- format->major_type = WG_MAJOR_TYPE_VIDEO; -- format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info)); -- format->u.video.width = GST_VIDEO_INFO_WIDTH(info); -- format->u.video.height = GST_VIDEO_INFO_HEIGHT(info); -- format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info); -- format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info); --} -- --static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps) --{ -- const GstStructure *structure = gst_caps_get_structure(caps, 0); -- gint layer, channels, rate; -- -- if (!gst_structure_get_int(structure, "layer", &layer)) -- { -- GST_WARNING("Missing \"layer\" value."); -- return; -- } -- if (!gst_structure_get_int(structure, "channels", &channels)) -- { -- GST_WARNING("Missing \"channels\" value."); -- return; -- } -- if (!gst_structure_get_int(structure, "rate", &rate)) -- { -- GST_WARNING("Missing \"rate\" value."); -- return; -- } -- -- format->major_type = WG_MAJOR_TYPE_AUDIO; -- -- if (layer == 1) -- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1; -- else if (layer == 2) -- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2; -- else if (layer == 3) -- format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3; -- -- format->u.audio.channels = channels; -- format->u.audio.rate = rate; --} -- --static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) --{ -- const GstStructure *structure = gst_caps_get_structure(caps, 0); -- gint width, height, fps_n, fps_d; -- -- if (!gst_structure_get_int(structure, "width", &width)) -- { -- GST_WARNING("Missing \"width\" value."); -- return; -- } -- if (!gst_structure_get_int(structure, "height", &height)) -- { -- GST_WARNING("Missing \"height\" value."); -- return; -- } -- if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) -- { -- fps_n = 0; -- fps_d = 1; -- } -- -- format->major_type = WG_MAJOR_TYPE_VIDEO; -- format->u.video.format = WG_VIDEO_FORMAT_CINEPAK; -- format->u.video.width = width; -- format->u.video.height = height; -- format->u.video.fps_n = fps_n; -- format->u.video.fps_d = fps_d; --} -- --void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) --{ -- const GstStructure *structure = gst_caps_get_structure(caps, 0); -- const char *name = gst_structure_get_name(structure); -- -- memset(format, 0, sizeof(*format)); -- -- if (!strcmp(name, "audio/x-raw")) -- { -- GstAudioInfo info; -- -- if (gst_audio_info_from_caps(&info, caps)) -- wg_format_from_audio_info(format, &info); -- } -- else if (!strcmp(name, "video/x-raw")) -- { -- GstVideoInfo info; -- -- if (gst_video_info_from_caps(&info, caps)) -- wg_format_from_video_info(format, &info); -- } -- else if (!strcmp(name, "audio/mpeg")) -- { -- wg_format_from_caps_audio_mpeg(format, caps); -- } -- else if (!strcmp(name, "video/x-cinepak")) -- { -- wg_format_from_caps_video_cinepak(format, caps); -- } -- else -- { -- gchar *str = gst_caps_to_string(caps); -- -- GST_FIXME("Unhandled caps %s.", str); -- g_free(str); -- } --} -- --static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format) --{ -- switch (format) -- { -- case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8; -- case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE; -- case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE; -- case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE; -- case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE; -- case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE; -- default: return GST_AUDIO_FORMAT_UNKNOWN; -- } --} -- --static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t mask, uint32_t channel_count) --{ -- const uint32_t orig_mask = mask; -- unsigned int i; -- DWORD bit; -- -- static const GstAudioChannelPosition position_map[] = -- { -- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, -- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, -- GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, -- GST_AUDIO_CHANNEL_POSITION_LFE1, -- GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, -- GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, -- GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, -- GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, -- GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, -- GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, -- GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, -- GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, -- GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, -- GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, -- GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, -- GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, -- GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, -- GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, -- }; -- -- for (i = 0; i < channel_count; ++i) -- { -- positions[i] = GST_AUDIO_CHANNEL_POSITION_NONE; -- if (BitScanForward(&bit, mask)) -- { -- if (bit < ARRAY_SIZE(position_map)) -- positions[i] = position_map[bit]; -- else -- GST_WARNING("Invalid channel mask %#x.\n", orig_mask); -- mask &= ~(1 << bit); -- } -- else -- { -- GST_WARNING("Incomplete channel mask %#x.\n", orig_mask); -- } -- } --} -- --static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) --{ -- GstAudioChannelPosition positions[32]; -- GstAudioFormat audio_format; -- GstAudioInfo info; -- -- if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN) -- return NULL; -- -- wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels); -- gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions); -- return gst_audio_info_to_caps(&info); --} -- --static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) --{ -- switch (format) -- { -- case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA; -- case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx; -- case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR; -- case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15; -- case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16; -- case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV; -- case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420; -- case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12; -- case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY; -- case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2; -- case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12; -- case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU; -- default: return GST_VIDEO_FORMAT_UNKNOWN; -- } --} -- --static GstCaps *wg_format_to_caps_video(const struct wg_format *format) --{ -- GstVideoFormat video_format; -- GstVideoInfo info; -- unsigned int i; -- GstCaps *caps; -- -- if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) -- return NULL; -- -- gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height)); -- if ((caps = gst_video_info_to_caps(&info))) -- { -- /* Clear some fields that shouldn't prevent us from connecting. */ -- for (i = 0; i < gst_caps_get_size(caps); ++i) -- { -- gst_structure_remove_fields(gst_caps_get_structure(caps, i), -- "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL); -- } -- } -- return caps; --} -- --GstCaps *wg_format_to_caps(const struct wg_format *format) --{ -- switch (format->major_type) -- { -- case WG_MAJOR_TYPE_UNKNOWN: -- return NULL; -- case WG_MAJOR_TYPE_AUDIO: -- return wg_format_to_caps_audio(format); -- case WG_MAJOR_TYPE_VIDEO: -- return wg_format_to_caps_video(format); -- } -- assert(0); -- return NULL; --} -- --bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) --{ -- if (a->major_type != b->major_type) -- return false; -- -- switch (a->major_type) -- { -- case WG_MAJOR_TYPE_UNKNOWN: -- return false; -- -- case WG_MAJOR_TYPE_AUDIO: -- return a->u.audio.format == b->u.audio.format -- && a->u.audio.channels == b->u.audio.channels -- && a->u.audio.rate == b->u.audio.rate; -- -- case WG_MAJOR_TYPE_VIDEO: -- /* Do not compare FPS. */ -- return a->u.video.format == b->u.video.format -- && a->u.video.width == b->u.video.width -- && abs(a->u.video.height) == abs(b->u.video.height); -- } -- -- assert(0); -- return false; --} -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index a73685a2e69..013566b25e9 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -37,7 +37,7 @@ - #include "winternl.h" - #include "dshow.h" - --#include "unix_private.h" -+#include "unixlib.h" - - typedef enum - { -@@ -51,7 +51,7 @@ typedef enum - * debug logging instead of Wine debug logging. In order to be safe we forbid - * any use of Wine debug logging in this entire file. */ - --GST_DEBUG_CATEGORY(wine); -+GST_DEBUG_CATEGORY_STATIC(wine); - #define GST_CAT_DEFAULT wine - - typedef BOOL (*init_gst_cb)(struct wg_parser *parser); -@@ -111,6 +111,399 @@ struct wg_parser_stream - uint64_t duration; - }; - -+static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) -+{ -+ switch (format) -+ { -+ case GST_AUDIO_FORMAT_U8: -+ return WG_AUDIO_FORMAT_U8; -+ case GST_AUDIO_FORMAT_S16LE: -+ return WG_AUDIO_FORMAT_S16LE; -+ case GST_AUDIO_FORMAT_S24LE: -+ return WG_AUDIO_FORMAT_S24LE; -+ case GST_AUDIO_FORMAT_S32LE: -+ return WG_AUDIO_FORMAT_S32LE; -+ case GST_AUDIO_FORMAT_F32LE: -+ return WG_AUDIO_FORMAT_F32LE; -+ case GST_AUDIO_FORMAT_F64LE: -+ return WG_AUDIO_FORMAT_F64LE; -+ default: -+ return WG_AUDIO_FORMAT_UNKNOWN; -+ } -+} -+ -+static uint32_t wg_channel_position_from_gst(GstAudioChannelPosition position) -+{ -+ static const uint32_t position_map[] = -+ { -+ SPEAKER_FRONT_LEFT, -+ SPEAKER_FRONT_RIGHT, -+ SPEAKER_FRONT_CENTER, -+ SPEAKER_LOW_FREQUENCY, -+ SPEAKER_BACK_LEFT, -+ SPEAKER_BACK_RIGHT, -+ SPEAKER_FRONT_LEFT_OF_CENTER, -+ SPEAKER_FRONT_RIGHT_OF_CENTER, -+ SPEAKER_BACK_CENTER, -+ 0, -+ SPEAKER_SIDE_LEFT, -+ SPEAKER_SIDE_RIGHT, -+ SPEAKER_TOP_FRONT_LEFT, -+ SPEAKER_TOP_FRONT_RIGHT, -+ SPEAKER_TOP_FRONT_CENTER, -+ SPEAKER_TOP_CENTER, -+ SPEAKER_TOP_BACK_LEFT, -+ SPEAKER_TOP_BACK_RIGHT, -+ 0, -+ 0, -+ SPEAKER_TOP_BACK_CENTER, -+ }; -+ -+ if (position == GST_AUDIO_CHANNEL_POSITION_MONO) -+ return SPEAKER_FRONT_CENTER; -+ -+ if (position >= 0 && position < ARRAY_SIZE(position_map)) -+ return position_map[position]; -+ return 0; -+} -+ -+static uint32_t wg_channel_mask_from_gst(const GstAudioInfo *info) -+{ -+ uint32_t mask = 0, position; -+ unsigned int i; -+ -+ for (i = 0; i < GST_AUDIO_INFO_CHANNELS(info); ++i) -+ { -+ if (!(position = wg_channel_position_from_gst(GST_AUDIO_INFO_POSITION(info, i)))) -+ { -+ GST_WARNING("Unsupported channel %#x.", GST_AUDIO_INFO_POSITION(info, i)); -+ return 0; -+ } -+ /* Make sure it's also in WinMM order. WinMM mandates that channels be -+ * ordered, as it were, from least to most significant SPEAKER_* bit. -+ * Hence we fail if the current channel was already specified, or if any -+ * higher bit was already specified. */ -+ if (mask & ~(position - 1)) -+ { -+ GST_WARNING("Unsupported channel order."); -+ return 0; -+ } -+ mask |= position; -+ } -+ return mask; -+} -+ -+static void wg_format_from_audio_info(struct wg_format *format, const GstAudioInfo *info) -+{ -+ format->major_type = WG_MAJOR_TYPE_AUDIO; -+ format->u.audio.format = wg_audio_format_from_gst(GST_AUDIO_INFO_FORMAT(info)); -+ format->u.audio.channels = GST_AUDIO_INFO_CHANNELS(info); -+ format->u.audio.channel_mask = wg_channel_mask_from_gst(info); -+ format->u.audio.rate = GST_AUDIO_INFO_RATE(info); -+} -+ -+static enum wg_video_format wg_video_format_from_gst(GstVideoFormat format) -+{ -+ switch (format) -+ { -+ case GST_VIDEO_FORMAT_BGRA: -+ return WG_VIDEO_FORMAT_BGRA; -+ case GST_VIDEO_FORMAT_BGRx: -+ return WG_VIDEO_FORMAT_BGRx; -+ case GST_VIDEO_FORMAT_BGR: -+ return WG_VIDEO_FORMAT_BGR; -+ case GST_VIDEO_FORMAT_RGB15: -+ return WG_VIDEO_FORMAT_RGB15; -+ case GST_VIDEO_FORMAT_RGB16: -+ return WG_VIDEO_FORMAT_RGB16; -+ case GST_VIDEO_FORMAT_AYUV: -+ return WG_VIDEO_FORMAT_AYUV; -+ case GST_VIDEO_FORMAT_I420: -+ return WG_VIDEO_FORMAT_I420; -+ case GST_VIDEO_FORMAT_NV12: -+ return WG_VIDEO_FORMAT_NV12; -+ case GST_VIDEO_FORMAT_UYVY: -+ return WG_VIDEO_FORMAT_UYVY; -+ case GST_VIDEO_FORMAT_YUY2: -+ return WG_VIDEO_FORMAT_YUY2; -+ case GST_VIDEO_FORMAT_YV12: -+ return WG_VIDEO_FORMAT_YV12; -+ case GST_VIDEO_FORMAT_YVYU: -+ return WG_VIDEO_FORMAT_YVYU; -+ default: -+ return WG_VIDEO_FORMAT_UNKNOWN; -+ } -+} -+ -+static void wg_format_from_video_info(struct wg_format *format, const GstVideoInfo *info) -+{ -+ format->major_type = WG_MAJOR_TYPE_VIDEO; -+ format->u.video.format = wg_video_format_from_gst(GST_VIDEO_INFO_FORMAT(info)); -+ format->u.video.width = GST_VIDEO_INFO_WIDTH(info); -+ format->u.video.height = GST_VIDEO_INFO_HEIGHT(info); -+ format->u.video.fps_n = GST_VIDEO_INFO_FPS_N(info); -+ format->u.video.fps_d = GST_VIDEO_INFO_FPS_D(info); -+} -+ -+static void wg_format_from_caps_audio_mpeg(struct wg_format *format, const GstCaps *caps) -+{ -+ const GstStructure *structure = gst_caps_get_structure(caps, 0); -+ gint layer, channels, rate; -+ -+ if (!gst_structure_get_int(structure, "layer", &layer)) -+ { -+ GST_WARNING("Missing \"layer\" value."); -+ return; -+ } -+ if (!gst_structure_get_int(structure, "channels", &channels)) -+ { -+ GST_WARNING("Missing \"channels\" value."); -+ return; -+ } -+ if (!gst_structure_get_int(structure, "rate", &rate)) -+ { -+ GST_WARNING("Missing \"rate\" value."); -+ return; -+ } -+ -+ format->major_type = WG_MAJOR_TYPE_AUDIO; -+ -+ if (layer == 1) -+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER1; -+ else if (layer == 2) -+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER2; -+ else if (layer == 3) -+ format->u.audio.format = WG_AUDIO_FORMAT_MPEG1_LAYER3; -+ -+ format->u.audio.channels = channels; -+ format->u.audio.rate = rate; -+} -+ -+static void wg_format_from_caps_video_cinepak(struct wg_format *format, const GstCaps *caps) -+{ -+ const GstStructure *structure = gst_caps_get_structure(caps, 0); -+ gint width, height, fps_n, fps_d; -+ -+ if (!gst_structure_get_int(structure, "width", &width)) -+ { -+ GST_WARNING("Missing \"width\" value."); -+ return; -+ } -+ if (!gst_structure_get_int(structure, "height", &height)) -+ { -+ GST_WARNING("Missing \"height\" value."); -+ return; -+ } -+ if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d)) -+ { -+ fps_n = 0; -+ fps_d = 1; -+ } -+ -+ format->major_type = WG_MAJOR_TYPE_VIDEO; -+ format->u.video.format = WG_VIDEO_FORMAT_CINEPAK; -+ format->u.video.width = width; -+ format->u.video.height = height; -+ format->u.video.fps_n = fps_n; -+ format->u.video.fps_d = fps_d; -+} -+ -+static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) -+{ -+ const GstStructure *structure = gst_caps_get_structure(caps, 0); -+ const char *name = gst_structure_get_name(structure); -+ -+ memset(format, 0, sizeof(*format)); -+ -+ if (!strcmp(name, "audio/x-raw")) -+ { -+ GstAudioInfo info; -+ -+ if (gst_audio_info_from_caps(&info, caps)) -+ wg_format_from_audio_info(format, &info); -+ } -+ else if (!strcmp(name, "video/x-raw")) -+ { -+ GstVideoInfo info; -+ -+ if (gst_video_info_from_caps(&info, caps)) -+ wg_format_from_video_info(format, &info); -+ } -+ else if (!strcmp(name, "audio/mpeg")) -+ { -+ wg_format_from_caps_audio_mpeg(format, caps); -+ } -+ else if (!strcmp(name, "video/x-cinepak")) -+ { -+ wg_format_from_caps_video_cinepak(format, caps); -+ } -+ else -+ { -+ gchar *str = gst_caps_to_string(caps); -+ -+ GST_FIXME("Unhandled caps %s.", str); -+ g_free(str); -+ } -+} -+ -+static GstAudioFormat wg_audio_format_to_gst(enum wg_audio_format format) -+{ -+ switch (format) -+ { -+ case WG_AUDIO_FORMAT_U8: return GST_AUDIO_FORMAT_U8; -+ case WG_AUDIO_FORMAT_S16LE: return GST_AUDIO_FORMAT_S16LE; -+ case WG_AUDIO_FORMAT_S24LE: return GST_AUDIO_FORMAT_S24LE; -+ case WG_AUDIO_FORMAT_S32LE: return GST_AUDIO_FORMAT_S32LE; -+ case WG_AUDIO_FORMAT_F32LE: return GST_AUDIO_FORMAT_F32LE; -+ case WG_AUDIO_FORMAT_F64LE: return GST_AUDIO_FORMAT_F64LE; -+ default: return GST_AUDIO_FORMAT_UNKNOWN; -+ } -+} -+ -+static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t mask, uint32_t channel_count) -+{ -+ const uint32_t orig_mask = mask; -+ unsigned int i; -+ DWORD bit; -+ -+ static const GstAudioChannelPosition position_map[] = -+ { -+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, -+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, -+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, -+ GST_AUDIO_CHANNEL_POSITION_LFE1, -+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, -+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, -+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, -+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, -+ GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, -+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, -+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, -+ GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, -+ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, -+ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, -+ GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, -+ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, -+ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, -+ GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, -+ }; -+ -+ for (i = 0; i < channel_count; ++i) -+ { -+ positions[i] = GST_AUDIO_CHANNEL_POSITION_NONE; -+ if (BitScanForward(&bit, mask)) -+ { -+ if (bit < ARRAY_SIZE(position_map)) -+ positions[i] = position_map[bit]; -+ else -+ GST_WARNING("Invalid channel mask %#x.\n", orig_mask); -+ mask &= ~(1 << bit); -+ } -+ else -+ { -+ GST_WARNING("Incomplete channel mask %#x.\n", orig_mask); -+ } -+ } -+} -+ -+static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) -+{ -+ GstAudioChannelPosition positions[32]; -+ GstAudioFormat audio_format; -+ GstAudioInfo info; -+ -+ if ((audio_format = wg_audio_format_to_gst(format->u.audio.format)) == GST_AUDIO_FORMAT_UNKNOWN) -+ return NULL; -+ -+ wg_channel_mask_to_gst(positions, format->u.audio.channel_mask, format->u.audio.channels); -+ gst_audio_info_set_format(&info, audio_format, format->u.audio.rate, format->u.audio.channels, positions); -+ return gst_audio_info_to_caps(&info); -+} -+ -+static GstVideoFormat wg_video_format_to_gst(enum wg_video_format format) -+{ -+ switch (format) -+ { -+ case WG_VIDEO_FORMAT_BGRA: return GST_VIDEO_FORMAT_BGRA; -+ case WG_VIDEO_FORMAT_BGRx: return GST_VIDEO_FORMAT_BGRx; -+ case WG_VIDEO_FORMAT_BGR: return GST_VIDEO_FORMAT_BGR; -+ case WG_VIDEO_FORMAT_RGB15: return GST_VIDEO_FORMAT_RGB15; -+ case WG_VIDEO_FORMAT_RGB16: return GST_VIDEO_FORMAT_RGB16; -+ case WG_VIDEO_FORMAT_AYUV: return GST_VIDEO_FORMAT_AYUV; -+ case WG_VIDEO_FORMAT_I420: return GST_VIDEO_FORMAT_I420; -+ case WG_VIDEO_FORMAT_NV12: return GST_VIDEO_FORMAT_NV12; -+ case WG_VIDEO_FORMAT_UYVY: return GST_VIDEO_FORMAT_UYVY; -+ case WG_VIDEO_FORMAT_YUY2: return GST_VIDEO_FORMAT_YUY2; -+ case WG_VIDEO_FORMAT_YV12: return GST_VIDEO_FORMAT_YV12; -+ case WG_VIDEO_FORMAT_YVYU: return GST_VIDEO_FORMAT_YVYU; -+ default: return GST_VIDEO_FORMAT_UNKNOWN; -+ } -+} -+ -+static GstCaps *wg_format_to_caps_video(const struct wg_format *format) -+{ -+ GstVideoFormat video_format; -+ GstVideoInfo info; -+ unsigned int i; -+ GstCaps *caps; -+ -+ if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) -+ return NULL; -+ -+ gst_video_info_set_format(&info, video_format, format->u.video.width, abs(format->u.video.height)); -+ if ((caps = gst_video_info_to_caps(&info))) -+ { -+ /* Clear some fields that shouldn't prevent us from connecting. */ -+ for (i = 0; i < gst_caps_get_size(caps); ++i) -+ { -+ gst_structure_remove_fields(gst_caps_get_structure(caps, i), -+ "framerate", "pixel-aspect-ratio", "colorimetry", "chroma-site", NULL); -+ } -+ } -+ return caps; -+} -+ -+static GstCaps *wg_format_to_caps(const struct wg_format *format) -+{ -+ switch (format->major_type) -+ { -+ case WG_MAJOR_TYPE_UNKNOWN: -+ return NULL; -+ case WG_MAJOR_TYPE_AUDIO: -+ return wg_format_to_caps_audio(format); -+ case WG_MAJOR_TYPE_VIDEO: -+ return wg_format_to_caps_video(format); -+ } -+ assert(0); -+ return NULL; -+} -+ -+static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) -+{ -+ if (a->major_type != b->major_type) -+ return false; -+ -+ switch (a->major_type) -+ { -+ case WG_MAJOR_TYPE_UNKNOWN: -+ return false; -+ -+ case WG_MAJOR_TYPE_AUDIO: -+ return a->u.audio.format == b->u.audio.format -+ && a->u.audio.channels == b->u.audio.channels -+ && a->u.audio.rate == b->u.audio.rate; -+ -+ case WG_MAJOR_TYPE_VIDEO: -+ /* Do not compare FPS. */ -+ return a->u.video.format == b->u.video.format -+ && a->u.video.width == b->u.video.width -+ && abs(a->u.video.height) == abs(b->u.video.height); -+ } -+ -+ assert(0); -+ return false; -+} -+ - static NTSTATUS wg_parser_get_stream_count(void *args) - { - struct wg_parser_get_stream_count_params *params = args; --- -2.34.1 - - -From efbf419a0405874dcd51dff3dcc177377921d9d1 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Wed, 21 Oct 2020 16:03:21 -0500 -Subject: [PATCH] winegstreamer: Allow videoconvert to parallelize. - -Not sure if this should be called a hack. It's not the *best* solution to the problem, but it's not a wrong one either. - -Signed-off-by: Zebediah Figura ---- - dlls/winegstreamer/wg_parser.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 0a6cf927187..5f3b4375b4c 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1189,6 +1189,9 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - if (!(vconv = create_element("videoconvert", "base"))) - goto out; - -+ /* Let GStreamer choose a default number of threads. */ -+ gst_util_set_object_arg(G_OBJECT(vconv), "n-threads", "0"); -+ - /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ - if (!(flip = create_element("videoflip", "good"))) - goto out; -From 26664823124d788c82f79bdf9001cc4109d2346c Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Tue, 20 Oct 2020 17:03:24 -0500 -Subject: [PATCH] HACK: winegstreamer: Use capssetter to ignore non-default YUV - color spaces. - ---- - dlls/winegstreamer/wg_parser.c | 53 ++++++++++++++++++++++++++++++++-- - 1 file changed, 51 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 5f3b4375b4c..b93b2c182ae 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1176,7 +1176,53 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - - if (!strcmp(name, "video/x-raw")) - { -- GstElement *deinterlace, *vconv, *flip, *vconv2; -+ GstElement *capssetter, *deinterlace, *vconv, *flip, *vconv2; -+ -+ /* Hack?: Flatten down the colorimetry to default values, without -+ * actually modifying the video at all. -+ * -+ * We want to do color matrix conversions when converting from YUV to -+ * RGB or vice versa. We do *not* want to do color matrix conversions -+ * when converting YUV <-> YUV or RGB <-> RGB, because these are slow -+ * (it essentially means always using the slow path, never going through -+ * liborc). However, we have two videoconvert elements, and it's -+ * basically impossible to know what conversions each is going to do -+ * until caps are negotiated (without depending on some implementation -+ * details, and even then it'snot exactly trivial). And setting -+ * matrix-mode after caps are negotiated has no effect. -+ * -+ * Nor can we just retain colorimetry information the way we retain -+ * other caps values, because videoconvert automatically clears it if -+ * not doing passthrough. I think that this would only happen if we have -+ * to do a double conversion, but that is possible. Not likely, but I -+ * don't want to have to be the one to find out that there's still a -+ * game broken. -+ * -+ * [Note that we'd actually kind of like to retain colorimetry -+ * information, just in case it does ever become relevant to pass that -+ * on to the next DirectShow filter. Hence I think the correct solution -+ * for upstream is to get videoconvert to Not Do That.] -+ * -+ * So as a fallback solution, we force an identity transformation of -+ * the caps to those with a "default" color matrix—i.e. transform the -+ * caps, but not the data. We do this by *pre*pending a capssetter to -+ * the front of the chain, and we remove the matrix-mode setting for the -+ * videoconvert elements. -+ */ -+ if (!(capssetter = gst_element_factory_make("capssetter", NULL))) -+ { -+ GST_ERROR("Failed to create capssetter, are %u-bit GStreamer \"good\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ goto out; -+ } -+ gst_util_set_object_arg(G_OBJECT(capssetter), "join", "true"); -+ /* Actually, this is invalid, but it causes videoconvert to use default -+ * colorimetry as a result. Yes, this is depending on undocumented -+ * implementation details. It's a hack. -+ * -+ * Sadly there doesn't seem to be a way to get capssetter to clear -+ * certain fields while leaving others untouched. */ -+ gst_util_set_object_arg(G_OBJECT(capssetter), "caps", "video/x-raw,colorimetry=0:0:0:0"); - - /* DirectShow can express interlaced video, but downstream filters can't - * necessarily consume it. In particular, the video renderer can't. */ -@@ -1202,6 +1248,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - goto out; - - /* The bin takes ownership of these elements. */ -+ gst_bin_add(GST_BIN(parser->container), capssetter); -+ gst_element_sync_state_with_parent(capssetter); - gst_bin_add(GST_BIN(parser->container), deinterlace); - gst_element_sync_state_with_parent(deinterlace); - gst_bin_add(GST_BIN(parser->container), vconv); -@@ -1211,11 +1259,12 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - gst_bin_add(GST_BIN(parser->container), vconv2); - gst_element_sync_state_with_parent(vconv2); - -+ gst_element_link(capssetter, deinterlace); - gst_element_link(deinterlace, vconv); - gst_element_link(vconv, flip); - gst_element_link(flip, vconv2); - -- stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); -+ stream->post_sink = gst_element_get_static_pad(capssetter, "sink"); - stream->post_src = gst_element_get_static_pad(vconv2, "src"); - stream->flip = flip; - } -From bac47475ac704e00f0706bcea91451f586ae8d00 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 6 Jul 2021 14:06:11 +0200 -Subject: [PATCH] HACK: quartz: Keep a reference on the IMediaPosition - interface. - -In the same way we do for IMediaSeeking. Both interfaces are actually -implemented with a shared refcount and releasing both makes the filter -be destroyed. - -For Tokyo Xanadu eX+ crash on launch. - -CW-Bug-Id: #18994 ---- - dlls/quartz/filtergraph.c | 24 ++++++++++++++++-------- - 1 file changed, 16 insertions(+), 8 deletions(-) - -diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c -index 62d22f96cea..e0da92f1596 100644 ---- a/dlls/quartz/filtergraph.c -+++ b/dlls/quartz/filtergraph.c -@@ -61,6 +61,7 @@ struct filter - struct list entry; - IBaseFilter *filter; - IMediaSeeking *seeking; -+ IMediaPosition *position; - WCHAR *name; - BOOL sorting; - }; -@@ -541,6 +542,7 @@ static BOOL has_output_pins(IBaseFilter *filter) - - static void update_seeking(struct filter *filter) - { -+ IMediaPosition *position; - IMediaSeeking *seeking; - - if (!filter->seeking) -@@ -559,11 +561,19 @@ static void update_seeking(struct filter *filter) - IMediaSeeking_Release(seeking); - } - } -+ -+ if (!filter->position) -+ { -+ /* Tokyo Xanadu eX+, same as above, same developer, destroys its filter when -+ * its IMediaPosition interface is released, so cache the interface instead -+ * of querying for it every time. */ -+ if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaPosition, (void **)&position))) -+ filter->position = position; -+ } - } - - static BOOL is_renderer(struct filter *filter) - { -- IMediaPosition *media_position; - IAMFilterMiscFlags *flags; - BOOL ret = FALSE; - -@@ -573,16 +583,11 @@ static BOOL is_renderer(struct filter *filter) - ret = TRUE; - IAMFilterMiscFlags_Release(flags); - } -- else if (SUCCEEDED(IBaseFilter_QueryInterface(filter->filter, &IID_IMediaPosition, (void **)&media_position))) -- { -- if (!has_output_pins(filter->filter)) -- ret = TRUE; -- IMediaPosition_Release(media_position); -- } - else - { - update_seeking(filter); -- if (filter->seeking && !has_output_pins(filter->filter)) -+ if ((filter->seeking || filter->position) && -+ !has_output_pins(filter->filter)) - ret = TRUE; - } - return ret; -@@ -653,6 +658,7 @@ static HRESULT WINAPI FilterGraph2_AddFilter(IFilterGraph2 *iface, - list_add_head(&graph->filters, &entry->entry); - entry->sorting = FALSE; - entry->seeking = NULL; -+ entry->position = NULL; - ++graph->version; - - return duplicate_name ? VFW_S_DUPLICATE_NAME : hr; -@@ -720,6 +726,8 @@ static HRESULT WINAPI FilterGraph2_RemoveFilter(IFilterGraph2 *iface, IBaseFilte - { - IBaseFilter_SetSyncSource(pFilter, NULL); - IBaseFilter_Release(pFilter); -+ if (entry->position) -+ IMediaPosition_Release(entry->position); - if (entry->seeking) - IMediaSeeking_Release(entry->seeking); - list_remove(&entry->entry); -From d8d9f10c92fdf6e0ebeb200f50ca0212a9932b8f Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 18 Mar 2021 16:54:44 -0400 -Subject: [PATCH] mfplat: Stub out MFCreateDXGIDeviceManager, to avoid the d3d - path. - ---- - dlls/mfplat/main.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) - -diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c -index 47454310234..f56652b2cdd 100644 ---- a/dlls/mfplat/main.c -+++ b/dlls/mfplat/main.c -@@ -9231,9 +9472,31 @@ static const IMFDXGIDeviceManagerVtbl dxgi_device_manager_vtbl = - HRESULT WINAPI MFCreateDXGIDeviceManager(UINT *token, IMFDXGIDeviceManager **manager) - { - struct dxgi_device_manager *object; -+ const char *sgi = getenv("SteamGameId"); -+ const char *do_not_create = getenv("PROTON_DO_NOT_CREATE_DXGI_DEVICE_MANAGER"); - - TRACE("%p, %p.\n", token, manager); - -+ /* Returning a DXGI device manager triggers a bug and breaks The -+ * Long Dark and Trailmakers. This should be removed once CW bug -+ * #19126 is solved. Returning a DXGI device manager also breaks -+ * Age of Empires Definitive Edition - this gameid should be removed -+ * once CW bug #19741 is solved. */ -+ if (sgi && ( -+ strcmp(sgi, "305620") == 0 || /* The Long Dark */ -+ strcmp(sgi, "1110100") == 0 || /* Power Rangers: Battle for the Grid */ -+ strcmp(sgi, "983970") == 0 || /* Haven */ -+ strcmp(sgi, "585420") == 0 || /* Trailmakers */ -+ strcmp(sgi, "684450") == 0 || /* Surviving the Aftermath */ -+ strcmp(sgi, "1017900") == 0 || /* Age of Empires: Definitive Edition */ -+ strcmp(sgi, "1331440") == 0 || /* FUSER */ -+ (do_not_create && do_not_create[0] != '\0') -+ )) -+ { -+ FIXME("stubbing out\n"); -+ return E_NOTIMPL; -+ } -+ - if (!token || !manager) - return E_POINTER; - -From e15d481b858b5441b40e5c487fcc6c2c9413cc3a Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Thu, 27 May 2021 19:40:45 +0200 -Subject: [PATCH] HACK: mfreadwrite: Ignore source reader flushes for The - Medium. - ---- - dlls/mfreadwrite/reader.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/dlls/mfreadwrite/reader.c b/dlls/mfreadwrite/reader.c -index 7bcb52eaaa6..163a734e506 100644 ---- a/dlls/mfreadwrite/reader.c -+++ b/dlls/mfreadwrite/reader.c -@@ -2021,10 +2021,20 @@ static HRESULT source_reader_flush_async(struct source_reader *reader, unsigned - static HRESULT WINAPI src_reader_Flush(IMFSourceReader *iface, DWORD index) - { - struct source_reader *reader = impl_from_IMFSourceReader(iface); -+ const char *sgi; - HRESULT hr; - - TRACE("%p, %#lx.\n", iface, index); - -+ sgi = getenv("SteamGameId"); -+ if (sgi && strcmp(sgi, "1293160") == 0) -+ { -+ /* In The Medium flushes sometimes lead to the callback -+ calling objects that have already been destroyed. */ -+ WARN("ignoring flush\n"); -+ return S_OK; -+ } -+ - EnterCriticalSection(&reader->cs); - - if (reader->async_callback) -From 5f45dece300837793ed1b8ecb7489124c7a1f738 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 6 Jul 2021 14:04:51 +0200 -Subject: [PATCH] HACK: qasf: Implement ASF Reader filter as a simple file - source. - -Shamelessly copied from quartz filesource.c. - -It then exposes a single MEDIATYPE_Stream pin, which should be -automatically plugged to the GStreamer decodebin filter and then to -application provided renderer. - -This is not how it's supposed to work, and it should instead be more -like a splitter filter able to expose compressed streams (and possibly -uncompressed streams too), and be implemented on top of wmvcore to -forward its interfaces as services, but this seems to work. - -The specific AttemptConnection implementation also seems important for -Tokyo Xanadu eX+, as using the default implementation with IMemInputPin -interface seems to cause it to crash as well. - -For Tokyo Xanadu eX+ crash on launch. - -CW-Bug-Id: #18994 ---- - dlls/qasf/Makefile.in | 2 +- - dlls/qasf/asfreader.c | 887 +++++++++++++++++++++++++++++++++++++++--- - 2 files changed, 834 insertions(+), 55 deletions(-) - -diff --git a/dlls/qasf/Makefile.in b/dlls/qasf/Makefile.in -index ee8fd0451e1..cc82f7736c3 100644 ---- a/dlls/qasf/Makefile.in -+++ b/dlls/qasf/Makefile.in -@@ -1,5 +1,5 @@ - MODULE = qasf.dll --IMPORTS = strmbase dmoguids strmiids uuid ole32 oleaut32 -+IMPORTS = strmbase dmoguids strmiids uuid ole32 oleaut32 kernelbase - - C_SRCS = \ - asfreader.c \ -diff --git a/dlls/qasf/asfreader.c b/dlls/qasf/asfreader.c -index a037728079f..3a355994851 100644 ---- a/dlls/qasf/asfreader.c -+++ b/dlls/qasf/asfreader.c -@@ -18,35 +18,341 @@ - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -+#define NONAMELESSUNION -+#define NONAMELESSSTRUCT -+ - #include "qasf_private.h" - -+#include "wine/debug.h" -+#include "wine/heap.h" -+#include "uuids.h" -+#include "vfwmsgs.h" -+#include "winbase.h" -+#include "winreg.h" -+#include "shlwapi.h" -+#include -+ - WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -+/* see IAsyncReader::Request on MSDN for the explanation of this */ -+#define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) -+#define BYTES_FROM_MEDIATIME(time) ((time) / 10000000) -+ -+static const AM_MEDIA_TYPE default_mt = -+{ -+ {0xe436eb83,0x524f,0x11ce,{0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70}}, /* MEDIATYPE_Stream */ -+ {0,0,0,{0,0,0,0,0,0,0,0}}, -+ TRUE, -+ FALSE, -+ 1, -+ {0,0,0,{0,0,0,0,0,0,0,0}}, -+ NULL, -+ 0, -+ NULL -+}; -+ -+struct request -+{ -+ IMediaSample *sample; -+ DWORD_PTR cookie; -+ OVERLAPPED ovl; -+}; -+ - struct asf_reader - { - struct strmbase_filter filter; - IFileSourceFilter IFileSourceFilter_iface; - -- AM_MEDIA_TYPE type; -- WCHAR *filename; -+ struct strmbase_source source; -+ IAsyncReader IAsyncReader_iface; -+ -+ LPOLESTR pszFileName; -+ AM_MEDIA_TYPE mt; -+ HANDLE file, port, io_thread; -+ LARGE_INTEGER file_size; -+ CRITICAL_SECTION sample_cs; -+ BOOL flushing; -+ struct request *requests; -+ unsigned int max_requests; -+ CONDITION_VARIABLE sample_cv; - }; - --static inline struct asf_reader *impl_reader_from_strmbase_filter(struct strmbase_filter *iface) -+static const struct strmbase_source_ops source_ops; -+ -+static inline struct asf_reader *impl_from_strmbase_filter(struct strmbase_filter *iface) - { - return CONTAINING_RECORD(iface, struct asf_reader, filter); - } - -+static inline struct asf_reader *impl_from_IFileSourceFilter(IFileSourceFilter *iface) -+{ -+ return CONTAINING_RECORD(iface, struct asf_reader, IFileSourceFilter_iface); -+} -+ -+static const IFileSourceFilterVtbl FileSource_Vtbl; -+static const IAsyncReaderVtbl FileAsyncReader_Vtbl; -+ -+static int byte_from_hex_char(WCHAR c) -+{ -+ if ('0' <= c && c <= '9') return c - '0'; -+ if ('a' <= c && c <= 'f') return c - 'a' + 10; -+ if ('A' <= c && c <= 'F') return c - 'A' + 10; -+ return -1; -+} -+ -+static BOOL process_pattern_string(const WCHAR *pattern, HANDLE file) -+{ -+ ULONG size, offset, i, ret_size; -+ BYTE *mask, *expect, *actual; -+ int d; -+ BOOL ret = TRUE; -+ -+ /* format: "offset, size, mask, value" */ -+ -+ offset = wcstol(pattern, NULL, 10); -+ -+ if (!(pattern = wcschr(pattern, ','))) -+ return FALSE; -+ pattern++; -+ -+ size = wcstol(pattern, NULL, 10); -+ mask = heap_alloc(size); -+ expect = heap_alloc(size); -+ memset(mask, 0xff, size); -+ -+ if (!(pattern = wcschr(pattern, ','))) -+ { -+ heap_free(mask); -+ heap_free(expect); -+ return FALSE; -+ } -+ pattern++; -+ while (byte_from_hex_char(*pattern) == -1 && (*pattern != ',')) -+ pattern++; -+ -+ for (i = 0; (d = byte_from_hex_char(*pattern)) != -1 && (i/2 < size); pattern++, i++) -+ { -+ if (i % 2) -+ mask[i / 2] |= d; -+ else -+ mask[i / 2] = d << 4; -+ } -+ -+ if (!(pattern = wcschr(pattern, ','))) -+ { -+ heap_free(mask); -+ heap_free(expect); -+ return FALSE; -+ } -+ pattern++; -+ while (byte_from_hex_char(*pattern) == -1 && (*pattern != ',')) -+ pattern++; -+ -+ for (i = 0; (d = byte_from_hex_char(*pattern)) != -1 && (i/2 < size); pattern++, i++) -+ { -+ if (i % 2) -+ expect[i / 2] |= d; -+ else -+ expect[i / 2] = d << 4; -+ } -+ -+ actual = heap_alloc(size); -+ SetFilePointer(file, offset, NULL, FILE_BEGIN); -+ if (!ReadFile(file, actual, size, &ret_size, NULL) || ret_size != size) -+ { -+ heap_free(actual); -+ heap_free(expect); -+ heap_free(mask); -+ return FALSE; -+ } -+ -+ for (i = 0; i < size; ++i) -+ { -+ if ((actual[i] & mask[i]) != expect[i]) -+ { -+ ret = FALSE; -+ break; -+ } -+ } -+ -+ heap_free(actual); -+ heap_free(expect); -+ heap_free(mask); -+ -+ /* If there is a following tuple, then we must match that as well. */ -+ if (ret && (pattern = wcschr(pattern, ','))) -+ return process_pattern_string(pattern + 1, file); -+ -+ return ret; -+} -+ -+BOOL get_media_type(const WCHAR *filename, GUID *majortype, GUID *subtype, GUID *source_clsid) -+{ -+ WCHAR extensions_path[278] = L"Media Type\\Extensions\\"; -+ DWORD majortype_idx, size; -+ const WCHAR *ext; -+ HKEY parent_key; -+ HANDLE file; -+ -+ if ((ext = wcsrchr(filename, '.'))) -+ { -+ WCHAR guidstr[39]; -+ HKEY key; -+ -+ wcscat(extensions_path, ext); -+ if (!RegOpenKeyExW(HKEY_CLASSES_ROOT, extensions_path, 0, KEY_READ, &key)) -+ { -+ size = sizeof(guidstr); -+ if (majortype && !RegQueryValueExW(key, L"Media Type", NULL, NULL, (BYTE *)guidstr, &size)) -+ CLSIDFromString(guidstr, majortype); -+ -+ size = sizeof(guidstr); -+ if (subtype && !RegQueryValueExW(key, L"Subtype", NULL, NULL, (BYTE *)guidstr, &size)) -+ CLSIDFromString(guidstr, subtype); -+ -+ size = sizeof(guidstr); -+ if (source_clsid && !RegQueryValueExW(key, L"Source Filter", NULL, NULL, (BYTE *)guidstr, &size)) -+ CLSIDFromString(guidstr, source_clsid); -+ -+ RegCloseKey(key); -+ return FALSE; -+ } -+ } -+ -+ if ((file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, -+ OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) -+ { -+ WARN("Failed to open file %s, error %u.\n", debugstr_w(filename), GetLastError()); -+ return FALSE; -+ } -+ -+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Media Type", 0, KEY_READ, &parent_key)) -+ { -+ CloseHandle(file); -+ return FALSE; -+ } -+ -+ for (majortype_idx = 0; ; ++majortype_idx) -+ { -+ WCHAR majortype_str[39]; -+ HKEY majortype_key; -+ DWORD subtype_idx; -+ -+ size = ARRAY_SIZE(majortype_str); -+ if (RegEnumKeyExW(parent_key, majortype_idx, majortype_str, &size, NULL, NULL, NULL, NULL)) -+ break; -+ -+ if (!wcscmp(majortype_str, L"Extensions")) -+ continue; -+ -+ if (RegOpenKeyExW(parent_key, majortype_str, 0, KEY_READ, &majortype_key)) -+ continue; -+ -+ for (subtype_idx = 0; ; ++subtype_idx) -+ { -+ WCHAR subtype_str[39], *pattern; -+ DWORD value_idx, max_size; -+ HKEY subtype_key; -+ -+ size = ARRAY_SIZE(subtype_str); -+ if (RegEnumKeyExW(majortype_key, subtype_idx, subtype_str, &size, NULL, NULL, NULL, NULL)) -+ break; -+ -+ if (RegOpenKeyExW(majortype_key, subtype_str, 0, KEY_READ, &subtype_key)) -+ continue; -+ -+ if (RegQueryInfoKeyW(subtype_key, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &max_size, NULL, NULL)) -+ continue; -+ -+ pattern = heap_alloc(max_size); -+ -+ for (value_idx = 0; ; ++value_idx) -+ { -+ /* The longest name we should encounter is "Source Filter". */ -+ WCHAR value_name[14], source_clsid_str[39]; -+ DWORD value_len = ARRAY_SIZE(value_name); -+ -+ size = max_size; -+ if (RegEnumValueW(subtype_key, value_idx, value_name, &value_len, -+ NULL, NULL, (BYTE *)pattern, &max_size)) -+ break; -+ -+ if (!wcscmp(value_name, L"Source Filter")) -+ continue; -+ -+ if (!process_pattern_string(pattern, file)) -+ continue; -+ -+ if (majortype) -+ CLSIDFromString(majortype_str, majortype); -+ if (subtype) -+ CLSIDFromString(subtype_str, subtype); -+ size = sizeof(source_clsid_str); -+ if (source_clsid && !RegQueryValueExW(subtype_key, L"Source Filter", -+ NULL, NULL, (BYTE *)source_clsid_str, &size)) -+ CLSIDFromString(source_clsid_str, source_clsid); -+ -+ heap_free(pattern); -+ RegCloseKey(subtype_key); -+ RegCloseKey(majortype_key); -+ RegCloseKey(parent_key); -+ CloseHandle(file); -+ return TRUE; -+ } -+ -+ heap_free(pattern); -+ RegCloseKey(subtype_key); -+ } -+ -+ RegCloseKey(majortype_key); -+ } -+ -+ RegCloseKey(parent_key); -+ CloseHandle(file); -+ return FALSE; -+} -+ - static struct strmbase_pin *asf_reader_get_pin(struct strmbase_filter *iface, unsigned int index) - { -+ struct asf_reader *filter = impl_from_strmbase_filter(iface); -+ -+ if (!index && filter->pszFileName) -+ return &filter->source.pin; - return NULL; - } - - static void asf_reader_destroy(struct strmbase_filter *iface) - { -- struct asf_reader *filter = impl_reader_from_strmbase_filter(iface); -+ struct asf_reader *filter = impl_from_strmbase_filter(iface); -+ -+ if (filter->pszFileName) -+ { -+ unsigned int i; -+ -+ if (filter->source.pin.peer) -+ IPin_Disconnect(filter->source.pin.peer); -+ -+ IPin_Disconnect(&filter->source.pin.IPin_iface); -+ -+ if (filter->requests) -+ { -+ for (i = 0; i < filter->max_requests; ++i) -+ CloseHandle(filter->requests[i].ovl.hEvent); -+ free(filter->requests); -+ } -+ CloseHandle(filter->file); -+ filter->sample_cs.DebugInfo->Spare[0] = 0; -+ DeleteCriticalSection(&filter->sample_cs); -+ strmbase_source_cleanup(&filter->source); -+ -+ free(filter->pszFileName); -+ FreeMediaType(&filter->mt); -+ } - -- free(filter->filename); -- FreeMediaType(&filter->type); -+ PostQueuedCompletionStatus(filter->port, 0, 1, NULL); -+ WaitForSingleObject(filter->io_thread, INFINITE); -+ CloseHandle(filter->io_thread); -+ CloseHandle(filter->port); - - strmbase_filter_cleanup(&filter->filter); - free(filter); -@@ -54,7 +360,7 @@ static void asf_reader_destroy(struct strmbase_filter *iface) - - static HRESULT asf_reader_query_interface(struct strmbase_filter *iface, REFIID iid, void **out) - { -- struct asf_reader *filter = impl_reader_from_strmbase_filter(iface); -+ struct asf_reader *filter = impl_from_strmbase_filter(iface); - - if (IsEqualGUID(iid, &IID_IFileSourceFilter)) - { -@@ -66,110 +372,583 @@ static HRESULT asf_reader_query_interface(struct strmbase_filter *iface, REFIID - return E_NOINTERFACE; - } - --static struct strmbase_filter_ops filter_ops = -+static const struct strmbase_filter_ops filter_ops = - { - .filter_get_pin = asf_reader_get_pin, - .filter_destroy = asf_reader_destroy, - .filter_query_interface = asf_reader_query_interface, - }; - --static inline struct asf_reader *impl_from_IFileSourceFilter(IFileSourceFilter *iface) -+static DWORD CALLBACK io_thread(void *arg) - { -- return CONTAINING_RECORD(iface, struct asf_reader, IFileSourceFilter_iface); -+ struct asf_reader *filter = arg; -+ struct request *req; -+ OVERLAPPED *ovl; -+ ULONG_PTR key; -+ DWORD size; -+ BOOL ret; -+ -+ for (;;) -+ { -+ ret = GetQueuedCompletionStatus(filter->port, &size, &key, &ovl, INFINITE); -+ -+ if (ret && key) -+ break; -+ -+ EnterCriticalSection(&filter->sample_cs); -+ -+ req = CONTAINING_RECORD(ovl, struct request, ovl); -+ TRACE("Got sample %u.\n", req - filter->requests); -+ assert(req >= filter->requests && req < filter->requests + filter->max_requests); -+ -+ if (ret) -+ WakeConditionVariable(&filter->sample_cv); -+ else -+ { -+ ERR("GetQueuedCompletionStatus() returned failure, error %u.\n", GetLastError()); -+ req->sample = NULL; -+ } -+ -+ LeaveCriticalSection(&filter->sample_cs); -+ } -+ -+ return 0; - } - --static HRESULT WINAPI filesourcefilter_QueryInterface(IFileSourceFilter *iface, REFIID iid, void **out) -+HRESULT asf_reader_create(IUnknown *outer, IUnknown **out) - { -- struct asf_reader *filter = impl_from_IFileSourceFilter(iface); -+ struct asf_reader *object; -+ -+ if (!(object = calloc(1, sizeof(*object)))) -+ return E_OUTOFMEMORY; - -- return IBaseFilter_QueryInterface(&filter->filter.IBaseFilter_iface, iid, out); -+ strmbase_filter_init(&object->filter, outer, &CLSID_AsyncReader, &filter_ops); -+ -+ object->IFileSourceFilter_iface.lpVtbl = &FileSource_Vtbl; -+ object->IAsyncReader_iface.lpVtbl = &FileAsyncReader_Vtbl; -+ -+ InitializeCriticalSection(&object->sample_cs); -+ object->sample_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FileAsyncReader.sample_cs"); -+ InitializeConditionVariable(&object->sample_cv); -+ object->port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); -+ object->io_thread = CreateThread(NULL, 0, io_thread, object, 0, NULL); -+ -+ TRACE("Created file source %p.\n", object); -+ *out = &object->filter.IUnknown_inner; -+ return S_OK; - } - --static ULONG WINAPI filesourcefilter_AddRef(IFileSourceFilter *iface) -+static HRESULT WINAPI FileSource_QueryInterface(IFileSourceFilter * iface, REFIID riid, LPVOID * ppv) - { - struct asf_reader *filter = impl_from_IFileSourceFilter(iface); -+ return IBaseFilter_QueryInterface(&filter->filter.IBaseFilter_iface, riid, ppv); -+} - -+static ULONG WINAPI FileSource_AddRef(IFileSourceFilter * iface) -+{ -+ struct asf_reader *filter = impl_from_IFileSourceFilter(iface); - return IBaseFilter_AddRef(&filter->filter.IBaseFilter_iface); - } - --static ULONG WINAPI filesourcefilter_Release(IFileSourceFilter *iface) -+static ULONG WINAPI FileSource_Release(IFileSourceFilter * iface) - { - struct asf_reader *filter = impl_from_IFileSourceFilter(iface); -- - return IBaseFilter_Release(&filter->filter.IBaseFilter_iface); - } - --static HRESULT WINAPI filesourcefilter_Load(IFileSourceFilter *iface, LPCOLESTR filename, const AM_MEDIA_TYPE *type) -+static HRESULT WINAPI FileSource_Load(IFileSourceFilter * iface, LPCOLESTR pszFileName, const AM_MEDIA_TYPE * pmt) - { -- struct asf_reader *filter = impl_from_IFileSourceFilter(iface); -+ struct asf_reader *This = impl_from_IFileSourceFilter(iface); -+ HANDLE hFile; - -- TRACE("filter %p, filename %s, type %p.\n", filter, debugstr_w(filename), type); -- strmbase_dump_media_type(type); -+ TRACE("%p->(%s, %p)\n", This, debugstr_w(pszFileName), pmt); -+ strmbase_dump_media_type(pmt); - -- if (!filename) -+ if (!pszFileName) - return E_POINTER; - -- if (filter->filename) -- return E_FAIL; -+ /* open file */ -+ /* FIXME: check the sharing values that native uses */ -+ hFile = CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); -+ -+ if (hFile == INVALID_HANDLE_VALUE) -+ { -+ return HRESULT_FROM_WIN32(GetLastError()); -+ } -+ -+ if (!GetFileSizeEx(hFile, &This->file_size)) -+ { -+ WARN("Could not get file size.\n"); -+ CloseHandle(hFile); -+ return HRESULT_FROM_WIN32(GetLastError()); -+ } -+ -+ if (This->pszFileName) -+ { -+ free(This->pszFileName); -+ FreeMediaType(&This->mt); -+ } - -- if (!(filter->filename = wcsdup(filename))) -+ if (!(This->pszFileName = wcsdup(pszFileName))) -+ { -+ CloseHandle(hFile); - return E_OUTOFMEMORY; -+ } -+ -+ strmbase_source_init(&This->source, &This->filter, L"Output", &source_ops); -+ BaseFilterImpl_IncrementPinVersion(&This->filter); -+ -+ This->file = hFile; -+ This->flushing = FALSE; -+ This->requests = NULL; - -- if (type) -- CopyMediaType(&filter->type, type); -+ if (!pmt) -+ { -+ CopyMediaType(&This->mt, &default_mt); -+ if (get_media_type(pszFileName, &This->mt.majortype, &This->mt.subtype, NULL)) -+ { -+ TRACE("Found major type %s, subtype %s.\n", -+ debugstr_guid(&This->mt.majortype), debugstr_guid(&This->mt.subtype)); -+ } -+ } -+ else -+ CopyMediaType(&This->mt, pmt); - - return S_OK; - } - --static HRESULT WINAPI filesourcefilter_GetCurFile(IFileSourceFilter *iface, LPOLESTR *filename, AM_MEDIA_TYPE *type) -+static HRESULT WINAPI FileSource_GetCurFile(IFileSourceFilter *iface, LPOLESTR *ppszFileName, AM_MEDIA_TYPE *mt) - { -- struct asf_reader *filter = impl_from_IFileSourceFilter(iface); -+ struct asf_reader *This = impl_from_IFileSourceFilter(iface); - -- TRACE("filter %p, filename %p, type %p.\n", filter, filename, type); -+ TRACE("filter %p, filename %p, mt %p.\n", This, ppszFileName, mt); - -- if (!filename) -+ if (!ppszFileName) - return E_POINTER; -- *filename = NULL; - -- if (type) -+ /* copy file name & media type if available, otherwise clear the outputs */ -+ if (This->pszFileName) - { -- type->majortype = filter->type.majortype; -- type->subtype = filter->type.subtype; -- type->lSampleSize = filter->type.lSampleSize; -- type->pUnk = filter->type.pUnk; -- type->cbFormat = filter->type.cbFormat; -+ *ppszFileName = CoTaskMemAlloc((wcslen(This->pszFileName) + 1) * sizeof(WCHAR)); -+ wcscpy(*ppszFileName, This->pszFileName); -+ if (mt) -+ CopyMediaType(mt, &This->mt); - } -- -- if (filter->filename) -+ else - { -- *filename = CoTaskMemAlloc((wcslen(filter->filename) + 1) * sizeof(WCHAR)); -- wcscpy(*filename, filter->filename); -+ *ppszFileName = NULL; -+ if (mt) -+ memset(mt, 0, sizeof(AM_MEDIA_TYPE)); - } - - return S_OK; - } - --static const IFileSourceFilterVtbl filesourcefilter_vtbl = -+static const IFileSourceFilterVtbl FileSource_Vtbl = - { -- filesourcefilter_QueryInterface, -- filesourcefilter_AddRef, -- filesourcefilter_Release, -- filesourcefilter_Load, -- filesourcefilter_GetCurFile, -+ FileSource_QueryInterface, -+ FileSource_AddRef, -+ FileSource_Release, -+ FileSource_Load, -+ FileSource_GetCurFile - }; - --HRESULT asf_reader_create(IUnknown *outer, IUnknown **out) -+static inline struct asf_reader *impl_from_strmbase_pin(struct strmbase_pin *iface) - { -- struct asf_reader *object; -+ return CONTAINING_RECORD(iface, struct asf_reader, source.pin); -+} - -- if (!(object = calloc(1, sizeof(*object)))) -+static inline struct asf_reader *impl_from_IAsyncReader(IAsyncReader *iface) -+{ -+ return CONTAINING_RECORD(iface, struct asf_reader, IAsyncReader_iface); -+} -+ -+static HRESULT source_query_accept(struct strmbase_pin *iface, const AM_MEDIA_TYPE *mt) -+{ -+ struct asf_reader *filter = impl_from_strmbase_pin(iface); -+ -+ if (IsEqualGUID(&mt->majortype, &filter->mt.majortype) -+ && (!IsEqualGUID(&mt->subtype, &GUID_NULL) -+ || IsEqualGUID(&filter->mt.subtype, &GUID_NULL))) -+ return S_OK; -+ -+ return S_FALSE; -+} -+ -+static HRESULT source_get_media_type(struct strmbase_pin *iface, unsigned int index, AM_MEDIA_TYPE *mt) -+{ -+ struct asf_reader *filter = impl_from_strmbase_pin(iface); -+ -+ if (index > 1) -+ return VFW_S_NO_MORE_ITEMS; -+ -+ if (index == 0) -+ CopyMediaType(mt, &filter->mt); -+ else if (index == 1) -+ CopyMediaType(mt, &default_mt); -+ return S_OK; -+} -+ -+static HRESULT source_query_interface(struct strmbase_pin *iface, REFIID iid, void **out) -+{ -+ struct asf_reader *filter = impl_from_strmbase_pin(iface); -+ -+ if (IsEqualGUID(iid, &IID_IAsyncReader)) -+ *out = &filter->IAsyncReader_iface; -+ else -+ return E_NOINTERFACE; -+ -+ IUnknown_AddRef((IUnknown *)*out); -+ return S_OK; -+} -+ -+/* Function called as a helper to IPin_Connect */ -+/* specific AM_MEDIA_TYPE - it cannot be NULL */ -+/* this differs from standard OutputPin_AttemptConnection only in that it -+ * doesn't need the IMemInputPin interface on the receiving pin */ -+static HRESULT WINAPI FileAsyncReaderPin_AttemptConnection(struct strmbase_source *This, -+ IPin *pReceivePin, const AM_MEDIA_TYPE *pmt) -+{ -+ HRESULT hr; -+ -+ TRACE("%p->(%p, %p)\n", This, pReceivePin, pmt); -+ -+ if (This->pin.ops->pin_query_accept(&This->pin, pmt) != S_OK) -+ return VFW_E_TYPE_NOT_ACCEPTED; -+ -+ This->pin.peer = pReceivePin; -+ IPin_AddRef(pReceivePin); -+ CopyMediaType(&This->pin.mt, pmt); -+ -+ hr = IPin_ReceiveConnection(pReceivePin, &This->pin.IPin_iface, pmt); -+ -+ if (FAILED(hr)) -+ { -+ IPin_Release(This->pin.peer); -+ This->pin.peer = NULL; -+ FreeMediaType(&This->pin.mt); -+ } -+ -+ TRACE(" -- %x\n", hr); -+ return hr; -+} -+ -+static const struct strmbase_source_ops source_ops = -+{ -+ .base.pin_query_accept = source_query_accept, -+ .base.pin_get_media_type = source_get_media_type, -+ .base.pin_query_interface = source_query_interface, -+ .pfnAttemptConnection = FileAsyncReaderPin_AttemptConnection, -+}; -+ -+static HRESULT WINAPI FileAsyncReader_QueryInterface(IAsyncReader *iface, REFIID iid, void **out) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ return IPin_QueryInterface(&filter->source.pin.IPin_iface, iid, out); -+} -+ -+static ULONG WINAPI FileAsyncReader_AddRef(IAsyncReader * iface) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ return IPin_AddRef(&filter->source.pin.IPin_iface); -+} -+ -+static ULONG WINAPI FileAsyncReader_Release(IAsyncReader * iface) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ return IPin_Release(&filter->source.pin.IPin_iface); -+} -+ -+static HRESULT WINAPI FileAsyncReader_RequestAllocator(IAsyncReader *iface, -+ IMemAllocator *preferred, ALLOCATOR_PROPERTIES *props, IMemAllocator **ret_allocator) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ IMemAllocator *allocator; -+ unsigned int i; -+ HRESULT hr; -+ -+ TRACE("filter %p, preferred %p, props %p, ret_allocator %p.\n", filter, preferred, props, ret_allocator); -+ -+ if (!props->cbAlign) -+ props->cbAlign = 1; -+ -+ *ret_allocator = NULL; -+ -+ if (preferred) -+ IMemAllocator_AddRef(allocator = preferred); -+ else if (FAILED(hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL, -+ CLSCTX_INPROC, &IID_IMemAllocator, (void **)&allocator))) -+ return hr; -+ -+ if (FAILED(hr = IMemAllocator_SetProperties(allocator, props, props))) -+ { -+ IMemAllocator_Release(allocator); -+ return hr; -+ } -+ -+ if (filter->requests) -+ { -+ for (i = 0; i < filter->max_requests; ++i) -+ CloseHandle(filter->requests[i].ovl.hEvent); -+ free(filter->requests); -+ } -+ -+ filter->max_requests = props->cBuffers; -+ TRACE("Maximum request count: %u.\n", filter->max_requests); -+ if (!(filter->requests = calloc(filter->max_requests, sizeof(filter->requests[0])))) -+ { -+ IMemAllocator_Release(allocator); - return E_OUTOFMEMORY; -+ } - -- strmbase_filter_init(&object->filter, outer, &CLSID_WMAsfReader, &filter_ops); -- object->IFileSourceFilter_iface.lpVtbl = &filesourcefilter_vtbl; -+ for (i = 0; i < filter->max_requests; ++i) -+ filter->requests[i].ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - -- TRACE("Created WM ASF reader %p.\n", object); -- *out = &object->filter.IUnknown_inner; -+ *ret_allocator = allocator; -+ return S_OK; -+} -+ -+static HRESULT WINAPI FileAsyncReader_Request(IAsyncReader *iface, IMediaSample *sample, DWORD_PTR cookie) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ REFERENCE_TIME start, end; -+ struct request *req; -+ unsigned int i; -+ HRESULT hr; -+ BYTE *data; -+ -+ TRACE("filter %p, sample %p, cookie %#lx.\n", filter, sample, cookie); -+ -+ if (!sample) -+ return E_POINTER; -+ -+ if (FAILED(hr = IMediaSample_GetTime(sample, &start, &end))) -+ return hr; -+ -+ if (BYTES_FROM_MEDIATIME(start) >= filter->file_size.QuadPart) -+ return HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); -+ -+ if (FAILED(hr = IMediaSample_GetPointer(sample, &data))) -+ return hr; -+ -+ EnterCriticalSection(&filter->sample_cs); -+ if (filter->flushing) -+ { -+ LeaveCriticalSection(&filter->sample_cs); -+ return VFW_E_WRONG_STATE; -+ } -+ -+ for (i = 0; i < filter->max_requests; ++i) -+ { -+ if (!filter->requests[i].sample) -+ break; -+ } -+ assert(i < filter->max_requests); -+ req = &filter->requests[i]; -+ -+ req->ovl.u.s.Offset = BYTES_FROM_MEDIATIME(start); -+ req->ovl.u.s.OffsetHigh = BYTES_FROM_MEDIATIME(start) >> 32; -+ /* No reference is taken. */ -+ -+ if (ReadFile(filter->file, data, BYTES_FROM_MEDIATIME(end - start), NULL, &req->ovl) -+ || GetLastError() == ERROR_IO_PENDING) -+ { -+ hr = S_OK; -+ req->sample = sample; -+ req->cookie = cookie; -+ } -+ else -+ hr = HRESULT_FROM_WIN32(GetLastError()); -+ -+ LeaveCriticalSection(&filter->sample_cs); -+ return hr; -+} -+ -+static HRESULT WINAPI FileAsyncReader_WaitForNext(IAsyncReader *iface, -+ DWORD timeout, IMediaSample **sample, DWORD_PTR *cookie) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ unsigned int i; -+ -+ TRACE("filter %p, timeout %u, sample %p, cookie %p.\n", filter, timeout, sample, cookie); -+ -+ *sample = NULL; -+ *cookie = 0; -+ -+ EnterCriticalSection(&filter->sample_cs); -+ -+ do -+ { -+ if (filter->flushing) -+ { -+ LeaveCriticalSection(&filter->sample_cs); -+ return VFW_E_WRONG_STATE; -+ } -+ -+ for (i = 0; i < filter->max_requests; ++i) -+ { -+ struct request *req = &filter->requests[i]; -+ DWORD size; -+ -+ if (req->sample && GetOverlappedResult(filter->file, &req->ovl, &size, FALSE)) -+ { -+ REFERENCE_TIME start, end; -+ -+ IMediaSample_SetActualDataLength(req->sample, size); -+ start = MEDIATIME_FROM_BYTES(((ULONGLONG)req->ovl.u.s.OffsetHigh << 32) + req->ovl.u.s.Offset); -+ end = start + MEDIATIME_FROM_BYTES(size); -+ IMediaSample_SetTime(req->sample, &start, &end); -+ -+ *sample = req->sample; -+ *cookie = req->cookie; -+ req->sample = NULL; -+ -+ LeaveCriticalSection(&filter->sample_cs); -+ TRACE("Returning sample %u.\n", i); -+ return S_OK; -+ } -+ } -+ } while (SleepConditionVariableCS(&filter->sample_cv, &filter->sample_cs, timeout)); -+ -+ LeaveCriticalSection(&filter->sample_cs); -+ return VFW_E_TIMEOUT; -+} -+ -+static BOOL sync_read(HANDLE file, LONGLONG offset, LONG length, BYTE *buffer, DWORD *read_len) -+{ -+ OVERLAPPED ovl = {0}; -+ BOOL ret; -+ -+ ovl.hEvent = (HANDLE)((ULONG_PTR)CreateEventW(NULL, TRUE, FALSE, NULL) | 1); -+ ovl.u.s.Offset = (DWORD)offset; -+ ovl.u.s.OffsetHigh = offset >> 32; -+ -+ *read_len = 0; -+ -+ ret = ReadFile(file, buffer, length, NULL, &ovl); -+ if (ret || GetLastError() == ERROR_IO_PENDING) -+ ret = GetOverlappedResult(file, &ovl, read_len, TRUE); -+ -+ TRACE("Returning %u bytes.\n", *read_len); -+ -+ CloseHandle(ovl.hEvent); -+ return ret; -+} -+ -+static HRESULT WINAPI FileAsyncReader_SyncReadAligned(IAsyncReader *iface, IMediaSample *sample) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ REFERENCE_TIME start_time, end_time; -+ DWORD read_len; -+ BYTE *buffer; -+ LONG length; -+ HRESULT hr; -+ BOOL ret; -+ -+ TRACE("filter %p, sample %p.\n", filter, sample); -+ -+ hr = IMediaSample_GetTime(sample, &start_time, &end_time); -+ -+ if (SUCCEEDED(hr)) -+ hr = IMediaSample_GetPointer(sample, &buffer); -+ -+ if (SUCCEEDED(hr)) -+ { -+ length = BYTES_FROM_MEDIATIME(end_time - start_time); -+ ret = sync_read(filter->file, BYTES_FROM_MEDIATIME(start_time), length, buffer, &read_len); -+ if (ret) -+ hr = (read_len == length) ? S_OK : S_FALSE; -+ else if (GetLastError() == ERROR_HANDLE_EOF) -+ hr = S_OK; -+ else -+ hr = HRESULT_FROM_WIN32(GetLastError()); -+ } -+ -+ if (SUCCEEDED(hr)) -+ IMediaSample_SetActualDataLength(sample, read_len); -+ -+ return hr; -+} -+ -+static HRESULT WINAPI FileAsyncReader_SyncRead(IAsyncReader *iface, -+ LONGLONG offset, LONG length, BYTE *buffer) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ DWORD read_len; -+ HRESULT hr; -+ BOOL ret; -+ -+ TRACE("filter %p, offset %s, length %d, buffer %p.\n", -+ filter, wine_dbgstr_longlong(offset), length, buffer); -+ -+ ret = sync_read(filter->file, offset, length, buffer, &read_len); -+ if (ret) -+ hr = (read_len == length) ? S_OK : S_FALSE; -+ else if (GetLastError() == ERROR_HANDLE_EOF) -+ hr = S_FALSE; -+ else -+ hr = HRESULT_FROM_WIN32(GetLastError()); -+ -+ return hr; -+} -+ -+static HRESULT WINAPI FileAsyncReader_Length(IAsyncReader *iface, LONGLONG *total, LONGLONG *available) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ -+ TRACE("iface %p, total %p, available %p.\n", iface, total, available); -+ -+ *available = *total = filter->file_size.QuadPart; - - return S_OK; - } -+ -+static HRESULT WINAPI FileAsyncReader_BeginFlush(IAsyncReader * iface) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ unsigned int i; -+ -+ TRACE("iface %p.\n", iface); -+ -+ EnterCriticalSection(&filter->sample_cs); -+ -+ filter->flushing = TRUE; -+ for (i = 0; i < filter->max_requests; ++i) -+ filter->requests[i].sample = NULL; -+ CancelIoEx(filter->file, NULL); -+ WakeAllConditionVariable(&filter->sample_cv); -+ -+ LeaveCriticalSection(&filter->sample_cs); -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI FileAsyncReader_EndFlush(IAsyncReader * iface) -+{ -+ struct asf_reader *filter = impl_from_IAsyncReader(iface); -+ -+ TRACE("iface %p.\n", iface); -+ -+ EnterCriticalSection(&filter->sample_cs); -+ -+ filter->flushing = FALSE; -+ -+ LeaveCriticalSection(&filter->sample_cs); -+ -+ return S_OK; -+} -+ -+static const IAsyncReaderVtbl FileAsyncReader_Vtbl = -+{ -+ FileAsyncReader_QueryInterface, -+ FileAsyncReader_AddRef, -+ FileAsyncReader_Release, -+ FileAsyncReader_RequestAllocator, -+ FileAsyncReader_Request, -+ FileAsyncReader_WaitForNext, -+ FileAsyncReader_SyncReadAligned, -+ FileAsyncReader_SyncRead, -+ FileAsyncReader_Length, -+ FileAsyncReader_BeginFlush, -+ FileAsyncReader_EndFlush, -+}; -From 7e0b159a0bf0a10a70d7175497eb049a29f70a57 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 9 Mar 2021 16:53:09 -0500 -Subject: [PATCH] winegstreamer: Activate source pad in push mode if it isn't - activated in pull mode. - -Since our source pad is not part of any element, gstreamer won't end up activating it -directly through the state transition. Instead, if the downstream element doesn't -activate the source pad into pull mode during the transition to the READY state, -we activate our pad in push mode. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/wg_parser.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index b93b2c182ae..d7412409a27 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -75,7 +75,7 @@ struct wg_parser - pthread_mutex_t mutex; - - pthread_cond_t init_cond; -- bool no_more_pads, has_duration, error; -+ bool no_more_pads, has_duration, error, pull_mode; - - pthread_cond_t read_cond, read_done_cond; - struct -@@ -1528,9 +1528,12 @@ static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode - GST_DEBUG("%s source pad for parser %p in %s mode.", - activate ? "Activating" : "Deactivating", parser, gst_pad_mode_get_name(mode)); - -+ parser->pull_mode = false; -+ - switch (mode) - { - case GST_PAD_MODE_PULL: -+ parser->pull_mode = activate; - return TRUE; - case GST_PAD_MODE_PUSH: - return activate_push(pad, activate); -@@ -1695,6 +1698,8 @@ static NTSTATUS wg_parser_connect(void *args) - goto out; - - gst_element_set_state(parser->container, GST_STATE_PAUSED); -+ if (!parser->pull_mode) -+ gst_pad_set_active(parser->my_src, 1); - ret = gst_element_get_state(parser->container, NULL, NULL, -1); - if (ret == GST_STATE_CHANGE_FAILURE) - { -@@ -1833,6 +1838,8 @@ static NTSTATUS wg_parser_disconnect(void *args) - pthread_mutex_unlock(&parser->mutex); - - gst_element_set_state(parser->container, GST_STATE_NULL); -+ if (!parser->pull_mode) -+ gst_pad_set_active(parser->my_src, 0); - gst_pad_unlink(parser->my_src, parser->their_sink); - gst_object_unref(parser->my_src); - gst_object_unref(parser->their_sink); -From a9d8d8ef6005016504bacb6de9bbc5034db3a15e Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 10 Mar 2021 10:43:03 -0500 -Subject: [PATCH] winegstreamer: Push stream-start and segment events in push - mode. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/wg_parser.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index d7412409a27..c6e8bbcb26b 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1449,6 +1449,7 @@ static void *push_data(void *arg) - { - struct wg_parser *parser = arg; - GstBuffer *buffer; -+ GstSegment *segment; - guint max_size; - - GST_DEBUG("Starting push thread."); -@@ -1461,6 +1462,12 @@ static void *push_data(void *arg) - - max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; - -+ gst_pad_push_event(parser->my_src, gst_event_new_stream_start("wg_stream")); -+ -+ segment = gst_segment_new(); -+ gst_segment_init(segment, GST_FORMAT_BYTES); -+ gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); -+ - for (;;) - { - ULONG size; -@@ -1595,6 +1602,7 @@ static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) - GstEvent *flush_event; - GstSeekFlags flags; - gint64 cur, stop; -+ GstSegment *seg; - guint32 seqnum; - gdouble rate; - -@@ -1628,7 +1636,12 @@ static gboolean src_perform_seek(struct wg_parser *parser, GstEvent *event) - gst_event_set_seqnum(flush_event, seqnum); - gst_pad_push_event(parser->my_src, flush_event); - if (thread) -+ { - gst_pad_set_active(parser->my_src, 1); -+ seg = gst_segment_new(); -+ gst_segment_init(seg, GST_FORMAT_BYTES); -+ gst_pad_push_event(parser->my_src, gst_event_new_segment(seg)); -+ } - } - - return TRUE; -From 052e04347d4cd98dfb699172c086e41d0459c538 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 10 Mar 2021 13:09:51 -0500 -Subject: [PATCH] winegstreamer: Introduce H.264 decoder transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/decode_transform.c | 301 +++++++++++++++++++ - dlls/winegstreamer/gst_private.h | 2 + - dlls/winegstreamer/main.c | 3 + - dlls/winegstreamer/mfplat.c | 1 + - dlls/winegstreamer/winegstreamer_classes.idl | 6 + - 6 files changed, 314 insertions(+) - create mode 100644 dlls/winegstreamer/decode_transform.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 76e6aeed54d..c612ef340b7 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -8,6 +8,7 @@ EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) - - C_SRCS = \ - audioconvert.c \ -+ decode_transform.c \ - main.c \ - media_source.c \ - mfplat.c \ -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -new file mode 100644 -index 00000000000..f5d4763bde4 ---- /dev/null -+++ b/dlls/winegstreamer/decode_transform.c -@@ -0,0 +1,301 @@ -+/* GStreamer Decoder Transform -+ * -+ * Copyright 2021 Derek Lesho -+ * -+ * 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 "gst_private.h" -+ -+#include "mfapi.h" -+#include "mferror.h" -+#include "mfobjects.h" -+#include "mftransform.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -+ -+struct mf_decoder -+{ -+ IMFTransform IMFTransform_iface; -+ LONG refcount; -+}; -+ -+static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) -+{ -+ return CONTAINING_RECORD(iface, struct mf_decoder, IMFTransform_iface); -+} -+ -+static HRESULT WINAPI mf_decoder_QueryInterface (IMFTransform *iface, REFIID riid, void **out) -+{ -+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); -+ -+ if (IsEqualIID(riid, &IID_IMFTransform) || -+ IsEqualIID(riid, &IID_IUnknown)) -+ { -+ *out = iface; -+ IMFTransform_AddRef(iface); -+ return S_OK; -+ } -+ -+ WARN("Unsupported %s.\n", debugstr_guid(riid)); -+ *out = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI mf_decoder_AddRef(IMFTransform *iface) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ ULONG refcount = InterlockedIncrement(&decoder->refcount); -+ -+ TRACE("%p, refcount %u.\n", iface, refcount); -+ -+ return refcount; -+} -+ -+static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) -+{ -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ ULONG refcount = InterlockedDecrement(&decoder->refcount); -+ -+ TRACE("%p, refcount %u.\n", iface, refcount); -+ -+ if (!refcount) -+ { -+ heap_free(decoder); -+ } -+ -+ return refcount; -+} -+ -+static HRESULT WINAPI mf_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, -+ DWORD *output_minimum, DWORD *output_maximum) -+{ -+ TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum); -+ -+ *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI mf_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -+{ -+ TRACE("%p %p %p.\n", iface, inputs, outputs); -+ -+ *inputs = *outputs = 1; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI mf_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, -+ DWORD output_size, DWORD *outputs) -+{ -+ TRACE("%p %u %p %u %p.\n", iface, input_size, inputs, output_size, outputs); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -+{ -+ FIXME("%p %u %p.\n", iface, id, info); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -+{ -+ FIXME("%p %u %p.\n", iface, id, info); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -+{ -+ FIXME("%p, %p.\n", iface, attributes); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, attributes); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, attributes); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) -+{ -+ TRACE("%p, %u.\n", iface, id); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -+{ -+ TRACE("%p, %u, %p.\n", iface, streams, ids); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -+{ -+ FIXME("%p, %u, %p\n", iface, id, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) -+{ -+ FIXME("%p, %p.\n", iface, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -+{ -+ FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, event); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -+{ -+ FIXME("%p, %u %lu.\n", iface, message, param); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -+{ -+ FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -+{ -+ FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ -+ return E_NOTIMPL; -+} -+ -+static const IMFTransformVtbl mf_decoder_vtbl = -+{ -+ mf_decoder_QueryInterface, -+ mf_decoder_AddRef, -+ mf_decoder_Release, -+ mf_decoder_GetStreamLimits, -+ mf_decoder_GetStreamCount, -+ mf_decoder_GetStreamIDs, -+ mf_decoder_GetInputStreamInfo, -+ mf_decoder_GetOutputStreamInfo, -+ mf_decoder_GetAttributes, -+ mf_decoder_GetInputStreamAttributes, -+ mf_decoder_GetOutputStreamAttributes, -+ mf_decoder_DeleteInputStream, -+ mf_decoder_AddInputStreams, -+ mf_decoder_GetInputAvailableType, -+ mf_decoder_GetOutputAvailableType, -+ mf_decoder_SetInputType, -+ mf_decoder_SetOutputType, -+ mf_decoder_GetInputCurrentType, -+ mf_decoder_GetOutputCurrentType, -+ mf_decoder_GetInputStatus, -+ mf_decoder_GetOutputStatus, -+ mf_decoder_SetOutputBounds, -+ mf_decoder_ProcessEvent, -+ mf_decoder_ProcessMessage, -+ mf_decoder_ProcessInput, -+ mf_decoder_ProcessOutput, -+}; -+ -+HRESULT decode_transform_create(REFIID riid, void **obj) -+{ -+ struct mf_decoder *object; -+ -+ TRACE("%s, %p.\n", debugstr_guid(riid), obj); -+ -+ if (!(object = heap_alloc_zero(sizeof(*object)))) -+ return E_OUTOFMEMORY; -+ -+ object->IMFTransform_iface.lpVtbl = &mf_decoder_vtbl; -+ object->refcount = 1; -+ -+ *obj = &object->IMFTransform_iface; -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 9e1d67417d4..ad4acdccc24 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -118,6 +118,8 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HI - - HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - -+HRESULT decode_transform_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; -+ - struct wm_stream - { - struct wm_reader *reader; -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 600ba090312..d63d4100947 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -529,6 +529,9 @@ HRESULT WINAPI DllRegisterServer(void) - - init_gstreamer(); - -+ if (FAILED(hr = mfplat_DllRegisterServer())) -+ return hr; -+ - if (FAILED(hr = __wine_register_resources())) - return hr; - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 5404728ba83..f6afdf7f73e 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -407,6 +407,7 @@ class_objects[] = - { &CLSID_VideoProcessorMFT, &video_processor_create }, - { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, - { &CLSID_WINEAudioConverter, &audio_converter_create }, -+ { &CLSID_MSH264DecoderMFT, &decode_transform_create }, - }; - - HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) -diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 072ec90eea4..064a6872c79 100644 ---- a/dlls/winegstreamer/winegstreamer_classes.idl -+++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -73,3 +73,9 @@ coclass WINEAudioConverter { } - uuid(2eeb4adf-4578-4d10-bca7-bb955f56320a) - ] - coclass CWMADecMediaObject {}; -+ -+[ -+ threading(both), -+ uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d) -+] -+coclass CMSH264DecoderMFT { } -From ad44caf3da769c573c430e95af4c53a5a751c9ea Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 14 Dec 2021 13:36:27 +0100 -Subject: [PATCH] winegstreamer: Implement ::GetInputAvailableType for decode - transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/decode_transform.c | 60 +++++++++++++++++++++++++-- - dlls/winegstreamer/gst_private.h | 6 ++- - dlls/winegstreamer/mfplat.c | 7 +++- - 3 files changed, 67 insertions(+), 6 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index f5d4763bde4..55a0c1c6c9b 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -29,10 +29,33 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -+const GUID *h264_input_types[] = {&MFVideoFormat_H264}; -+/* NV12 comes first https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order . thanks to @vitorhnn */ -+const GUID *h264_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_YUY2, &MFVideoFormat_YV12}; -+ -+static struct decoder_desc -+{ -+ const GUID *major_type; -+ const GUID **input_types; -+ unsigned int input_types_count; -+ const GUID **output_types; -+ unsigned int output_types_count; -+} decoder_descs[] = -+{ -+ { /* DECODER_TYPE_H264 */ -+ &MFMediaType_Video, -+ h264_input_types, -+ ARRAY_SIZE(h264_input_types), -+ h264_output_types, -+ ARRAY_SIZE(h264_output_types), -+ }, -+}; -+ - struct mf_decoder - { - IMFTransform IMFTransform_iface; - LONG refcount; -+ enum decoder_type type; - }; - - static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) -@@ -163,9 +186,36 @@ static HRESULT WINAPI mf_decoder_AddInputStreams(IMFTransform *iface, DWORD stre - static HRESULT WINAPI mf_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ IMFMediaType *input_type; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %u, %p\n", decoder, id, index, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (index >= decoder_descs[decoder->type].input_types_count) -+ return MF_E_NO_MORE_TYPES; -+ -+ if (FAILED(hr = MFCreateMediaType(&input_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(input_type, &MF_MT_MAJOR_TYPE, decoder_descs[decoder->type].major_type))) -+ { -+ IMFMediaType_Release(input_type); -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(input_type, &MF_MT_SUBTYPE, decoder_descs[decoder->type].input_types[index]))) -+ { -+ IMFMediaType_Release(input_type); -+ return hr; -+ } -+ -+ *type = input_type; -+ -+ return S_OK; - } - - static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -@@ -284,11 +334,11 @@ static const IMFTransformVtbl mf_decoder_vtbl = - mf_decoder_ProcessOutput, - }; - --HRESULT decode_transform_create(REFIID riid, void **obj) -+HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) - { - struct mf_decoder *object; - -- TRACE("%s, %p.\n", debugstr_guid(riid), obj); -+ TRACE("%s, %p %u.\n", debugstr_guid(riid), obj, type); - - if (!(object = heap_alloc_zero(sizeof(*object)))) - return E_OUTOFMEMORY; -@@ -296,6 +346,8 @@ HRESULT decode_transform_create(REFIID riid, void **obj) - object->IMFTransform_iface.lpVtbl = &mf_decoder_vtbl; - object->refcount = 1; - -+ object->type = type; -+ - *obj = &object->IMFTransform_iface; - return S_OK; - } -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index ad4acdccc24..35f78ed3ccd 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -118,7 +118,11 @@ HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj) DECLSPEC_HI - - HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - --HRESULT decode_transform_create(REFIID riid, void **obj) DECLSPEC_HIDDEN; -+enum decoder_type -+{ -+ DECODER_TYPE_H264, -+}; -+HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; - - struct wm_stream - { -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index f6afdf7f73e..9bef3c11f48 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -397,6 +397,11 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a - - static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}}; - -+static HRESULT h264_decoder_create(REFIID riid, void **ret) -+{ -+ return decode_transform_create(riid, ret, DECODER_TYPE_H264); -+} -+ - static const struct class_object - { - const GUID *clsid; -@@ -407,7 +412,7 @@ class_objects[] = - { &CLSID_VideoProcessorMFT, &video_processor_create }, - { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, - { &CLSID_WINEAudioConverter, &audio_converter_create }, -- { &CLSID_MSH264DecoderMFT, &decode_transform_create }, -+ { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, - }; - - HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) -From af0b0115bd28d4e0ce44f7e9de6ad6eeb3662ed0 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 10 Mar 2021 14:23:09 -0500 -Subject: [PATCH] winegstreamer: Implement ::GetOutputAvailableType for decode - transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/decode_transform.c | 31 +++++++++++++++++++++++++-- - 1 file changed, 29 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index 55a0c1c6c9b..3c71fddd67c 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -221,9 +221,36 @@ static HRESULT WINAPI mf_decoder_GetInputAvailableType(IMFTransform *iface, DWOR - static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ IMFMediaType *output_type; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %u, %p\n", decoder, id, index, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (index >= decoder_descs[decoder->type].output_types_count) -+ return MF_E_NO_MORE_TYPES; -+ -+ if (FAILED(hr = MFCreateMediaType(&output_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_MAJOR_TYPE, decoder_descs[decoder->type].major_type))) -+ { -+ IMFMediaType_Release(output_type); -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(output_type, &MF_MT_SUBTYPE, decoder_descs[decoder->type].output_types[index]))) -+ { -+ IMFMediaType_Release(output_type); -+ return hr; -+ } -+ -+ *type = output_type; -+ -+ return S_OK; - } - - static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -From 9d8939defa9d5ba38310e10a5b348af9443ffc0c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 11 Mar 2021 12:33:02 -0500 -Subject: [PATCH] winegstreamer: Implement ::SetInputType for decode transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/decode_transform.c | 80 ++++++++++++++++++++++++++- - dlls/winegstreamer/mfplat.c | 17 +++++- - dlls/winegstreamer/quartz_parser.c | 1 + - dlls/winegstreamer/unixlib.h | 10 ++++ - dlls/winegstreamer/wg_parser.c | 76 +++++++++++++++++++++++++ - 5 files changed, 180 insertions(+), 4 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index 3c71fddd67c..f709ef32fc1 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -56,6 +56,8 @@ struct mf_decoder - IMFTransform IMFTransform_iface; - LONG refcount; - enum decoder_type type; -+ IMFMediaType *input_type; -+ CRITICAL_SECTION cs; - }; - - static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) -@@ -99,6 +101,14 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) - - if (!refcount) - { -+ if (decoder->input_type) -+ { -+ IMFMediaType_Release(decoder->input_type); -+ decoder->input_type = NULL; -+ } -+ -+ DeleteCriticalSection(&decoder->cs); -+ - heap_free(decoder); - } - -@@ -255,9 +265,73 @@ static HRESULT WINAPI mf_decoder_GetOutputAvailableType(IMFTransform *iface, DWO - - static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ struct wg_format input_format; -+ GUID major_type, subtype; -+ unsigned int i; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %p, %#x.\n", decoder, id, type, flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (!type) -+ { -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&decoder->cs); -+ -+ if (decoder->input_type) -+ { -+ IMFMediaType_Release(decoder->input_type); -+ decoder->input_type = NULL; -+ } -+ -+ LeaveCriticalSection(&decoder->cs); -+ -+ return S_OK; -+ } -+ -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) -+ return MF_E_INVALIDTYPE; -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return MF_E_INVALIDTYPE; -+ -+ if (!(IsEqualGUID(&major_type, decoder_descs[decoder->type].major_type))) -+ return MF_E_INVALIDTYPE; -+ -+ for (i = 0; i < decoder_descs[decoder->type].input_types_count; i++) -+ { -+ if (IsEqualGUID(&subtype, decoder_descs[decoder->type].input_types[i])) -+ break; -+ if (i == decoder_descs[decoder->type].input_types_count) -+ return MF_E_INVALIDTYPE; -+ } -+ -+ mf_media_type_to_wg_format(type, &input_format); -+ if (!input_format.major_type) -+ return MF_E_INVALIDTYPE; -+ -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&decoder->cs); -+ -+ hr = S_OK; -+ -+ if (!decoder->input_type) -+ hr = MFCreateMediaType(&decoder->input_type); -+ -+ if (SUCCEEDED(hr) && FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes*) decoder->input_type))) -+ { -+ IMFMediaType_Release(decoder->input_type); -+ decoder->input_type = NULL; -+ } -+ -+ LeaveCriticalSection(&decoder->cs); -+ return hr; - } - - static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -@@ -375,6 +449,8 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) - - object->type = type; - -+ InitializeCriticalSection(&object->cs); -+ - *obj = &object->IMFTransform_iface; - return S_OK; - } -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 9bef3c11f48..de6bb4bae08 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -528,6 +528,7 @@ video_formats[] = - {&MFVideoFormat_YUY2, WG_VIDEO_FORMAT_YUY2}, - {&MFVideoFormat_YV12, WG_VIDEO_FORMAT_YV12}, - {&MFVideoFormat_YVYU, WG_VIDEO_FORMAT_YVYU}, -+ {&MFVideoFormat_H264, WG_VIDEO_FORMAT_H264}, - }; - - static const struct -@@ -715,10 +716,22 @@ static void mf_media_type_to_wg_format_video(IMFMediaType *type, struct wg_forma - if (IsEqualGUID(&subtype, video_formats[i].subtype)) - { - format->u.video.format = video_formats[i].format; -- return; -+ break; - } - } -- FIXME("Unrecognized video subtype %s.\n", debugstr_guid(&subtype)); -+ if (i == ARRAY_SIZE(video_formats)) -+ FIXME("Unrecognized video subtype %s.\n", debugstr_guid(&subtype)); -+ -+ if (format->u.video.format == WG_VIDEO_FORMAT_H264) -+ { -+ UINT32 profile, level; -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) -+ format->u.video.compressed.h264.profile = profile; -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) -+ format->u.video.compressed.h264.level = level; -+ } - } - - void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) -diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c -index 8532fc1af8b..86f64bd1753 100644 ---- a/dlls/winegstreamer/quartz_parser.c -+++ b/dlls/winegstreamer/quartz_parser.c -@@ -271,6 +271,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) - * but as long as every sample fits into our allocator, we're fine. */ - return width * height * 3; - -+ case WG_VIDEO_FORMAT_H264: - case WG_VIDEO_FORMAT_UNKNOWN: - FIXME("Cannot guess maximum sample size for unknown video format.\n"); - return 0; -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 82bb534b938..f3db631d16d 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -62,9 +62,19 @@ struct wg_format - WG_VIDEO_FORMAT_YVYU, - - WG_VIDEO_FORMAT_CINEPAK, -+ -+ WG_VIDEO_FORMAT_H264, - } format; - int32_t width, height; - uint32_t fps_n, fps_d; -+ union -+ { -+ struct -+ { -+ uint32_t profile; -+ uint32_t level; -+ } h264; -+ } compressed; - } video; - struct - { -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 552184591e7..7a47ac9411f 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -387,6 +387,22 @@ static void wg_channel_mask_to_gst(GstAudioChannelPosition *positions, uint32_t - } - } - -+static void wg_set_caps_from_wg_format(GstCaps *caps, const struct wg_format *format) -+{ -+ switch (format->major_type) -+ { -+ case WG_MAJOR_TYPE_VIDEO: -+ { -+ gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.video.width, NULL); -+ gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL); -+ gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL); -+ break; -+ } -+ default: -+ break; -+ } -+} -+ - static GstCaps *wg_format_to_caps_audio(const struct wg_format *format) - { - GstAudioChannelPosition positions[32]; -@@ -428,6 +444,65 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) - unsigned int i; - GstCaps *caps; - -+ /* compressed types */ -+ -+ if (format->u.video.format == WG_VIDEO_FORMAT_H264) -+ { -+ const char *profile; -+ const char *level; -+ -+ caps = gst_caps_new_empty_simple("video/x-h264"); -+ wg_set_caps_from_wg_format(caps, format); -+ -+ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); -+ gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL); -+ -+ switch (format->u.video.compressed.h264.profile) -+ { -+ case /* eAVEncH264VProfile_Main */ 77: profile = "main"; break; -+ case /* eAVEncH264VProfile_High */ 100: profile = "high"; break; -+ case /* eAVEncH264VProfile_444 */ 244: profile = "high-4:4:4"; break; -+ default: -+ GST_ERROR("Unrecognized H.264 profile attribute %u\n", format->u.video.compressed.h264.profile); -+ /* fallthrough */ -+ case 0: profile = NULL; -+ } -+ -+ switch (format->u.video.compressed.h264.level) -+ { -+ case /* eAVEncH264VLevel1 */ 10: level = "1"; break; -+ case /* eAVEncH264VLevel1_1 */ 11: level = "1.1"; break; -+ case /* eAVEncH264VLevel1_2 */ 12: level = "1.2"; break; -+ case /* eAVEncH264VLevel1_3 */ 13: level = "1.3"; break; -+ case /* eAVEncH264VLevel2 */ 20: level = "2"; break; -+ case /* eAVEncH264VLevel2_1 */ 21: level = "2.1"; break; -+ case /* eAVEncH264VLevel2_2 */ 22: level = "2.2"; break; -+ case /* eAVEncH264VLevel3 */ 30: level = "3"; break; -+ case /* eAVEncH264VLevel3_1 */ 31: level = "3.1"; break; -+ case /* eAVEncH264VLevel3_2 */ 32: level = "3.2"; break; -+ case /* eAVEncH264VLevel4 */ 40: level = "4"; break; -+ case /* eAVEncH264VLevel4_1 */ 41: level = "4.1"; break; -+ case /* eAVEncH264VLevel4_2 */ 42: level = "4.2"; break; -+ case /* eAVEncH264VLevel5 */ 50: level = "5"; break; -+ case /* eAVEncH264VLevel5_1 */ 51: level = "5.1"; break; -+ case /* eAVEncH264VLevel5_2 */ 52: level = "5.2"; break; -+ default: -+ GST_ERROR("Unrecognized H.264 level attribute %u\n", format->u.video.compressed.h264.level); -+ /* fallthrough */ -+ case 0: level = NULL; -+ } -+ -+ if (profile) -+ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); -+ -+ if (level) -+ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); -+ -+ return caps; -+ } -+ -+ /* uncompressed types */ -+ - if ((video_format = wg_video_format_to_gst(format->u.video.format)) == GST_VIDEO_FORMAT_UNKNOWN) - return NULL; - -@@ -587,6 +662,7 @@ static void CDECL wg_parser_stream_enable(struct wg_parser_stream *stream, const - case WG_VIDEO_FORMAT_YVYU: - case WG_VIDEO_FORMAT_UNKNOWN: - case WG_VIDEO_FORMAT_CINEPAK: -+ case WG_VIDEO_FORMAT_H264: - break; - } - -From b07022ca924d38109efb85d889f1ed3805406ca0 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 11 Mar 2021 12:58:32 -0500 -Subject: [PATCH] winegstreamer: Implement ::SetOutputType for decode - transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/decode_transform.c | 76 +++++++++++++++++++++++++-- - 1 file changed, 73 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index f709ef32fc1..0848cb47c9d 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -56,7 +56,7 @@ struct mf_decoder - IMFTransform IMFTransform_iface; - LONG refcount; - enum decoder_type type; -- IMFMediaType *input_type; -+ IMFMediaType *input_type, *output_type; - CRITICAL_SECTION cs; - }; - -@@ -107,6 +107,12 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) - decoder->input_type = NULL; - } - -+ if (decoder->output_type) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ - DeleteCriticalSection(&decoder->cs); - - heap_free(decoder); -@@ -336,9 +342,73 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF - - static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ struct wg_format output_format; -+ GUID major_type, subtype; -+ HRESULT hr; -+ unsigned int i; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %p, %#x.\n", decoder, id, type, flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (!type) -+ { -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&decoder->cs); -+ -+ if (decoder->output_type) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ -+ LeaveCriticalSection(&decoder->cs); -+ -+ return S_OK; -+ } -+ -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) -+ return MF_E_INVALIDTYPE; -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return MF_E_INVALIDTYPE; -+ -+ if (!(IsEqualGUID(&major_type, decoder_descs[decoder->type].major_type))) -+ return MF_E_INVALIDTYPE; -+ -+ for (i = 0; i < decoder_descs[decoder->type].output_types_count; i++) -+ { -+ if (IsEqualGUID(&subtype, decoder_descs[decoder->type].output_types[i])) -+ break; -+ if (i == decoder_descs[decoder->type].output_types_count) -+ return MF_E_INVALIDTYPE; -+ } -+ -+ mf_media_type_to_wg_format(type, &output_format); -+ if (!output_format.major_type) -+ return MF_E_INVALIDTYPE; -+ -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&decoder->cs); -+ -+ hr = S_OK; -+ -+ if (!decoder->output_type) -+ hr = MFCreateMediaType(&decoder->output_type); -+ -+ if (SUCCEEDED(hr) && FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes*) decoder->output_type))) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ -+ LeaveCriticalSection(&decoder->cs); -+ return hr; - } - - static HRESULT WINAPI mf_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -From 3e95cd0910098093e142e6aeb8a07978fec4a75d Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 11 Mar 2021 14:40:32 -0500 -Subject: [PATCH] winegstreamer: Implement ::Get(Input/Output)StreamInfo for - decode transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/decode_transform.c | 61 +++++++++++++++++++++++++-- - 1 file changed, 57 insertions(+), 4 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index 0848cb47c9d..dadd161bcc9 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -58,6 +58,7 @@ struct mf_decoder - enum decoder_type type; - IMFMediaType *input_type, *output_type; - CRITICAL_SECTION cs; -+ BOOL video; - }; - - static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) -@@ -150,16 +151,67 @@ static HRESULT WINAPI mf_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_s - - static HRESULT WINAPI mf_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) - { -- FIXME("%p %u %p.\n", iface, id, info); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); - -- return E_NOTIMPL; -+ TRACE("%p %u %p\n", decoder, id, info); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF; -+ info->cbAlignment = 0; -+ info->cbSize = 0; -+ /* TODO: retrieve following fields from gstreamer */ -+ info->hnsMaxLatency = 0; -+ info->cbMaxLookahead = 0; -+ return S_OK; - } - - static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) - { -- FIXME("%p %u %p.\n", iface, id, info); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ MFT_OUTPUT_STREAM_INFO stream_info = {}; -+ GUID output_subtype; -+ UINT64 framesize; - -- return E_NOTIMPL; -+ TRACE("%p %u %p\n", decoder, id, info); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&decoder->cs); -+ -+ if (!decoder->output_type) -+ { -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ if (decoder->video) -+ { -+ stream_info.dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | -+ MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES; -+ stream_info.cbSize = 0; -+ if (SUCCEEDED(IMFMediaType_GetGUID(decoder->output_type, &MF_MT_SUBTYPE, &output_subtype)) && -+ SUCCEEDED(IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_SIZE, &framesize))) -+ { -+ MFCalculateImageSize(&output_subtype, framesize >> 32, (UINT32) framesize, &stream_info.cbSize); -+ } -+ if (!stream_info.cbSize) -+ ERR("Failed to get desired output buffer size\n"); -+ } -+ else -+ { -+ stream_info.dwFlags = MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES; -+ stream_info.cbSize = 4; -+ } -+ stream_info.cbAlignment = 0; -+ -+ LeaveCriticalSection(&decoder->cs); -+ -+ *info = stream_info; -+ -+ return S_OK; - } - - static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -@@ -518,6 +570,7 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) - object->refcount = 1; - - object->type = type; -+ object->video = decoder_descs[type].major_type == &MFMediaType_Video; - - InitializeCriticalSection(&object->cs); - -From aac92e4ae27edb3f2c49f6a927bf1c871f18235a Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 16:55:15 -0400 -Subject: [PATCH] winegstreamer: Semi-stub ::GetAttributes for decoder - transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/decode_transform.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index dadd161bcc9..fb282d850ff 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -216,9 +216,9 @@ static HRESULT WINAPI mf_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD - - static HRESULT WINAPI mf_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) - { -- FIXME("%p, %p.\n", iface, attributes); -+ FIXME("%p, %p. semi-stub!\n", iface, attributes); - -- return E_NOTIMPL; -+ return MFCreateAttributes(attributes, 0); - } - - static HRESULT WINAPI mf_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -From 3dab47d4ca36f6fe3b6a0dcb3cefc99f27cd42f1 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 16:57:11 -0400 -Subject: [PATCH] winegstreamer: Register the H.264 decoder transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index de6bb4bae08..2dc607cd240 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -448,6 +448,20 @@ static const GUID *audio_converter_supported_types[] = - &MFAudioFormat_Float, - }; - -+static WCHAR h264_decoderW[] = L"H.264 Decoder"; -+static const GUID *h264_decoder_input_types[] = -+{ -+ &MFVideoFormat_H264, -+}; -+static const GUID *h264_decoder_output_types[] = -+{ -+ &MFVideoFormat_NV12, -+ &MFVideoFormat_I420, -+ &MFVideoFormat_IYUV, -+ &MFVideoFormat_YUY2, -+ &MFVideoFormat_YV12, -+}; -+ - static const struct mft - { - const GUID *clsid; -@@ -473,6 +487,17 @@ mfts[] = - ARRAY_SIZE(audio_converter_supported_types), - audio_converter_supported_types, - }, -+ { -+ &CLSID_MSH264DecoderMFT, -+ &MFT_CATEGORY_VIDEO_DECODER, -+ h264_decoderW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Video, -+ ARRAY_SIZE(h264_decoder_input_types), -+ h264_decoder_input_types, -+ ARRAY_SIZE(h264_decoder_output_types), -+ h264_decoder_output_types, -+ }, - }; - - HRESULT mfplat_DllRegisterServer(void) -From 7b7598711d37a3b6d90408456ded6c824ce8e447 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 16:59:29 -0400 -Subject: [PATCH] winegstreamer: Introduce AAC decoder transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/decode_transform.c | 10 ++++ - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 63 +++++++++++++++++++- - dlls/winegstreamer/quartz_parser.c | 2 + - dlls/winegstreamer/unixlib.h | 16 +++++ - dlls/winegstreamer/wg_parser.c | 62 +++++++++++++++++++ - dlls/winegstreamer/winegstreamer_classes.idl | 6 ++ - 7 files changed, 159 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index fb282d850ff..4967fc49012 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -33,6 +33,9 @@ const GUID *h264_input_types[] = {&MFVideoFormat_H264}; - /* NV12 comes first https://docs.microsoft.com/en-us/windows/win32/medfound/mft-decoder-expose-output-types-in-native-order . thanks to @vitorhnn */ - const GUID *h264_output_types[] = {&MFVideoFormat_NV12, &MFVideoFormat_I420, &MFVideoFormat_IYUV, &MFVideoFormat_YUY2, &MFVideoFormat_YV12}; - -+const GUID *aac_input_types[] = {&MFAudioFormat_AAC}; -+const GUID *aac_output_types[] = {&MFAudioFormat_Float}; -+ - static struct decoder_desc - { - const GUID *major_type; -@@ -49,6 +52,13 @@ static struct decoder_desc - h264_output_types, - ARRAY_SIZE(h264_output_types), - }, -+ { /* DECODER_TYPE_AAC */ -+ &MFMediaType_Audio, -+ aac_input_types, -+ ARRAY_SIZE(aac_input_types), -+ aac_output_types, -+ ARRAY_SIZE(aac_output_types), -+ } - }; - - struct mf_decoder -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 35f78ed3ccd..40db88bb795 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -121,6 +121,7 @@ HRESULT audio_converter_create(REFIID riid, void **ret) DECLSPEC_HIDDEN; - enum decoder_type - { - DECODER_TYPE_H264, -+ DECODER_TYPE_AAC, - }; - HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type) DECLSPEC_HIDDEN; - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 2dc607cd240..e8e913eda4c 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -413,6 +418,7 @@ class_objects[] = - { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, - { &CLSID_WINEAudioConverter, &audio_converter_create }, - { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, -+ { &CLSID_MSAACDecMFT, &aac_decoder_create }, - }; - - HRESULT mfplat_get_class_object(REFCLSID rclsid, REFIID riid, void **obj) -@@ -594,7 +600,8 @@ static IMFMediaType *mf_media_type_from_wg_format_audio(const struct wg_format * - IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, audio_formats[i].depth); - IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, format->u.audio.rate); - IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, format->u.audio.channels); -- IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, format->u.audio.channel_mask); -+ if (format->u.audio.channel_mask) -+ IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_CHANNEL_MASK, format->u.audio.channel_mask); - IMFMediaType_SetUINT32(type, &MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); - IMFMediaType_SetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, format->u.audio.channels * audio_formats[i].depth / 8); - -@@ -684,6 +691,8 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma - channel_mask = KSAUDIO_SPEAKER_MONO; - else if (channels == 2) - channel_mask = KSAUDIO_SPEAKER_STEREO; -+ else if IsEqualGUID(&subtype, &MFAudioFormat_AAC) -+ channel_mask = 0; - else - { - FIXME("Channel mask is not set.\n"); -@@ -696,6 +705,58 @@ static void mf_media_type_to_wg_format_audio(IMFMediaType *type, struct wg_forma - format->u.audio.channel_mask = channel_mask; - format->u.audio.rate = rate; - -+ if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) -+ { -+ UINT32 payload_type, indication, user_data_size; -+ unsigned char *user_data; -+ -+ format->u.audio.format = WG_AUDIO_FORMAT_AAC; -+ -+ if (SUCCEEDED(IMFMediaType_GetBlobSize(type, &MF_MT_USER_DATA, &user_data_size))) -+ { -+ user_data = malloc(user_data_size); -+ if (SUCCEEDED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, user_data, user_data_size, NULL))) -+ { -+ struct { -+ WORD payload_type; -+ WORD indication; -+ WORD type; -+ WORD reserved1; -+ DWORD reserved2; -+ } *aac_info = (void *) user_data; -+ -+ format->u.audio.compressed.aac.payload_type = aac_info->payload_type; -+ format->u.audio.compressed.aac.indication = aac_info->indication; -+ -+ /* Audio specific config is stored at after HEAACWAVEINFO in MF_MT_USER_DATA -+ https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-heaacwaveformat */ -+ if (user_data_size > 12) -+ { -+ user_data += 12; -+ user_data_size -= 12; -+ -+ if (user_data_size > sizeof(format->u.audio.compressed.aac.audio_specifc_config)) -+ { -+ FIXME("Encountered Audio-Specific-Config with a size larger than we support %u\n", user_data_size); -+ user_data_size = sizeof(format->u.audio.compressed.aac.audio_specifc_config); -+ } -+ -+ memcpy(format->u.audio.compressed.aac.audio_specifc_config, user_data, user_data_size); -+ format->u.audio.compressed.aac.asp_size = user_data_size; -+ } -+ -+ } -+ } -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &payload_type))) -+ format->u.audio.compressed.aac.payload_type = payload_type; -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &indication))) -+ format->u.audio.compressed.aac.indication = indication; -+ -+ return; -+ } -+ - for (i = 0; i < ARRAY_SIZE(audio_formats); ++i) - { - if (IsEqualGUID(&subtype, audio_formats[i].subtype) && depth == audio_formats[i].depth) -diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c -index 86f64bd1753..32393f4288d 100644 ---- a/dlls/winegstreamer/quartz_parser.c -+++ b/dlls/winegstreamer/quartz_parser.c -@@ -100,6 +100,7 @@ static bool amt_from_wg_format_audio(AM_MEDIA_TYPE *mt, const struct wg_format * - switch (format->u.audio.format) - { - case WG_AUDIO_FORMAT_UNKNOWN: -+ case WG_AUDIO_FORMAT_AAC: - return false; - - case WG_AUDIO_FORMAT_MPEG1_LAYER1: -@@ -313,6 +314,7 @@ unsigned int wg_format_get_max_size(const struct wg_format *format) - case WG_AUDIO_FORMAT_MPEG1_LAYER3: - return 40000; - -+ case WG_AUDIO_FORMAT_AAC: - case WG_AUDIO_FORMAT_UNKNOWN: - FIXME("Cannot guess maximum sample size for unknown audio format.\n"); - return 0; -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index f3db631d16d..d9c675ea873 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -92,11 +92,27 @@ struct wg_format - WG_AUDIO_FORMAT_MPEG1_LAYER1, - WG_AUDIO_FORMAT_MPEG1_LAYER2, - WG_AUDIO_FORMAT_MPEG1_LAYER3, -+ -+ WG_AUDIO_FORMAT_AAC, - } format; - - uint32_t channels; - uint32_t channel_mask; /* In WinMM format. */ - uint32_t rate; -+ -+ union -+ { -+ struct -+ { -+ uint32_t payload_type; -+ uint32_t indication; -+ /* The definition of this structure is found in ISO/IEC 14496-3, -+ which we don't have access to, so we'll just keep -+ the size set to the largest instance we've seen used. */ -+ unsigned char audio_specifc_config[2]; -+ uint32_t asp_size; -+ } aac; -+ } compressed; - } audio; - } u; - }; - -diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 064a6872c79..4c58d83403b 100644 ---- a/dlls/winegstreamer/winegstreamer_classes.idl -+++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -73,3 +73,9 @@ coclass WINEAudioConverter { } - uuid(62ce7e72-4c71-4d20-b15d-452831a87d9d) - ] - coclass CMSH264DecoderMFT { } -+ -+[ -+ threading(both), -+ uuid(32d186a7-218f-4c75-8876-dd77273a8999) -+] -+coclass CMSAACDecMFT { } -From 22de47ce147704d1a22a4a8525e6b2ecab7afe08 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 17:00:51 -0400 -Subject: [PATCH] winegstreamer: Rename GStreamer objects to be more generic. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/wg_parser.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 5ff25dd8d22..c4d4853c873 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1258,7 +1258,7 @@ static struct wg_parser_stream *create_stream(struct wg_parser *parser) - pthread_cond_init(&stream->event_cond, NULL); - pthread_cond_init(&stream->event_empty_cond, NULL); - -- sprintf(pad_name, "qz_sink_%u", parser->stream_count); -+ sprintf(pad_name, "wine_sink_%u", parser->stream_count); - stream->my_sink = gst_pad_new(pad_name, GST_PAD_SINK); - gst_pad_set_element_private(stream->my_sink, stream); - gst_pad_set_chain_function(stream->my_sink, sink_chain_cb); -@@ -1815,7 +1815,7 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) - - static NTSTATUS wg_parser_connect(void *args) - { -- GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("quartz_src", -+ GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", - GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); - const struct wg_parser_connect_params *params = args; - struct wg_parser *parser = params->parser; -@@ -1834,7 +1834,7 @@ static NTSTATUS wg_parser_connect(void *args) - parser->container = gst_bin_new(NULL); - gst_element_set_bus(parser->container, parser->bus); - -- parser->my_src = gst_pad_new_from_static_template(&src_template, "quartz-src"); -+ parser->my_src = gst_pad_new_from_static_template(&src_template, "wine-src"); - gst_pad_set_getrange_function(parser->my_src, src_getrange_cb); - gst_pad_set_query_function(parser->my_src, src_query_cb); - gst_pad_set_activatemode_function(parser->my_src, src_activate_mode_cb); -From 7b786ed20439f43d6d92161481db91ad1460971e Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 17:01:54 -0400 -Subject: [PATCH] winegstreamer: Report streams backwards in media source. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/media_source.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 6ecd345cb73..f33be0b0b40 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -1482,7 +1482,7 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); - for (i = 0; i < object->stream_count; i++) - { -- IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[i]); -+ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[object->stream_count - 1 - i]); - } - - if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) -From 1ff45c8c25d967a9c4c21d4d17e75e080ddcc0dc Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 15:12:20 -0400 -Subject: [PATCH] winegstreamer: Implement ::Get(Input/Output)StreamInfo for - audio conversion transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/audioconvert.c | 42 ++++++++++++++++++++++++++++--- - 1 file changed, 38 insertions(+), 4 deletions(-) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 33350fb3566..cebdc7ada2a 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -115,16 +115,50 @@ static HRESULT WINAPI audio_converter_GetStreamIDs(IMFTransform *iface, DWORD in - - static HRESULT WINAPI audio_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) - { -- FIXME("%p, %lu, %p.\n", iface, id, info); -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - -- return E_NOTIMPL; -+ TRACE("%p, %lu, %p.\n", iface, id, info); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF; -+ info->cbMaxLookahead = 0; -+ info->cbAlignment = 0; -+ info->hnsMaxLatency = 0; -+ info->cbSize = 0; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->input_type) -+ IMFMediaType_GetUINT32(converter->input_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &info->cbSize); -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - } - - static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) - { -- FIXME("%p. %lu, %p.\n", iface, id, info); -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - -- return E_NOTIMPL; -+ TRACE("%p. %lu, %p.\n", iface, id, info); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ info->dwFlags = MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES | MFT_OUTPUT_STREAM_WHOLE_SAMPLES; -+ info->cbAlignment = 0; -+ info->cbSize = 0; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->output_type) -+ IMFMediaType_GetUINT32(converter->output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &info->cbSize); -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - } - - static HRESULT WINAPI audio_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -From b43022ba6946448f3a25b6d5ace17a654eb5cf34 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 15:19:32 -0400 -Subject: [PATCH] winegstreamer: Semi-stub Get*Attributes functions for audio - converter transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/audioconvert.c | 39 +++++++++++++++++++++++++++---- - 1 file changed, 35 insertions(+), 4 deletions(-) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index cebdc7ada2a..dfc7dd4a307 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -35,6 +35,7 @@ struct audio_converter - IMFMediaType *input_type; - IMFMediaType *output_type; - CRITICAL_SECTION cs; -+ IMFAttributes *attributes, *output_attributes; - }; - - static struct audio_converter *impl_audio_converter_from_IMFTransform(IMFTransform *iface) -@@ -80,6 +81,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) - { - transform->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&transform->cs); -+ if (transform->attributes) -+ IMFAttributes_Release(transform->attributes); -+ if (transform->output_attributes) -+ IMFAttributes_Release(transform->output_attributes); - free(transform); - } - -@@ -163,9 +168,14 @@ static HRESULT WINAPI audio_converter_GetOutputStreamInfo(IMFTransform *iface, D - - static HRESULT WINAPI audio_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) - { -- FIXME("%p, %p.\n", iface, attributes); -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - -- return E_NOTIMPL; -+ TRACE("%p, %p.\n", iface, attributes); -+ -+ *attributes = converter->attributes; -+ IMFAttributes_AddRef(*attributes); -+ -+ return S_OK; - } - - static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -@@ -179,9 +189,17 @@ static HRESULT WINAPI audio_converter_GetInputStreamAttributes(IMFTransform *ifa - static HRESULT WINAPI audio_converter_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, - IMFAttributes **attributes) - { -- FIXME("%p, %lu, %p.\n", iface, id, attributes); -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - -- return E_NOTIMPL; -+ TRACE("%p, %lu, %p.\n", iface, id, attributes); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ *attributes = converter->output_attributes; -+ IMFAttributes_AddRef(*attributes); -+ -+ return S_OK; - } - - static HRESULT WINAPI audio_converter_DeleteInputStream(IMFTransform *iface, DWORD id) -@@ -601,6 +619,7 @@ static const IMFTransformVtbl audio_converter_vtbl = - HRESULT audio_converter_create(REFIID riid, void **ret) - { - struct audio_converter *object; -+ HRESULT hr; - - TRACE("%s %p\n", debugstr_guid(riid), ret); - -@@ -613,6 +632,18 @@ HRESULT audio_converter_create(REFIID riid, void **ret) - InitializeCriticalSection(&object->cs); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": audio_converter_lock"); - -+ if (FAILED(hr = MFCreateAttributes(&object->attributes, 0))) -+ { -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return hr; -+ } -+ -+ if (FAILED(hr = MFCreateAttributes(&object->output_attributes, 0))) -+ { -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return hr; -+ } -+ - *ret = &object->IMFTransform_iface; - return S_OK; - } -From 3f412f8fadd42ae05bcd500db5d14160dd2ee9eb Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 15:35:20 -0400 -Subject: [PATCH] winegstreamer: Introduce color conversion transform. - -Serves as a wrapper of videoconvert, and exposes the CColorConverterDMO MFT interface. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/colorconvert.c | 298 +++++++++++++++++++ - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 2 + - dlls/winegstreamer/winegstreamer_classes.idl | 6 + - include/wmcodecdsp.idl | 5 + - 6 files changed, 313 insertions(+) - create mode 100644 dlls/winegstreamer/colorconvert.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index c612ef340b7..36b5be80978 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -8,6 +8,7 @@ EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) - - C_SRCS = \ - audioconvert.c \ -+ colorconvert.c \ - decode_transform.c \ - main.c \ - media_source.c \ -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -new file mode 100644 -index 00000000000..1f0d061a30c ---- /dev/null -+++ b/dlls/winegstreamer/colorconvert.c -@@ -0,0 +1,298 @@ -+/* GStreamer Color Converter -+ * -+ * Copyright 2020 Derek Lesho -+ * -+ * 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 "gst_private.h" -+ -+#include "mfapi.h" -+#include "mferror.h" -+ -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -+ -+struct color_converter -+{ -+ IMFTransform IMFTransform_iface; -+ LONG refcount; -+}; -+ -+static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface) -+{ -+ return CONTAINING_RECORD(iface, struct color_converter, IMFTransform_iface); -+} -+ -+static HRESULT WINAPI color_converter_QueryInterface(IMFTransform *iface, REFIID riid, void **obj) -+{ -+ TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); -+ -+ if (IsEqualGUID(riid, &IID_IMFTransform) || -+ IsEqualGUID(riid, &IID_IUnknown)) -+ { -+ *obj = iface; -+ IMFTransform_AddRef(iface); -+ return S_OK; -+ } -+ -+ WARN("Unsupported %s.\n", debugstr_guid(riid)); -+ *obj = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI color_converter_AddRef(IMFTransform *iface) -+{ -+ struct color_converter *transform = impl_color_converter_from_IMFTransform(iface); -+ ULONG refcount = InterlockedIncrement(&transform->refcount); -+ -+ TRACE("%p, refcount %u.\n", iface, refcount); -+ -+ return refcount; -+} -+ -+static ULONG WINAPI color_converter_Release(IMFTransform *iface) -+{ -+ struct color_converter *transform = impl_color_converter_from_IMFTransform(iface); -+ ULONG refcount = InterlockedDecrement(&transform->refcount); -+ -+ TRACE("%p, refcount %u.\n", iface, refcount); -+ -+ if (!refcount) -+ { -+ free(transform); -+ } -+ -+ return refcount; -+} -+ -+static HRESULT WINAPI color_converter_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, -+ DWORD *output_minimum, DWORD *output_maximum) -+{ -+ TRACE("%p, %p, %p, %p, %p.\n", iface, input_minimum, input_maximum, output_minimum, output_maximum); -+ -+ *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI color_converter_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -+{ -+ TRACE("%p, %p, %p.\n", iface, inputs, outputs); -+ -+ *inputs = *outputs = 1; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI color_converter_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, -+ DWORD output_size, DWORD *outputs) -+{ -+ TRACE("%p %u %p %u %p.\n", iface, input_size, inputs, output_size, outputs); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -+{ -+ FIXME("%p %u %p.\n", iface, id, info); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -+{ -+ FIXME("%p %u %p.\n", iface, id, info); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -+{ -+ FIXME("%p, %p.\n", iface, attributes); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, attributes); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, attributes); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_DeleteInputStream(IMFTransform *iface, DWORD id) -+{ -+ TRACE("%p, %u.\n", iface, id); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -+{ -+ TRACE("%p, %u, %p.\n", iface, streams, ids); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -+{ -+ FIXME("%p, %u, %p.\n", iface, id, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_GetOutputStatus(IMFTransform *iface, DWORD *flags) -+{ -+ FIXME("%p, %p.\n", iface, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -+{ -+ FIXME("%p, %s, %s.\n", iface, wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -+{ -+ TRACE("%p, %u, %p.\n", iface, id, event); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -+{ -+ FIXME("%p, %u %lu.\n", iface, message, param); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -+{ -+ FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -+{ -+ FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ -+ return E_NOTIMPL; -+} -+ -+static const IMFTransformVtbl color_converter_vtbl = -+{ -+ color_converter_QueryInterface, -+ color_converter_AddRef, -+ color_converter_Release, -+ color_converter_GetStreamLimits, -+ color_converter_GetStreamCount, -+ color_converter_GetStreamIDs, -+ color_converter_GetInputStreamInfo, -+ color_converter_GetOutputStreamInfo, -+ color_converter_GetAttributes, -+ color_converter_GetInputStreamAttributes, -+ color_converter_GetOutputStreamAttributes, -+ color_converter_DeleteInputStream, -+ color_converter_AddInputStreams, -+ color_converter_GetInputAvailableType, -+ color_converter_GetOutputAvailableType, -+ color_converter_SetInputType, -+ color_converter_SetOutputType, -+ color_converter_GetInputCurrentType, -+ color_converter_GetOutputCurrentType, -+ color_converter_GetInputStatus, -+ color_converter_GetOutputStatus, -+ color_converter_SetOutputBounds, -+ color_converter_ProcessEvent, -+ color_converter_ProcessMessage, -+ color_converter_ProcessInput, -+ color_converter_ProcessOutput, -+}; -+ -+HRESULT color_converter_create(REFIID riid, void **ret) -+{ -+ struct color_converter *object; -+ -+ TRACE("%s %p\n", debugstr_guid(riid), ret); -+ -+ if (!(object = calloc(1, sizeof(*object)))) -+ return E_OUTOFMEMORY; -+ -+ object->IMFTransform_iface.lpVtbl = &color_converter_vtbl; -+ object->refcount = 1; -+ -+ *ret = &object->IMFTransform_iface; -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 40db88bb795..fdb7ab375e5 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -117,6 +117,7 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) DE - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); - - HRESULT audio_converter_create(REFIID riid, void **ret); -+HRESULT color_converter_create(REFIID riid, void **ret); - - enum decoder_type - { -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index be88fb27c6d..6cfab806bd8 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -410,6 +410,7 @@ class_objects[] = - { &CLSID_VideoProcessorMFT, &video_processor_create }, - { &CLSID_GStreamerByteStreamHandler, &winegstreamer_stream_handler_create }, - { &CLSID_WINEAudioConverter, &audio_converter_create }, -+ { &CLSID_CColorConvertDMO, &color_converter_create }, - { &CLSID_MSH264DecoderMFT, &h264_decoder_create }, - { &CLSID_MSAACDecMFT, &aac_decoder_create }, - }; -diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl -index 4c58d83403b..093fca3521e 100644 ---- a/dlls/winegstreamer/winegstreamer_classes.idl -+++ b/dlls/winegstreamer/winegstreamer_classes.idl -@@ -79,3 +79,9 @@ coclass CMSH264DecoderMFT { } - uuid(32d186a7-218f-4c75-8876-dd77273a8999) - ] - coclass CMSAACDecMFT { } -+ -+[ -+ threading(both), -+ uuid(98230571-0087-4204-b020-3282538e57d3) -+] -+coclass CColorConvertDMO { } -diff --git a/include/wmcodecdsp.idl b/include/wmcodecdsp.idl -index 1e43766a358..086d16836fc 100644 ---- a/include/wmcodecdsp.idl -+++ b/include/wmcodecdsp.idl -@@ -40,3 +40,8 @@ coclass CMSH264DecoderMFT {} - uuid(93af0c51-2275-45d2-a35b-f2ba21caed00) - ] - coclass AACMFTEncoder {}; -+ -+[ -+ uuid(98230571-0087-4204-b020-3282538e57d3) -+] -+coclass CColorConvertDMO {} -From ee07db9e937f778f1fc4e22158916e75efeb8933 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 15:37:17 -0400 -Subject: [PATCH] winegstreamer: Register the color conversion transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/mfplat.c | 35 +++++++++++++++++++++++++++++++++-- - 1 file changed, 33 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 6cfab806bd8..ba6e60ca159 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -456,6 +456,26 @@ static const GUID *audio_converter_supported_types[] = - &MFAudioFormat_Float, - }; - -+static WCHAR color_converterW[] = L"Color Converter"; -+static const GUID *color_converter_supported_types[] = -+{ -+ &MFVideoFormat_RGB24, -+ &MFVideoFormat_RGB32, -+ &MFVideoFormat_RGB555, -+ &MFVideoFormat_RGB8, -+ &MFVideoFormat_AYUV, -+ &MFVideoFormat_I420, -+ &MFVideoFormat_IYUV, -+ &MFVideoFormat_NV11, -+ &MFVideoFormat_NV12, -+ &MFVideoFormat_UYVY, -+ &MFVideoFormat_v216, -+ &MFVideoFormat_v410, -+ &MFVideoFormat_YUY2, -+ &MFVideoFormat_YVYU, -+ &MFVideoFormat_YVYU, -+}; -+ - static WCHAR h264_decoderW[] = L"H.264 Decoder"; - static const GUID *h264_decoder_input_types[] = - { -@@ -507,7 +527,18 @@ mfts[] = - audio_converter_supported_types, - }, - { -- &CLSID_MSH264DecoderMFT, -+ &CLSID_CColorConvertDMO, -+ &MFT_CATEGORY_VIDEO_EFFECT, -+ color_converterW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Video, -+ ARRAY_SIZE(color_converter_supported_types), -+ color_converter_supported_types, -+ ARRAY_SIZE(color_converter_supported_types), -+ color_converter_supported_types, -+ }, -+ { -+ &CLSID_MSAACDecMFT, - &MFT_CATEGORY_VIDEO_DECODER, - h264_decoderW, - MFT_ENUM_FLAG_SYNCMFT, -@@ -534,7 +565,7 @@ HRESULT mfplat_DllRegisterServer(void) - { - unsigned int i, j; - HRESULT hr; -- MFT_REGISTER_TYPE_INFO input_types[4], output_types[2]; -+ MFT_REGISTER_TYPE_INFO input_types[15], output_types[15]; - - for (i = 0; i < ARRAY_SIZE(mfts); i++) - { -From 7128152d27eef41d9fb5f971550192001f200874 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 15:41:33 -0400 -Subject: [PATCH] winegstreamer: Implement ::GetInputAvailableType for color - conversion transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 48 +++++++++++++++++++++++++++++-- - 1 file changed, 46 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 1f0d061a30c..078782daaed 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -26,6 +26,24 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -+static const GUID *raw_types[] = { -+ &MFVideoFormat_RGB24, -+ &MFVideoFormat_RGB32, -+ &MFVideoFormat_RGB555, -+ &MFVideoFormat_RGB8, -+ &MFVideoFormat_AYUV, -+ &MFVideoFormat_I420, -+ &MFVideoFormat_IYUV, -+ &MFVideoFormat_NV11, -+ &MFVideoFormat_NV12, -+ &MFVideoFormat_UYVY, -+ &MFVideoFormat_v216, -+ &MFVideoFormat_v410, -+ &MFVideoFormat_YUY2, -+ &MFVideoFormat_YVYU, -+ &MFVideoFormat_YVYU, -+}; -+ - struct color_converter - { - IMFTransform IMFTransform_iface; -@@ -160,9 +178,35 @@ static HRESULT WINAPI color_converter_AddInputStreams(IMFTransform *iface, DWORD - static HRESULT WINAPI color_converter_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ IMFMediaType *ret; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %u, %p.\n", iface, id, index, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (index >= ARRAY_SIZE(raw_types)) -+ return MF_E_NO_MORE_TYPES; -+ -+ if (FAILED(hr = MFCreateMediaType(&ret))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) -+ { -+ IMFMediaType_Release(ret); -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_SUBTYPE, raw_types[index]))) -+ { -+ IMFMediaType_Release(ret); -+ return hr; -+ } -+ -+ *type = ret; -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -From 6a6a3137548fa66b49b01c58236ea8fa259beb6b Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 16:01:18 -0400 -Subject: [PATCH] winegstreamer: Implement ::SetInputType for color conversion - transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 75 ++++++++++++++++++++++++++++++- - 1 file changed, 73 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 078782daaed..06186ed7846 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -48,6 +48,8 @@ struct color_converter - { - IMFTransform IMFTransform_iface; - LONG refcount; -+ IMFMediaType *input_type; -+ CRITICAL_SECTION cs; - }; - - static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface) -@@ -91,6 +93,8 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) - - if (!refcount) - { -+ transform->cs.DebugInfo->Spare[0] = 0; -+ DeleteCriticalSection(&transform->cs); - free(transform); - } - -@@ -219,9 +223,73 @@ static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface - - static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ GUID major_type, subtype; -+ unsigned int i; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (!type) -+ { -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->input_type) -+ { -+ IMFMediaType_Release(converter->input_type); -+ converter->input_type = NULL; -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; -+ } -+ -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) -+ return MF_E_INVALIDTYPE; -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return MF_E_INVALIDTYPE; -+ -+ if (!IsEqualGUID(&major_type, &MFMediaType_Video)) -+ return MF_E_INVALIDTYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(raw_types); i++) -+ { -+ if (IsEqualGUID(&subtype, raw_types[i])) -+ break; -+ } -+ -+ if (i == ARRAY_SIZE(raw_types)) -+ return MF_E_INVALIDTYPE; -+ -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ hr = S_OK; -+ -+ if (!converter->input_type) -+ hr = MFCreateMediaType(&converter->input_type); -+ -+ if (SUCCEEDED(hr)) -+ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->input_type); -+ -+ if (FAILED(hr)) -+ { -+ IMFMediaType_Release(converter->input_type); -+ converter->input_type = NULL; -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return hr; - } - - static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -@@ -337,6 +405,9 @@ HRESULT color_converter_create(REFIID riid, void **ret) - object->IMFTransform_iface.lpVtbl = &color_converter_vtbl; - object->refcount = 1; - -+ InitializeCriticalSection(&object->cs); -+ object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); -+ - *ret = &object->IMFTransform_iface; - return S_OK; - } -From 7bfd5bda7b93a8be57fa44738de9cbe6d6a0202c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 16:04:31 -0400 -Subject: [PATCH] winegstreamer: Implement ::GetOutputAvailableType for color - conversion transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 38 +++++++++++++++++++++++++++++-- - 1 file changed, 36 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 06186ed7846..6d7064a4482 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -216,9 +216,43 @@ static HRESULT WINAPI color_converter_GetInputAvailableType(IMFTransform *iface, - static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("%p, %u, %u, %p.\n", iface, id, index, type); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ IMFMediaType *ret; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %u, %p.\n", iface, id, index, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (index >= ARRAY_SIZE(raw_types)) -+ return MF_E_NO_MORE_TYPES; -+ -+ if (FAILED(hr = MFCreateMediaType(&ret))) -+ return hr; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->input_type) -+ IMFMediaType_CopyAllItems(converter->input_type, (IMFAttributes *) ret); -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) -+ { -+ IMFMediaType_Release(ret); -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(ret, &MF_MT_SUBTYPE, raw_types[index]))) -+ { -+ IMFMediaType_Release(ret); -+ return hr; -+ } -+ -+ *type = ret; -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -From 4d7cbba3ab661fb4146716cb8f82d067905d1b2c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 16:26:28 -0400 -Subject: [PATCH] winegstreamer: Implement ::SetOutputType for color conversion - transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 99 ++++++++++++++++++++++++++++++- - 1 file changed, 97 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 6d7064a4482..e001c6c827e 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -49,6 +49,7 @@ struct color_converter - IMFTransform IMFTransform_iface; - LONG refcount; - IMFMediaType *input_type; -+ IMFMediaType *output_type; - CRITICAL_SECTION cs; - }; - -@@ -95,6 +96,8 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) - { - transform->cs.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&transform->cs); -+ if (transform->output_type) -+ IMFMediaType_Release(transform->output_type); - free(transform); - } - -@@ -258,6 +261,7 @@ static HRESULT WINAPI color_converter_GetOutputAvailableType(IMFTransform *iface - static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { - struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ UINT64 input_framesize, output_framesize; - GUID major_type, subtype; - unsigned int i; - HRESULT hr; -@@ -302,6 +306,19 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - if (i == ARRAY_SIZE(raw_types)) - return MF_E_INVALIDTYPE; - -+ EnterCriticalSection(&converter->cs); -+ -+ if(converter->output_type -+ && SUCCEEDED(IMFMediaType_GetUINT64(converter->output_type, &MF_MT_FRAME_SIZE, &output_framesize)) -+ && SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &input_framesize)) -+ && input_framesize != output_framesize) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_INVALIDTYPE; -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - -@@ -328,9 +345,87 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - - static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ UINT64 input_framesize, output_framesize; -+ GUID major_type, subtype; -+ unsigned int i; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %p, %#x.\n", iface, id, type, flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (!type) -+ { -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->output_type) -+ { -+ IMFMediaType_Release(converter->output_type); -+ converter->output_type = NULL; -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; -+ } -+ -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major_type))) -+ return MF_E_INVALIDTYPE; -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return MF_E_INVALIDTYPE; -+ -+ if (!IsEqualGUID(&major_type, &MFMediaType_Video)) -+ return MF_E_INVALIDTYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(raw_types); i++) -+ { -+ if (IsEqualGUID(&subtype, raw_types[i])) -+ break; -+ } -+ -+ if (i == ARRAY_SIZE(raw_types)) -+ return MF_E_INVALIDTYPE; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if(converter->input_type -+ && SUCCEEDED(IMFMediaType_GetUINT64(converter->input_type, &MF_MT_FRAME_SIZE, &input_framesize)) -+ && SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &output_framesize)) -+ && input_framesize != output_framesize) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return MF_E_INVALIDTYPE; -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ if (flags & MFT_SET_TYPE_TEST_ONLY) -+ return S_OK; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ hr = S_OK; -+ -+ if (!converter->output_type) -+ hr = MFCreateMediaType(&converter->output_type); -+ -+ if (SUCCEEDED(hr)) -+ hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *) converter->output_type); -+ -+ if (FAILED(hr)) -+ { -+ IMFMediaType_Release(converter->output_type); -+ converter->output_type = NULL; -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -From 70281310e888b594bbd3e20db732ee419446fab2 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 16:50:47 -0400 -Subject: [PATCH] winegstreamer: Implement ::ProcessMessage for color - conversion MFT. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index e001c6c827e..0e8980659a5 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -472,9 +472,17 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id - - static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { -- FIXME("%p, %u %lu.\n", iface, message, param); -+ TRACE("%p, %u %lu.\n", iface, message, param); - -- return E_NOTIMPL; -+ switch(message) -+ { -+ case MFT_MESSAGE_COMMAND_FLUSH: -+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: -+ return S_OK; -+ default: -+ FIXME("Unhandled message type %x.\n", message); -+ return E_NOTIMPL; -+ } - } - - static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -From b30d2aa27ec5ac7824a9c8fea235651e12e33c05 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 17 Mar 2021 17:01:11 -0400 -Subject: [PATCH] winegstreamer: Implement ::Get(Input/Output)StreamInfo for - color conversion transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/colorconvert.c | 64 +++++++++++++++++++++++++++++-- - 1 file changed, 60 insertions(+), 4 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 0e8980659a5..db4ca4e3fbe 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -133,16 +133,72 @@ static HRESULT WINAPI color_converter_GetStreamIDs(IMFTransform *iface, DWORD in - - static HRESULT WINAPI color_converter_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) - { -- FIXME("%p %u %p.\n", iface, id, info); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ UINT64 framesize; -+ GUID subtype; - -- return E_NOTIMPL; -+ TRACE("%p %u %p.\n", iface, id, info); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_DOES_NOT_ADDREF | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; -+ info->cbMaxLookahead = 0; -+ info->cbAlignment = 0; -+ info->hnsMaxLatency = 0; -+ info->cbSize = 0; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->input_type) -+ { -+ if (SUCCEEDED(IMFMediaType_GetGUID(converter->input_type, &MF_MT_SUBTYPE, &subtype)) && -+ SUCCEEDED(IMFMediaType_GetUINT64(converter->input_type, &MF_MT_FRAME_SIZE, &framesize))) -+ { -+ MFCalculateImageSize(&subtype, framesize >> 32, (UINT32) framesize, &info->cbSize); -+ } -+ -+ if (!info->cbSize) -+ WARN("Failed to get desired input buffer size, the non-provided sample path will likely break\n"); -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) - { -- FIXME("%p %u %p.\n", iface, id, info); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ UINT64 framesize; -+ GUID subtype; - -- return E_NOTIMPL; -+ TRACE("%p %u %p.\n", iface, id, info); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ info->dwFlags = MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES | MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER; -+ info->cbAlignment = 0; -+ info->cbSize = 0; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->output_type) -+ { -+ if (SUCCEEDED(IMFMediaType_GetGUID(converter->output_type, &MF_MT_SUBTYPE, &subtype)) && -+ SUCCEEDED(IMFMediaType_GetUINT64(converter->output_type, &MF_MT_FRAME_SIZE, &framesize))) -+ { -+ MFCalculateImageSize(&subtype, framesize >> 32, (UINT32) framesize, &info->cbSize); -+ } -+ -+ if (!info->cbSize) -+ WARN("Failed to get desired output buffer size, the non-provided sample path will likely break\n"); -+ } -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ return S_OK; - } - - static HRESULT WINAPI color_converter_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -From db4b3e51677e463fd5ffec9e83943e3a2060aca1 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 18 Mar 2021 13:53:42 -0400 -Subject: [PATCH] mf/topology: Forward failure from ::SetOutputType when - resolving topology. - -Signed-off-by: Derek Lesho ---- - dlls/mf/topology.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c -index f97c0cc75d3..34459912fb0 100644 ---- a/dlls/mf/topology.c -+++ b/dlls/mf/topology.c -@@ -2122,8 +2122,7 @@ static HRESULT connect_to_sink(struct transform_output_type *output_type, struct - hr = IMFMediaTypeHandler_SetCurrentMediaType(context->sink_handler, output_type->type); - if (SUCCEEDED(hr)) - hr = IMFTransform_SetOutputType(output_type->transform, 0, output_type->type, 0); -- -- return S_OK; -+ return hr; - } - - static HRESULT connect_to_converter(struct transform_output_type *output_type, struct connect_context *context) -From a45f19da9ddb47028f15af590b41a67ee3c11ae1 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 18 Mar 2021 14:53:49 -0400 -Subject: [PATCH] winegstreamer: Handle flush command in audio converstion - transform. - -Signed-off-by: Derek Lesho ---- - dlls/winegstreamer/audioconvert.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index dfc7dd4a307..46712817647 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -563,6 +563,7 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME - - switch(message) - { -+ case MFT_MESSAGE_COMMAND_FLUSH: - case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: - return S_OK; - default: -From 0fc05746836c78bb84aea57e2058a79afeaf1be8 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 4 Dec 2020 16:17:11 -0500 -Subject: [PATCH] winegstreamer: In the default configuration, select one - stream of each major type. - ---- - dlls/winegstreamer/media_source.c | 22 +++++++++++++++++++++- - 1 file changed, 21 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index f33be0b0b40..44d1796a5e9 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -1389,6 +1389,7 @@ static const IMFMediaSourceVtbl IMFMediaSource_vtbl = - - static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_source **out_media_source) - { -+ BOOL video_selected = FALSE, audio_selected = FALSE; - IMFStreamDescriptor **descriptors = NULL; - unsigned int stream_count = UINT_MAX; - struct media_source *object; -@@ -1488,9 +1489,28 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) - goto fail; - -+ /* Select one of each major type. */ - for (i = 0; i < object->stream_count; i++) - { -- IMFPresentationDescriptor_SelectStream(object->pres_desc, i); -+ IMFMediaTypeHandler *handler; -+ GUID major_type; -+ BOOL select_stream = FALSE; -+ -+ IMFStreamDescriptor_GetMediaTypeHandler(descriptors[i], &handler); -+ IMFMediaTypeHandler_GetMajorType(handler, &major_type); -+ if (IsEqualGUID(&major_type, &MFMediaType_Video) && !video_selected) -+ { -+ select_stream = TRUE; -+ video_selected = TRUE; -+ } -+ if (IsEqualGUID(&major_type, &MFMediaType_Audio) && !audio_selected) -+ { -+ select_stream = TRUE; -+ audio_selected = TRUE; -+ } -+ if (select_stream) -+ IMFPresentationDescriptor_SelectStream(object->pres_desc, i); -+ IMFMediaTypeHandler_Release(handler); - IMFStreamDescriptor_Release(descriptors[i]); - } - free(descriptors); -From ef5b915fecf45c85af5821aa8d7e61a2d0a06f00 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 18 Oct 2021 12:29:34 -0500 -Subject: [PATCH] winegstreamer: Implement IMFTransform::GetOutputCurrentType - in colorconvert - -CW-Bug-Id: #19465 ---- - dlls/winegstreamer/colorconvert.c | 28 ++++++++++++++++++++++++++-- - 1 file changed, 26 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index db4ca4e3fbe..baf429d42f9 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -493,9 +493,33 @@ static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, D - - static HRESULT WINAPI color_converter_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) - { -- FIXME("%p, %u, %p.\n", iface, id, type); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ IMFMediaType *ret; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %p.\n", converter, id, type); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (FAILED(hr = MFCreateMediaType(&ret))) -+ return hr; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (converter->output_type) -+ hr = IMFMediaType_CopyAllItems(converter->output_type, (IMFAttributes *)ret); -+ else -+ hr = MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ LeaveCriticalSection(&converter->cs); -+ -+ if (SUCCEEDED(hr)) -+ *type = ret; -+ else -+ IMFMediaType_Release(ret); -+ -+ return hr; - } - - static HRESULT WINAPI color_converter_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -From b08f896cd3dbfd0623ff2575fc66e7c9b2fea41a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 14 Dec 2021 22:31:29 +0100 -Subject: [PATCH] winegstreamer: Implement stream draining support. - ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/main.c | 5 +++ - dlls/winegstreamer/unixlib.h | 2 + - dlls/winegstreamer/wg_parser.c | 70 +++++++++++++++++++++++++++++++- - 4 files changed, 77 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index fdb7ab375e5..db2959c8f6b 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -95,6 +95,7 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC - /* start_pos and stop_pos are in 100-nanosecond units. */ - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); -+bool wg_parser_stream_drain(struct wg_parser_stream *stream); - - unsigned int wg_format_get_max_size(const struct wg_format *format); - -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index d63d4100947..3043ad77f3d 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -252,6 +252,11 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); - } - -+bool wg_parser_stream_drain(struct wg_parser_stream *stream) -+{ -+ return !__wine_unix_call(unix_handle, unix_wg_parser_stream_drain, stream); -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - if (reason == DLL_PROCESS_ATTACH) -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index d9c675ea873..fc9d0c3c80d 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -271,6 +271,8 @@ enum unix_funcs - - unix_wg_parser_stream_get_duration, - unix_wg_parser_stream_seek, -+ -+ unix_wg_parser_stream_drain, - }; - - #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index c4d4853c873..d21346b7f38 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -87,7 +87,7 @@ struct wg_parser - GstFlowReturn ret; - } read_request; - -- bool flushing, sink_connected; -+ bool flushing, sink_connected, draining; - - bool unlimited_buffering; - }; -@@ -831,6 +831,16 @@ static NTSTATUS wg_parser_stream_get_event(void *args) - - *params->event = stream->event; - -+ /* Set to ensure that drain isn't called on an EOS stream, causing a lock-up -+ due to pull_data never being called again */ -+ if (stream->event.type == WG_PARSER_EVENT_EOS) -+ stream->eos = true; -+ -+ /* Set to ensure that drain isn't called on an EOS stream, causing a lock-up -+ due to pull_data never being called again */ -+ if (stream->event.type == WG_PARSER_EVENT_EOS) -+ stream->eos = true; -+ - if (stream->event.type != WG_PARSER_EVENT_BUFFER) - { - stream->event.type = WG_PARSER_EVENT_NONE; -@@ -921,6 +931,44 @@ static NTSTATUS wg_parser_stream_seek(void *args) - return S_OK; - } - -+static NTSTATUS wg_parser_stream_drain(void *args) -+{ -+ struct wg_parser_stream *stream = args; -+ struct wg_parser *parser = stream->parser; -+ bool ret; -+ -+ pthread_mutex_lock(&parser->mutex); -+ -+ /* Sanity check making sure caller didn't try to drain an already-EOS or unselected stream. -+ There's no reason for a caller to do this, but it could be an accident in which case we -+ should indicate that the stream is drained instead of locking-up. */ -+ if (!stream->enabled || stream->eos) -+ { -+ pthread_mutex_unlock(&parser->mutex); -+ return true; -+ } -+ -+ parser->draining = true; -+ pthread_cond_signal(&parser->read_done_cond); -+ -+ /* We must wait for either an event to occur or the drain to complete. -+ Since drains are blocking, we assign this responsibility to the thread -+ pulling data, as the pipeline will not need to pull more data until -+ the drain completes. If one input buffer yields more than one output -+ buffer, the chain callback blocks on the wg_parser_stream_buffer_release -+ for the first buffer, which would never be called if the drain function -+ hadn't completed. */ -+ while (!parser->flushing && parser->draining && stream->event.type == WG_PARSER_EVENT_NONE) -+ pthread_cond_wait(&stream->event_cond, &parser->mutex); -+ -+ ret = stream->event.type == WG_PARSER_EVENT_NONE; -+ parser->draining = false; -+ -+ pthread_mutex_unlock(&stream->parser->mutex); -+ -+ return ret; -+} -+ - static NTSTATUS wg_parser_stream_notify_qos(void *args) - { - const struct wg_parser_stream_notify_qos_params *params = args; -@@ -1493,6 +1541,7 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, - { - struct wg_parser *parser = gst_pad_get_element_private(pad); - GstFlowReturn ret; -+ unsigned int i; - - GST_LOG("pad %p, offset %" G_GINT64_MODIFIER "u, size %u, buffer %p.", pad, offset, size, *buffer); - -@@ -1514,6 +1563,14 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, - - pthread_mutex_lock(&parser->mutex); - -+ if (parser->draining) -+ { -+ gst_pad_peer_query(parser->my_src, gst_query_new_drain()); -+ parser->draining = false; -+ for (i = 0; i < parser->stream_count; i++) -+ pthread_cond_signal(&parser->streams[i]->event_cond); -+ } -+ - assert(!parser->read_request.size); - parser->read_request.buffer = *buffer; - parser->read_request.offset = offset; -@@ -1526,7 +1583,16 @@ static GstFlowReturn src_getrange_cb(GstPad *pad, GstObject *parent, - * read_thread() not running. */ - - while (!parser->read_request.done) -+ { - pthread_cond_wait(&parser->read_done_cond, &parser->mutex); -+ if (parser->draining) -+ { -+ gst_pad_peer_query(parser->my_src, gst_query_new_drain()); -+ parser->draining = false; -+ for (i = 0; i < parser->stream_count; i++) -+ pthread_cond_signal(&parser->streams[i]->event_cond); -+ } -+ } - - *buffer = parser->read_request.buffer; - ret = parser->read_request.ret; -@@ -2270,4 +2336,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - - X(wg_parser_stream_get_duration), - X(wg_parser_stream_seek), -+ -+ X(wg_parser_stream_drain), - }; -From d237255ff266c15ca201be71cde59957e0592b1b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 15 Dec 2021 11:26:41 +0100 -Subject: [PATCH] winegstreamer: Add an explicit result to wg_parser_push_data. - ---- - dlls/winegstreamer/gst_private.h | 2 +- - dlls/winegstreamer/main.c | 3 ++- - dlls/winegstreamer/media_source.c | 4 ++-- - dlls/winegstreamer/quartz_parser.c | 2 +- - dlls/winegstreamer/unixlib.h | 9 +++++++++ - dlls/winegstreamer/wg_parser.c | 19 ++++++++++++++++++- - dlls/winegstreamer/wm_reader.c | 8 ++++---- - 7 files changed, 37 insertions(+), 10 deletions(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index db2959c8f6b..7909ab8d8fa 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -74,7 +74,7 @@ void wg_parser_begin_flush(struct wg_parser *parser) DECLSPEC_HIDDEN; - void wg_parser_end_flush(struct wg_parser *parser); - - bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, uint32_t *size); --void wg_parser_push_data(struct wg_parser *parser, const void *data, uint32_t size); -+void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size); - - uint32_t wg_parser_get_stream_count(struct wg_parser *parser); - struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index); -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 3043ad77f3d..1ab0e2d38c1 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -118,11 +118,12 @@ bool wg_parser_get_next_read_offset(struct wg_parser *parser, uint64_t *offset, - return true; - } - --void wg_parser_push_data(struct wg_parser *parser, const void *data, uint32_t size) -+void wg_parser_push_data(struct wg_parser *parser, enum wg_read_result result, const void *data, uint32_t size) - { - struct wg_parser_push_data_params params = - { - .parser = parser, -+ .result = result, - .data = data, - .size = size, - }; -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 44d1796a5e9..777a66ee2de 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -643,7 +643,7 @@ static DWORD CALLBACK read_thread(void *arg) - * an error when reading past the file size. */ - if (!size) - { -- wg_parser_push_data(source->wg_parser, data, 0); -+ wg_parser_push_data(source->wg_parser, WG_READ_SUCCESS, data, 0); - continue; - } - -@@ -661,7 +661,7 @@ static DWORD CALLBACK read_thread(void *arg) - ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); - else if (ret_size != size) - ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size); -- wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? data : NULL, ret_size); -+ wg_parser_push_data(source->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, ret_size); - } - - free(data); -diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c -index 32393f4288d..b636db9de32 100644 ---- a/dlls/winegstreamer/quartz_parser.c -+++ b/dlls/winegstreamer/quartz_parser.c -@@ -884,7 +884,7 @@ static DWORD CALLBACK read_thread(void *arg) - if (FAILED(hr)) - ERR("Failed to read %u bytes at offset %I64u, hr %#x.\n", size, offset, hr); - -- wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? data : NULL, size); -+ wg_parser_push_data(filter->wg_parser, SUCCEEDED(hr) ? WG_READ_SUCCESS : WG_READ_FAILURE, data, size); - } - - free(data); -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index fc9d0c3c80d..f20ee5bb52f 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -125,6 +125,14 @@ enum wg_parser_event_type - WG_PARSER_EVENT_SEGMENT, - }; - -+enum wg_read_result -+{ -+ WG_READ_SUCCESS, -+ WG_READ_FAILURE, -+ WG_READ_FLUSHING, -+ WG_READ_EOS, -+}; -+ - struct wg_parser_event - { - enum wg_parser_event_type type; -@@ -177,6 +185,7 @@ struct wg_parser_get_next_read_offset_params - struct wg_parser_push_data_params - { - struct wg_parser *parser; -+ enum wg_read_result result; - const void *data; - UINT32 size; - }; -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index d21346b7f38..9268df3ef11 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -709,16 +709,33 @@ static NTSTATUS wg_parser_get_next_read_offset(void *args) - return S_OK; - } - -+static GstFlowReturn wg_read_result_to_gst(enum wg_read_result result) -+{ -+ switch (result) -+ { -+ case WG_READ_SUCCESS: return GST_FLOW_OK; -+ case WG_READ_FAILURE: return GST_FLOW_ERROR; -+ case WG_READ_FLUSHING: return GST_FLOW_FLUSHING; -+ case WG_READ_EOS: return GST_FLOW_EOS; -+ } -+ return GST_FLOW_ERROR; -+} -+ - static NTSTATUS wg_parser_push_data(void *args) - { - const struct wg_parser_push_data_params *params = args; - struct wg_parser *parser = params->parser; -+ enum wg_read_result result = params->result; - const void *data = params->data; - uint32_t size = params->size; - - pthread_mutex_lock(&parser->mutex); - -- if (data) -+ if (result != WG_READ_SUCCESS) -+ { -+ parser->read_request.ret = wg_read_result_to_gst(result); -+ } -+ else if (data) - { - if (size) - { -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index 693e9adfc19..73c8fdf4332 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -573,7 +573,7 @@ static DWORD CALLBACK read_thread(void *arg) - - if (!size) - { -- wg_parser_push_data(reader->wg_parser, data, 0); -+ wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, 0); - continue; - } - -@@ -592,7 +592,7 @@ static DWORD CALLBACK read_thread(void *arg) - || !ReadFile(file, data, size, &ret_size, NULL)) - { - ERR("Failed to read %u bytes at offset %I64u, error %lu.\n", size, offset, GetLastError()); -- wg_parser_push_data(reader->wg_parser, NULL, 0); -+ wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0); - continue; - } - } -@@ -603,14 +603,14 @@ static DWORD CALLBACK read_thread(void *arg) - if (FAILED(hr)) - { - ERR("Failed to read %u bytes at offset %I64u, hr %#lx.\n", size, offset, hr); -- wg_parser_push_data(reader->wg_parser, NULL, 0); -+ wg_parser_push_data(reader->wg_parser, WG_READ_FAILURE, NULL, 0); - continue; - } - } - - if (ret_size != size) - ERR("Unexpected short read: requested %u bytes, got %lu.\n", size, ret_size); -- wg_parser_push_data(reader->wg_parser, data, ret_size); -+ wg_parser_push_data(reader->wg_parser, WG_READ_SUCCESS, data, ret_size); - } - - free(data); -From 2f07bf359d2c19d6148f1f07f8c74c59292ec5f7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 15 Dec 2021 11:51:33 +0100 -Subject: [PATCH] winegstreamer: Unblock wg_parser_get_next_read_offset on read - errors too. - ---- - dlls/winegstreamer/wg_parser.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 9268df3ef11..9159b379d55 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -693,7 +693,7 @@ static NTSTATUS wg_parser_get_next_read_offset(void *args) - - pthread_mutex_lock(&parser->mutex); - -- while (parser->sink_connected && !parser->read_request.size) -+ while (parser->sink_connected && (!parser->read_request.size || parser->read_request.done)) - pthread_cond_wait(&parser->read_cond, &parser->mutex); - - if (!parser->sink_connected) -From 12b1fa9eff570414a589e6560041ce5e92518ba0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 15 Dec 2021 11:51:33 +0100 -Subject: [PATCH] winegstreamer: Update offset according to the size of the - buffer read. - ---- - dlls/winegstreamer/wg_parser.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 9159b379d55..cc7f11a65f1 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1704,7 +1704,7 @@ static void *push_data(void *arg) - break; - } - -- parser->next_offset += size; -+ parser->next_offset += gst_buffer_get_size(buffer); - - buffer->duration = buffer->pts = -1; - if ((ret = gst_pad_push(parser->my_src, buffer)) < 0) -From 8bef8acde401d6fd5839e97073d80b9eb81fedf5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 15 Dec 2021 13:54:05 +0100 -Subject: [PATCH] winegstreamer: Let src_getrange_cb allocate the buffer in - push_data. - -GStreamer documentation also states that gst_pad_push caller loses its -buffer reference, so whatever we were doing looks wrong here. ---- - dlls/winegstreamer/wg_parser.c | 11 ++--------- - 1 file changed, 2 insertions(+), 9 deletions(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index cc7f11a65f1..839eaac9d28 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1669,18 +1669,12 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - static void *push_data(void *arg) - { - struct wg_parser *parser = arg; -- GstBuffer *buffer; - GstSegment *segment; -+ GstBuffer *buffer; - guint max_size; - - GST_DEBUG("Starting push thread."); - -- if (!(buffer = gst_buffer_new_allocate(NULL, 16384, NULL))) -- { -- GST_ERROR("Failed to allocate memory."); -- return NULL; -- } -- - max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; - - gst_pad_push_event(parser->my_src, gst_event_new_stream_start("wg_stream")); -@@ -1698,6 +1692,7 @@ static void *push_data(void *arg) - break; - size = min(16384, max_size - parser->next_offset); - -+ buffer = NULL; - if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0) - { - GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret)); -@@ -1714,8 +1709,6 @@ static void *push_data(void *arg) - } - } - -- gst_buffer_unref(buffer); -- - gst_pad_push_event(parser->my_src, gst_event_new_eos()); - - GST_DEBUG("Stopping push thread."); -From 546f6bff053ff44588c93e3f4e03c1df5a150615 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 15 Dec 2021 10:25:48 +0100 -Subject: [PATCH] winegstreamer: Implement unseekable stream support. - ---- - dlls/winegstreamer/gst_private.h | 2 + - dlls/winegstreamer/main.c | 14 +++ - dlls/winegstreamer/unixlib.h | 9 ++ - dlls/winegstreamer/wg_parser.c | 197 ++++++++++++++++++++++++++++--- - 4 files changed, 203 insertions(+), 19 deletions(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 7909ab8d8fa..0cbc7e24a09 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -68,6 +68,8 @@ struct wg_parser *wg_parser_create(enum wg_parser_type type, bool unlimited_buff - void wg_parser_destroy(struct wg_parser *parser); - - HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); -+HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format, -+ uint32_t stream_count, const struct wg_format *out_formats); - void wg_parser_disconnect(struct wg_parser *parser); - - void wg_parser_begin_flush(struct wg_parser *parser); -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 1ab0e2d38c1..0b6d9885136 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -89,6 +89,20 @@ HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) - return __wine_unix_call(unix_handle, unix_wg_parser_connect, ¶ms); - } - -+HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format, -+ uint32_t stream_count, const struct wg_format *out_formats) -+{ -+ struct wg_parser_connect_unseekable_params params = -+ { -+ .parser = parser, -+ .in_format = in_format, -+ .stream_count = stream_count, -+ .out_formats = out_formats, -+ }; -+ -+ return __wine_unix_call(unix_handle, unix_wg_parser_connect_unseekable, ¶ms); -+} -+ - void wg_parser_disconnect(struct wg_parser *parser) - { - __wine_unix_call(unix_handle, unix_wg_parser_disconnect, parser); -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index f20ee5bb52f..e5d87716734 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -175,6 +175,14 @@ struct wg_parser_connect_params - UINT64 file_size; - }; - -+struct wg_parser_connect_unseekable_params -+{ -+ struct wg_parser *parser; -+ const struct wg_format *in_format; -+ UINT32 stream_count; -+ const struct wg_format *out_formats; -+}; -+ - struct wg_parser_get_next_read_offset_params - { - struct wg_parser *parser; -@@ -258,6 +266,7 @@ enum unix_funcs - unix_wg_parser_destroy, - - unix_wg_parser_connect, -+ unix_wg_parser_connect_unseekable, - unix_wg_parser_disconnect, - - unix_wg_parser_begin_flush, -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 839eaac9d28..7f7f9dc5624 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -61,7 +61,7 @@ struct wg_parser - init_gst_cb init_gst; - - struct wg_parser_stream **streams; -- unsigned int stream_count; -+ unsigned int stream_count, expected_stream_count; - - GstElement *container, *decodebin; - GstBus *bus; -@@ -75,7 +75,7 @@ struct wg_parser - pthread_mutex_t mutex; - - pthread_cond_t init_cond; -- bool no_more_pads, has_duration, error, pull_mode; -+ bool no_more_pads, has_duration, error, pull_mode, seekable; - - pthread_cond_t read_cond, read_done_cond; - struct -@@ -90,6 +90,7 @@ struct wg_parser - bool flushing, sink_connected, draining; - - bool unlimited_buffering; -+ struct wg_format input_format; - }; - - struct wg_parser_stream -@@ -662,6 +663,9 @@ static NTSTATUS wg_parser_begin_flush(void *args) - struct wg_parser *parser = args; - unsigned int i; - -+ if (!parser->seekable) -+ return S_OK; -+ - pthread_mutex_lock(&parser->mutex); - parser->flushing = true; - pthread_mutex_unlock(&parser->mutex); -@@ -679,6 +683,9 @@ static NTSTATUS wg_parser_end_flush(void *args) - { - struct wg_parser *parser = args; - -+ if (!parser->seekable) -+ return S_OK; -+ - pthread_mutex_lock(&parser->mutex); - parser->flushing = false; - pthread_mutex_unlock(&parser->mutex); -@@ -773,7 +780,9 @@ static NTSTATUS wg_parser_stream_get_preferred_format(void *args) - { - const struct wg_parser_stream_get_preferred_format_params *params = args; - -- *params->format = params->stream->preferred_format; -+ if (params->stream->has_caps) -+ *params->format = params->stream->preferred_format; -+ - return S_OK; - } - -@@ -783,6 +792,9 @@ static NTSTATUS wg_parser_stream_enable(void *args) - struct wg_parser_stream *stream = params->stream; - const struct wg_format *format = params->format; - -+ if (!stream->parser->seekable) -+ return S_OK; -+ - stream->current_format = *format; - stream->enabled = true; - -@@ -929,6 +941,9 @@ static NTSTATUS wg_parser_stream_seek(void *args) - DWORD stop_flags = params->stop_flags; - GstSeekFlags flags = 0; - -+ if (!params->stream->parser->seekable) -+ return E_FAIL; -+ - if (start_flags & AM_SEEKING_SeekToKeyFrame) - flags |= GST_SEEK_FLAG_KEY_UNIT; - if (start_flags & AM_SEEKING_Segment) -@@ -1308,14 +1323,27 @@ static GstElement *create_element(const char *name, const char *plugin_set) - static struct wg_parser_stream *create_stream(struct wg_parser *parser) - { - struct wg_parser_stream *stream, **new_array; -+ unsigned int i; - char pad_name[19]; - -- if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams)))) -- return NULL; -- parser->streams = new_array; -+ for (i = 0; i < parser->expected_stream_count; i++) -+ { -+ if (!parser->streams[i]->parser) -+ { -+ stream = parser->streams[i]; -+ break; -+ } -+ } - -- if (!(stream = calloc(1, sizeof(*stream)))) -- return NULL; -+ if (i == parser->expected_stream_count) -+ { -+ if (!(new_array = realloc(parser->streams, (parser->stream_count + 1) * sizeof(*parser->streams)))) -+ return NULL; -+ parser->streams = new_array; -+ -+ if (!(stream = calloc(1, sizeof(*stream)))) -+ return NULL; -+ } - - gst_segment_init(&stream->segment, GST_FORMAT_UNDEFINED); - -@@ -1637,7 +1665,7 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - gst_query_set_duration(query, GST_FORMAT_PERCENT, GST_FORMAT_PERCENT_MAX); - return TRUE; - } -- else if (format == GST_FORMAT_BYTES) -+ else if (format == GST_FORMAT_BYTES && parser->seekable) - { - gst_query_set_duration(query, GST_FORMAT_BYTES, parser->file_size); - return TRUE; -@@ -1651,15 +1679,42 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - GST_WARNING("Cannot seek using format \"%s\".", gst_format_get_name(format)); - return FALSE; - } -+ if (!parser->seekable) -+ return FALSE; - gst_query_set_seeking(query, GST_FORMAT_BYTES, 1, 0, parser->file_size); - return TRUE; - - case GST_QUERY_SCHEDULING: -- gst_query_set_scheduling(query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0); -+ gst_query_set_scheduling(query, parser->seekable ? GST_SCHEDULING_FLAG_SEEKABLE : GST_SCHEDULING_FLAG_SEQUENTIAL, 1, -1, 0); - gst_query_add_scheduling_mode(query, GST_PAD_MODE_PUSH); - gst_query_add_scheduling_mode(query, GST_PAD_MODE_PULL); - return TRUE; - -+ case GST_QUERY_CAPS: -+ { -+ GstCaps *caps, *filter, *temp; -+ -+ gst_query_parse_caps(query, &filter); -+ -+ if (parser->input_format.major_type) -+ caps = wg_format_to_caps(&parser->input_format); -+ else -+ caps = gst_caps_new_any(); -+ if (!caps) -+ return FALSE; -+ -+ if (filter) -+ { -+ temp = gst_caps_intersect(caps, filter); -+ gst_caps_unref(caps); -+ caps = temp; -+ } -+ -+ gst_query_set_caps_result(query, caps); -+ gst_caps_unref(caps); -+ return TRUE; -+ } -+ - default: - GST_WARNING("Unhandled query type %s.", GST_QUERY_TYPE_NAME(query)); - return FALSE; -@@ -1669,16 +1724,31 @@ static gboolean src_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - static void *push_data(void *arg) - { - struct wg_parser *parser = arg; -+ ULONG alloc_size = 16384; -+ GstCaps *caps = NULL; - GstSegment *segment; - GstBuffer *buffer; -+ unsigned int i; - guint max_size; - - GST_DEBUG("Starting push thread."); - -+ if (parser->input_format.major_type) -+ caps = wg_format_to_caps(&parser->input_format); -+ -+ if (parser->input_format.major_type == WG_MAJOR_TYPE_VIDEO) -+ { -+ GstVideoInfo info; -+ gst_video_info_from_caps(&info, caps); -+ alloc_size = info.size; -+ } -+ - max_size = parser->stop_offset ? parser->stop_offset : parser->file_size; - - gst_pad_push_event(parser->my_src, gst_event_new_stream_start("wg_stream")); - -+ if (caps) gst_pad_push_event(parser->my_src, gst_event_new_caps(caps)); -+ - segment = gst_segment_new(); - gst_segment_init(segment, GST_FORMAT_BYTES); - gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); -@@ -1688,13 +1758,47 @@ static void *push_data(void *arg) - ULONG size; - int ret; - -- if (parser->next_offset >= max_size) -+ if (parser->seekable && parser->next_offset >= max_size) - break; -- size = min(16384, max_size - parser->next_offset); -+ size = parser->seekable ? min(alloc_size, max_size - parser->next_offset) : alloc_size; - - buffer = NULL; -- if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer)) < 0) -+ if ((ret = src_getrange_cb(parser->my_src, NULL, parser->next_offset, size, &buffer) < 0)) - { -+ /* When we are in unseekable push mode, the pushing pad is responsible for handling flushing. */ -+ if (!parser->seekable && ret == GST_FLOW_FLUSHING) -+ { -+ gst_pad_push_event(parser->my_src, gst_event_new_seek(1.0f, -+ GST_FORMAT_BYTES, GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_NONE, 0)); -+ continue; -+ } -+ -+ if (!parser->seekable && ret == GST_FLOW_EOS) -+ { -+ gst_pad_push_event(parser->my_src, gst_event_new_eos()); -+ pthread_mutex_lock(&parser->mutex); -+ for (i = 0; i < parser->stream_count; i++) -+ { -+ if (!parser->streams[i]->enabled) -+ continue; -+ while (!parser->streams[i]->flushing && !parser->streams[i]->eos) -+ pthread_cond_wait(&parser->streams[i]->event_empty_cond, &parser->mutex); -+ parser->streams[i]->eos = false; -+ } -+ -+ if (parser->flushing) -+ { -+ pthread_mutex_unlock(&parser->mutex); -+ continue; -+ } -+ pthread_mutex_unlock(&parser->mutex); -+ -+ segment = gst_segment_new(); -+ gst_segment_init(segment, GST_FORMAT_BYTES); -+ gst_pad_push_event(parser->my_src, gst_event_new_segment(segment)); -+ continue; -+ } -+ - GST_ERROR("Failed to read data, ret %s.", gst_flow_get_name(ret)); - break; - } -@@ -1889,16 +1993,11 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) - return ret; - } - --static NTSTATUS wg_parser_connect(void *args) -+static HRESULT wg_parser_connect_inner(struct wg_parser *parser) - { - GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", - GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); -- const struct wg_parser_connect_params *params = args; -- struct wg_parser *parser = params->parser; -- unsigned int i; -- int ret; - -- parser->file_size = params->file_size; - parser->sink_connected = true; - - if (!parser->bus) -@@ -1921,6 +2020,23 @@ static NTSTATUS wg_parser_connect(void *args) - parser->next_pull_offset = 0; - parser->error = false; - -+ return S_OK; -+} -+ -+static NTSTATUS wg_parser_connect(void *args) -+{ -+ const struct wg_parser_connect_params *params = args; -+ struct wg_parser *parser = params->parser; -+ unsigned int i; -+ HRESULT hr; -+ int ret; -+ -+ parser->seekable = true; -+ parser->file_size = params->file_size; -+ -+ if ((hr = wg_parser_connect_inner(parser))) -+ return hr; -+ - if (!parser->init_gst(parser)) - goto out; - -@@ -2050,6 +2166,45 @@ static NTSTATUS wg_parser_connect(void *args) - return E_FAIL; - } - -+static NTSTATUS wg_parser_connect_unseekable(void *args) -+{ -+ const struct wg_parser_connect_unseekable_params *params = args; -+ const struct wg_format *out_formats = params->out_formats; -+ const struct wg_format *in_format = params->in_format; -+ uint32_t stream_count = params->stream_count; -+ struct wg_parser *parser = params->parser; -+ unsigned int i; -+ HRESULT hr; -+ -+ parser->seekable = false; -+ parser->flushing = false; -+ /* since typefind is not available here, we must have an input_format */ -+ parser->input_format = *in_format; -+ -+ if ((hr = wg_parser_connect_inner(parser))) -+ return hr; -+ -+ parser->stop_offset = -1; -+ -+ parser->expected_stream_count = stream_count; -+ parser->streams = calloc(stream_count, sizeof(*parser->streams)); -+ -+ for (i = 0; i < stream_count; i++) -+ { -+ parser->streams[i] = calloc(1, sizeof(*parser->streams[i])); -+ parser->streams[i]->current_format = out_formats[i]; -+ parser->streams[i]->enabled = true; -+ } -+ -+ if (!parser->init_gst(parser)) -+ return E_FAIL; -+ -+ if (parser->stream_count < parser->expected_stream_count) -+ return E_FAIL; -+ -+ return S_OK; -+} -+ - static NTSTATUS wg_parser_disconnect(void *args) - { - struct wg_parser *parser = args; -@@ -2099,6 +2254,9 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) - if (!(element = create_element("decodebin", "base"))) - return FALSE; - -+ if (parser->input_format.major_type) -+ g_object_set(G_OBJECT(element), "sink-caps", wg_format_to_caps(&parser->input_format), NULL); -+ - gst_bin_add(GST_BIN(parser->container), element); - parser->decodebin = element; - -@@ -2324,6 +2482,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - X(wg_parser_destroy), - - X(wg_parser_connect), -+ X(wg_parser_connect_unseekable), - X(wg_parser_disconnect), - - X(wg_parser_begin_flush), -From 2b19a89965ed2be000ffe5ddbaa3457c4f601c71 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 16:53:02 -0400 -Subject: [PATCH] winegstreamer: Implement ::Process(Input/Output) for decoder - transform. - ---- - dlls/winegstreamer/decode_transform.c | 542 +++++++++++++++++++++++++- - dlls/winegstreamer/wg_parser.c | 4 + - 2 files changed, 540 insertions(+), 6 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index 4967fc49012..c2b70c10f41 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -61,14 +61,47 @@ static struct decoder_desc - } - }; - -+struct pipeline_event -+{ -+ enum -+ { -+ PIPELINE_EVENT_NONE, -+ PIPELINE_EVENT_PARSER_STARTED, -+ PIPELINE_EVENT_READ_REQUEST, -+ } type; -+ union -+ { -+ struct -+ { -+ struct wg_parser_stream *stream; -+ } parser_started; -+ } u; -+}; -+ - struct mf_decoder - { - IMFTransform IMFTransform_iface; - LONG refcount; - enum decoder_type type; - IMFMediaType *input_type, *output_type; -- CRITICAL_SECTION cs; -- BOOL video; -+ CRITICAL_SECTION cs, help_cs, event_cs; -+ CONDITION_VARIABLE help_cv, event_cv; -+ BOOL flushing, draining, eos, helper_thread_shutdown, video; -+ HANDLE helper_thread, read_thread; -+ uint64_t offset_tracker; -+ struct wg_parser *wg_parser; -+ struct wg_parser_stream *wg_stream; -+ -+ struct -+ { -+ enum -+ { -+ HELP_REQ_NONE, -+ HELP_REQ_START_PARSER, -+ } type; -+ } help_request; -+ -+ struct pipeline_event event; - }; - - static struct mf_decoder *impl_mf_decoder_from_IMFTransform(IMFTransform *iface) -@@ -124,7 +157,35 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) - decoder->output_type = NULL; - } - -+ if (decoder->wg_parser) -+ { -+ /* NULL wg_parser is possible if the wg_parser creation failed. */ -+ -+ if (decoder->wg_stream) -+ wg_parser_disconnect(decoder->wg_parser); -+ -+ EnterCriticalSection(&decoder->event_cs); -+ decoder->helper_thread_shutdown = TRUE; -+ WakeAllConditionVariable(&decoder->event_cv); -+ LeaveCriticalSection(&decoder->event_cs); -+ -+ EnterCriticalSection(&decoder->help_cs); -+ WakeAllConditionVariable(&decoder->help_cv); -+ LeaveCriticalSection(&decoder->help_cs); -+ -+ if (WaitForSingleObject(decoder->helper_thread, 10000) != WAIT_OBJECT_0) -+ FIXME("Failed waiting for helper thread to terminate.\n"); -+ CloseHandle(decoder->helper_thread); -+ if (WaitForSingleObject(decoder->read_thread, 10000) != WAIT_OBJECT_0) -+ FIXME("Failed waiting for read thread to terminate.\n"); -+ CloseHandle(decoder->read_thread); -+ -+ wg_parser_destroy(decoder->wg_parser); -+ } -+ - DeleteCriticalSection(&decoder->cs); -+ DeleteCriticalSection(&decoder->help_cs); -+ DeleteCriticalSection(&decoder->event_cs); - - heap_free(decoder); - } -@@ -351,6 +412,12 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF - - EnterCriticalSection(&decoder->cs); - -+ if (decoder->wg_stream) -+ { -+ decoder->wg_stream = NULL; -+ wg_parser_disconnect(decoder->wg_parser); -+ } -+ - if (decoder->input_type) - { - IMFMediaType_Release(decoder->input_type); -@@ -389,6 +456,12 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF - - hr = S_OK; - -+ if (decoder->wg_stream) -+ { -+ decoder->wg_stream = NULL; -+ wg_parser_disconnect(decoder->wg_parser); -+ } -+ - if (!decoder->input_type) - hr = MFCreateMediaType(&decoder->input_type); - -@@ -398,6 +471,16 @@ static HRESULT WINAPI mf_decoder_SetInputType(IMFTransform *iface, DWORD id, IMF - decoder->input_type = NULL; - } - -+ if (decoder->input_type && decoder->output_type) -+ { -+ EnterCriticalSection(&decoder->help_cs); -+ while(decoder->help_request.type != HELP_REQ_NONE) -+ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE); -+ decoder->help_request.type = HELP_REQ_START_PARSER; -+ LeaveCriticalSection(&decoder->help_cs); -+ WakeAllConditionVariable(&decoder->help_cv); -+ } -+ - LeaveCriticalSection(&decoder->cs); - return hr; - } -@@ -422,6 +505,12 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM - - EnterCriticalSection(&decoder->cs); - -+ if (decoder->wg_stream) -+ { -+ decoder->wg_stream = NULL; -+ wg_parser_disconnect(decoder->wg_parser); -+ } -+ - if (decoder->output_type) - { - IMFMediaType_Release(decoder->output_type); -@@ -460,6 +549,12 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM - - hr = S_OK; - -+ if (decoder->wg_stream) -+ { -+ decoder->wg_stream = NULL; -+ wg_parser_disconnect(decoder->wg_parser); -+ } -+ - if (!decoder->output_type) - hr = MFCreateMediaType(&decoder->output_type); - -@@ -469,6 +564,16 @@ static HRESULT WINAPI mf_decoder_SetOutputType(IMFTransform *iface, DWORD id, IM - decoder->output_type = NULL; - } - -+ if (decoder->input_type && decoder->output_type) -+ { -+ EnterCriticalSection(&decoder->help_cs); -+ while(decoder->help_request.type != HELP_REQ_NONE) -+ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE); -+ decoder->help_request.type = HELP_REQ_START_PARSER; -+ LeaveCriticalSection(&decoder->help_cs); -+ WakeAllConditionVariable(&decoder->help_cv); -+ } -+ - LeaveCriticalSection(&decoder->cs); - return hr; - } -@@ -515,6 +620,117 @@ static HRESULT WINAPI mf_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMF - return E_NOTIMPL; - } - -+static DWORD CALLBACK helper_thread_func(PVOID ctx) -+{ -+ struct mf_decoder *decoder = (struct mf_decoder *)ctx; -+ -+ for(;;) -+ { -+ EnterCriticalSection(&decoder->help_cs); -+ -+ while(!decoder->helper_thread_shutdown && decoder->help_request.type == HELP_REQ_NONE) -+ SleepConditionVariableCS(&decoder->help_cv, &decoder->help_cs, INFINITE); -+ if (decoder->helper_thread_shutdown) -+ { -+ LeaveCriticalSection(&decoder->help_cs); -+ return 0; -+ } -+ -+ switch(decoder->help_request.type) -+ { -+ case HELP_REQ_START_PARSER: -+ { -+ struct wg_format input_format, output_format; -+ -+ decoder->help_request.type = HELP_REQ_NONE; -+ LeaveCriticalSection(&decoder->help_cs); -+ -+ mf_media_type_to_wg_format(decoder->input_type, &input_format); -+ mf_media_type_to_wg_format(decoder->output_type, &output_format); -+ -+ wg_parser_connect_unseekable(decoder->wg_parser, &input_format, 1, &output_format); -+ -+ EnterCriticalSection(&decoder->event_cs); -+ while (!decoder->helper_thread_shutdown && decoder->event.type != PIPELINE_EVENT_NONE) -+ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); -+ -+ if (decoder->helper_thread_shutdown) -+ { -+ LeaveCriticalSection(&decoder->event_cs); -+ return 0; -+ } -+ -+ decoder->event.type = PIPELINE_EVENT_PARSER_STARTED; -+ decoder->event.u.parser_started.stream = wg_parser_get_stream(decoder->wg_parser, 0); -+ -+ LeaveCriticalSection(&decoder->event_cs); -+ WakeAllConditionVariable(&decoder->event_cv); -+ -+ break; -+ } -+ default: -+ assert(0); -+ } -+ } -+} -+ -+/* We use a separate thread to wait for reads, as we may want to wait to WAIT_ANY -+ on a read and another event. */ -+static DWORD CALLBACK read_thread_func(PVOID ctx) -+{ -+ struct mf_decoder *decoder = (struct mf_decoder *)ctx; -+ uint64_t offset; -+ uint32_t size; -+ -+ for (;;) -+ { -+ if (decoder->helper_thread_shutdown) -+ break; -+ -+ if (!wg_parser_get_next_read_offset(decoder->wg_parser, &offset, &size)) -+ continue; -+ -+ EnterCriticalSection(&decoder->event_cs); -+ while (!decoder->helper_thread_shutdown && decoder->event.type != PIPELINE_EVENT_NONE) -+ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); -+ -+ if (decoder->helper_thread_shutdown) -+ { -+ LeaveCriticalSection(&decoder->event_cs); -+ break; -+ } -+ -+ decoder->event.type = PIPELINE_EVENT_READ_REQUEST; -+ WakeAllConditionVariable(&decoder->event_cv); -+ while (!decoder->helper_thread_shutdown && decoder->event.type == PIPELINE_EVENT_READ_REQUEST) -+ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); -+ LeaveCriticalSection(&decoder->event_cs); -+ } -+ -+ return 0; -+} -+ -+static struct pipeline_event get_pipeline_event(struct mf_decoder *decoder) -+{ -+ struct pipeline_event ret; -+ -+ EnterCriticalSection(&decoder->event_cs); -+ while(decoder->event.type == PIPELINE_EVENT_NONE) -+ SleepConditionVariableCS(&decoder->event_cv, &decoder->event_cs, INFINITE); -+ -+ ret = decoder->event; -+ -+ if (ret.type != PIPELINE_EVENT_READ_REQUEST) -+ { -+ decoder->event.type = PIPELINE_EVENT_NONE; -+ WakeAllConditionVariable(&decoder->event_cv); -+ } -+ -+ LeaveCriticalSection(&decoder->event_cs); -+ -+ return ret; -+} -+ - static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { - FIXME("%p, %u %lu.\n", iface, message, param); -@@ -524,17 +740,315 @@ static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE - - static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ struct pipeline_event pip_event; -+ IMFMediaBuffer *buffer = NULL; -+ HRESULT hr = S_OK; -+ BYTE *buffer_data; -+ DWORD buffer_size; -+ uint32_t size = 0; -+ uint64_t offset; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %p, %#x.\n", decoder, id, sample, flags); -+ -+ if (flags) -+ WARN("Unsupported flags %#x\n", flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&decoder->cs); -+ -+ if (!decoder->input_type || !decoder->output_type) -+ { -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ if (decoder->draining) -+ { -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_NOTACCEPTING; -+ } -+ -+ if (!decoder->wg_stream) -+ { -+ pip_event = get_pipeline_event(decoder); -+ -+ switch (pip_event.type) -+ { -+ case PIPELINE_EVENT_PARSER_STARTED: -+ decoder->wg_stream = pip_event.u.parser_started.stream; -+ break; -+ case PIPELINE_EVENT_READ_REQUEST: -+ break; -+ default: -+ assert(0); -+ } -+ } -+ -+ if (decoder->wg_stream && !wg_parser_stream_drain(decoder->wg_stream)) -+ { -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_NOTACCEPTING; -+ } -+ -+ /* At this point, we either have a pre-init read request, or drained pipeline */ -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size))) -+ goto done; -+ -+ pip_event = get_pipeline_event(decoder); -+ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); -+ -+ for(;;) -+ { -+ uint32_t copy_size; -+ -+ if (!wg_parser_get_next_read_offset(decoder->wg_parser, &offset, &size)) -+ continue; -+ -+ copy_size = min(size, buffer_size); -+ -+ if (offset != decoder->offset_tracker) -+ { -+ ERR("A seek is needed, MFTs don't support this!\n"); -+ wg_parser_push_data(decoder->wg_parser, WG_READ_FAILURE, NULL, 0); -+ IMFMediaBuffer_Unlock(buffer); -+ hr = E_FAIL; -+ goto done; -+ } -+ -+ wg_parser_push_data(decoder->wg_parser, WG_READ_SUCCESS, buffer_data, buffer_size); -+ -+ decoder->offset_tracker += copy_size; -+ -+ if (buffer_size <= size) -+ break; -+ -+ buffer_data += copy_size; -+ buffer_size -= copy_size; -+ -+ WARN("Input sample split into multiple read requests\n"); -+ } -+ -+ EnterCriticalSection(&decoder->event_cs); -+ decoder->event.type = PIPELINE_EVENT_NONE; -+ LeaveCriticalSection(&decoder->event_cs); -+ WakeAllConditionVariable(&decoder->event_cv); -+ -+ IMFMediaBuffer_Unlock(buffer); -+ -+ done: -+ if (buffer) -+ IMFMediaBuffer_Release(buffer); -+ LeaveCriticalSection(&decoder->cs); -+ return hr; - } - - static HRESULT WINAPI mf_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ MFT_OUTPUT_DATA_BUFFER *relevant_buffer = NULL; -+ struct wg_parser_event event; -+ struct pipeline_event pip_event; -+ IMFMediaBuffer *buffer; -+ DWORD buffer_len; -+ unsigned int i; -+ BYTE *data; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ -+ if (flags) -+ WARN("Unsupported flags %#x\n", flags); -+ -+ for (i = 0; i < count; i++) -+ { -+ MFT_OUTPUT_DATA_BUFFER *out_buffer = &samples[i]; -+ -+ if (out_buffer->dwStreamID != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (relevant_buffer) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ relevant_buffer = out_buffer; -+ } -+ -+ if (!relevant_buffer) -+ return S_OK; -+ -+ EnterCriticalSection(&decoder->cs); -+ -+ if (!decoder->input_type || !decoder->output_type) -+ { -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ if (!decoder->wg_stream) -+ { -+ pip_event = get_pipeline_event(decoder); -+ -+ switch (pip_event.type) -+ { -+ case PIPELINE_EVENT_PARSER_STARTED: -+ decoder->wg_stream = pip_event.u.parser_started.stream; -+ break; -+ case PIPELINE_EVENT_READ_REQUEST: -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ default: -+ assert(0); -+ } -+ } -+ -+ if (wg_parser_stream_drain(decoder->wg_stream)) -+ { -+ /* this would be unexpected, as we should get the EOS-event when a drain command completes. */ -+ assert (!decoder->draining); -+ -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ for (;;) -+ { -+ if (!wg_parser_stream_get_event(decoder->wg_stream, &event)) -+ { -+ LeaveCriticalSection(&decoder->cs); -+ return E_FAIL; -+ } -+ -+ if (event.type == WG_PARSER_EVENT_BUFFER) -+ break; -+ -+ if (event.type == WG_PARSER_EVENT_EOS) -+ { -+ if (!decoder->draining) -+ { -+ LeaveCriticalSection(&decoder->cs); -+ WARN("Received EOS event while not draining\n"); -+ return E_FAIL; -+ } -+ decoder->draining = FALSE; -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ assert(event.type != WG_PARSER_EVENT_NONE); -+ } -+ -+ if (relevant_buffer->pSample) -+ { -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(relevant_buffer->pSample, &buffer))) -+ { -+ ERR("Failed to get buffer from sample, hr %#x.\n", hr); -+ LeaveCriticalSection(&decoder->cs); -+ return hr; -+ } -+ } -+ else -+ { -+ if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) -+ { -+ ERR("Failed to create buffer, hr %#x.\n", hr); -+ LeaveCriticalSection(&decoder->cs); -+ return hr; -+ } -+ -+ if (FAILED(hr = MFCreateSample(&relevant_buffer->pSample))) -+ { -+ ERR("Failed to create sample, hr %#x.\n", hr); -+ LeaveCriticalSection(&decoder->cs); -+ IMFMediaBuffer_Release(buffer); -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFSample_AddBuffer(relevant_buffer->pSample, buffer))) -+ { -+ ERR("Failed to add buffer, hr %#x.\n", hr); -+ goto out; -+ } -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) -+ { -+ ERR("Failed to get buffer size, hr %#x.\n", hr); -+ goto out; -+ } -+ -+ if (buffer_len < event.u.buffer.size) -+ { -+ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", -+ buffer_len, event.u.buffer.size); -+ -+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, buffer_len))) -+ { -+ ERR("Failed to set size, hr %#x.\n", hr); -+ goto out; -+ } -+ } -+ else if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) -+ { -+ ERR("Failed to set size, hr %#x.\n", hr); -+ goto out; -+ } -+ -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL))) -+ { -+ ERR("Failed to lock buffer, hr %#x.\n", hr); -+ goto out; -+ } -+ -+ if (!wg_parser_stream_copy_buffer(decoder->wg_stream, data, 0, min(buffer_len, event.u.buffer.size))) -+ { -+ hr = E_FAIL; -+ goto out; -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_Unlock(buffer))) -+ { -+ ERR("Failed to unlock buffer, hr %#x.\n", hr); -+ goto out; -+ } -+ -+ if (FAILED(hr = IMFSample_SetSampleTime(relevant_buffer->pSample, event.u.buffer.pts))) -+ { -+ ERR("Failed to set sample time, hr %#x.\n", hr); -+ goto out; -+ } -+ -+ if (FAILED(hr = IMFSample_SetSampleDuration(relevant_buffer->pSample, event.u.buffer.duration))) -+ { -+ ERR("Failed to set sample duration, hr %#x.\n", hr); -+ goto out; -+ } -+ -+ relevant_buffer->dwStatus = 0; -+ relevant_buffer->pEvents = NULL; -+ *status = 0; -+ -+ out: -+ if (SUCCEEDED(hr)) -+ wg_parser_stream_release_buffer(decoder->wg_stream); -+ LeaveCriticalSection(&decoder->cs); -+ -+ if (FAILED(hr)) -+ { -+ IMFSample_Release(relevant_buffer->pSample); -+ relevant_buffer->pSample = NULL; -+ } -+ -+ IMFMediaBuffer_Release(buffer); -+ -+ return hr; - } - - static const IMFTransformVtbl mf_decoder_vtbl = -@@ -570,6 +1084,7 @@ static const IMFTransformVtbl mf_decoder_vtbl = - HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) - { - struct mf_decoder *object; -+ struct wg_parser *parser; - - TRACE("%s, %p %u.\n", debugstr_guid(riid), obj, type); - -@@ -583,6 +1098,21 @@ HRESULT decode_transform_create(REFIID riid, void **obj, enum decoder_type type) - object->video = decoder_descs[type].major_type == &MFMediaType_Video; - - InitializeCriticalSection(&object->cs); -+ InitializeCriticalSection(&object->help_cs); -+ InitializeCriticalSection(&object->event_cs); -+ InitializeConditionVariable(&object->help_cv); -+ InitializeConditionVariable(&object->event_cv); -+ -+ if (!(parser = wg_parser_create(WG_PARSER_DECODEBIN, TRUE))) -+ { -+ ERR("Failed to create Decoder MFT type %u: Unspecified GStreamer error\n", type); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_OUTOFMEMORY; -+ } -+ object->wg_parser = parser; -+ -+ object->helper_thread = CreateThread(NULL, 0, helper_thread_func, object, 0, NULL); -+ object->read_thread = CreateThread(NULL, 0, read_thread_func, object, 0, NULL); - - *obj = &object->IMFTransform_iface; - return S_OK; -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 7f7f9dc5624..30cd9504de6 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -2212,9 +2212,13 @@ static NTSTATUS wg_parser_disconnect(void *args) - - /* Unblock all of our streams. */ - pthread_mutex_lock(&parser->mutex); -+ parser->flushing = true; -+ parser->no_more_pads = true; -+ pthread_cond_signal(&parser->init_cond); - for (i = 0; i < parser->stream_count; ++i) - { - parser->streams[i]->flushing = true; -+ pthread_cond_signal(&parser->streams[i]->event_cond); - pthread_cond_signal(&parser->streams[i]->event_empty_cond); - } - pthread_mutex_unlock(&parser->mutex); -From cd0edf67170aac743da5da4110f5ab081aa1de35 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 19 Mar 2021 16:54:03 -0400 -Subject: [PATCH] winegstreamer: Implement ::ProcessMessage for decoder - transform. - ---- - dlls/winegstreamer/decode_transform.c | 96 ++++++++++++++++++++++++++- - 1 file changed, 94 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index c2b70c10f41..6f1363ff1f3 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -733,9 +733,101 @@ static struct pipeline_event get_pipeline_event(struct mf_decoder *decoder) - - static HRESULT WINAPI mf_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { -- FIXME("%p, %u %lu.\n", iface, message, param); -+ struct mf_decoder *decoder = impl_mf_decoder_from_IMFTransform(iface); -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %x %lu.\n", decoder, message, param); -+ -+ EnterCriticalSection(&decoder->cs); -+ if (!decoder->input_type || !decoder->output_type) -+ { -+ LeaveCriticalSection(&decoder->cs); -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ } -+ -+ hr = S_OK; -+ -+ switch (message) -+ { -+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: -+ case MFT_MESSAGE_NOTIFY_START_OF_STREAM: -+ break; -+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM: -+ { -+ if (param) -+ { -+ hr = MF_E_INVALIDSTREAMNUMBER; -+ break; -+ } -+ if (!decoder->wg_stream) -+ { -+ ERR("End-Of-Stream marked on a decoder MFT which hasn't finished initialization\n"); -+ hr = E_FAIL; -+ break; -+ } -+ -+ decoder->eos = TRUE; -+ break; -+ } -+ case MFT_MESSAGE_COMMAND_DRAIN: -+ { -+ struct pipeline_event pip_event; -+ -+ if (!decoder->wg_stream) -+ { -+ ERR("Drain requested on a decoder MFT which hasn't finished initialization\n"); -+ hr = E_FAIL; -+ break; -+ } -+ -+ pip_event = get_pipeline_event(decoder); -+ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); -+ -+ wg_parser_push_data(decoder->wg_parser, WG_READ_EOS, NULL, 0); -+ -+ EnterCriticalSection(&decoder->event_cs); -+ decoder->event.type = PIPELINE_EVENT_NONE; -+ LeaveCriticalSection(&decoder->event_cs); -+ WakeAllConditionVariable(&decoder->event_cv); -+ -+ decoder->draining = TRUE; -+ decoder->offset_tracker = 0; -+ break; -+ } -+ case MFT_MESSAGE_COMMAND_FLUSH: -+ { -+ struct pipeline_event pip_event; -+ -+ if (!decoder->wg_stream) -+ { -+ ERR("Flush requested on a decoder MFT which hasn't finished initialization\n"); -+ hr = E_FAIL; -+ break; -+ } -+ -+ pip_event = get_pipeline_event(decoder); -+ assert(pip_event.type == PIPELINE_EVENT_READ_REQUEST); -+ -+ wg_parser_push_data(decoder->wg_parser, WG_READ_FLUSHING, NULL, 0); -+ -+ EnterCriticalSection(&decoder->event_cs); -+ decoder->event.type = PIPELINE_EVENT_NONE; -+ LeaveCriticalSection(&decoder->event_cs); -+ WakeAllConditionVariable(&decoder->event_cv); -+ -+ decoder->offset_tracker = 0; -+ break; -+ } -+ default: -+ { -+ ERR("Unhandled message type %x.\n", message); -+ hr = E_FAIL; -+ break; -+ } -+ } -+ -+ LeaveCriticalSection(&decoder->cs); -+ return hr; - } - - static HRESULT WINAPI mf_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -From 0b25fed921e07fa6627bd9fd39895d7ba951d834 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 15 Dec 2021 10:59:45 +0100 -Subject: [PATCH] winegstreamer: Implement ::Process(Input/Output) for audio - conversion transform. - ---- - dlls/winegstreamer/audioconvert.c | 277 +++++++++++++++++++++++++++++- - dlls/winegstreamer/unixlib.h | 1 + - dlls/winegstreamer/wg_parser.c | 61 +++++++ - 3 files changed, 332 insertions(+), 7 deletions(-) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 46712817647..7c38eff8c79 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -35,6 +35,10 @@ struct audio_converter - IMFMediaType *input_type; - IMFMediaType *output_type; - CRITICAL_SECTION cs; -+ BOOL buffer_inflight; -+ LONGLONG buffer_pts, buffer_dur; -+ struct wg_parser *parser; -+ struct wg_parser_stream *stream; - IMFAttributes *attributes, *output_attributes; - }; - -@@ -85,6 +89,10 @@ static ULONG WINAPI audio_converter_Release(IMFTransform *iface) - IMFAttributes_Release(transform->attributes); - if (transform->output_attributes) - IMFAttributes_Release(transform->output_attributes); -+ if (transform->stream) -+ wg_parser_disconnect(transform->parser); -+ if (transform->parser) -+ wg_parser_destroy(transform->parser); - free(transform); - } - -@@ -324,6 +332,7 @@ static HRESULT WINAPI audio_converter_GetOutputAvailableType(IMFTransform *iface - static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { - GUID major_type, subtype; -+ struct wg_format format; - UINT32 unused; - HRESULT hr; - -@@ -343,6 +352,11 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id - - if (converter->input_type) - { -+ if (converter->stream) -+ { -+ wg_parser_disconnect(converter->parser); -+ converter->stream = NULL; -+ } - IMFMediaType_Release(converter->input_type); - converter->input_type = NULL; - } -@@ -369,6 +383,10 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id - if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) - return MF_E_INVALIDTYPE; - -+ mf_media_type_to_wg_format(type, &format); -+ if (!format.major_type) -+ return MF_E_INVALIDTYPE; -+ - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - -@@ -388,6 +406,21 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id - converter->input_type = NULL; - } - -+ if (converter->stream) -+ { -+ wg_parser_disconnect(converter->parser); -+ converter->stream = NULL; -+ } -+ -+ if (converter->input_type && converter->output_type) -+ { -+ struct wg_format output_format; -+ mf_media_type_to_wg_format(converter->output_type, &output_format); -+ -+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format))) -+ converter->stream = wg_parser_get_stream(converter->parser, 0); -+ } -+ - LeaveCriticalSection(&converter->cs); - - return hr; -@@ -397,6 +430,7 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - { - struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); - GUID major_type, subtype; -+ struct wg_format format; - UINT32 unused; - HRESULT hr; - -@@ -405,9 +439,6 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - if (id != 0) - return MF_E_INVALIDSTREAMNUMBER; - -- if (!converter->input_type) -- return MF_E_TRANSFORM_TYPE_NOT_SET; -- - if (!type) - { - if (flags & MFT_SET_TYPE_TEST_ONLY) -@@ -417,6 +448,11 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - - if (converter->output_type) - { -+ if (converter->stream) -+ { -+ wg_parser_disconnect(converter->parser); -+ converter->stream = NULL; -+ } - IMFMediaType_Release(converter->output_type); - converter->output_type = NULL; - } -@@ -443,6 +479,10 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - if (!IsEqualGUID(&subtype, &MFAudioFormat_PCM) && !IsEqualGUID(&subtype, &MFAudioFormat_Float)) - return MF_E_INVALIDTYPE; - -+ mf_media_type_to_wg_format(type, &format); -+ if (!format.major_type) -+ return MF_E_INVALIDTYPE; -+ - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - -@@ -462,6 +502,21 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - converter->output_type = NULL; - } - -+ if (converter->stream) -+ { -+ wg_parser_disconnect(converter->parser); -+ converter->stream = NULL; -+ } -+ -+ if (converter->input_type && converter->output_type) -+ { -+ struct wg_format input_format; -+ mf_media_type_to_wg_format(converter->input_type, &input_format); -+ -+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format))) -+ converter->stream = wg_parser_get_stream(converter->parser, 0); -+ } -+ - LeaveCriticalSection(&converter->cs); - - return hr; -@@ -574,17 +629,218 @@ static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_ME - - static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("%p, %lu, %p, %#lx.\n", iface, id, sample, flags); -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); -+ IMFMediaBuffer *buffer = NULL; -+ unsigned char *buffer_data; -+ DWORD buffer_size; -+ uint64_t offset; -+ uint32_t size; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %lu, %p, %#lx.\n", iface, id, sample, flags); -+ -+ if (flags) -+ WARN("Unsupported flags %#lx.\n", flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!converter->stream) -+ { -+ hr = MF_E_TRANSFORM_TYPE_NOT_SET; -+ goto done; -+ } -+ -+ if (converter->buffer_inflight) -+ { -+ hr = MF_E_NOTACCEPTING; -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size))) -+ goto done; -+ -+ for (;;) -+ { -+ if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) -+ continue; -+ -+ wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); -+ -+ if (buffer_size <= size) -+ break; -+ -+ buffer_data += size; -+ buffer_size -= size; -+ } -+ -+ IMFMediaBuffer_Unlock(buffer); -+ converter->buffer_inflight = TRUE; -+ if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) -+ converter->buffer_pts = -1; -+ if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur))) -+ converter->buffer_dur = -1; -+ -+done: -+ if (buffer) -+ IMFMediaBuffer_Release(buffer); -+ LeaveCriticalSection(&converter->cs); -+ return hr; - } - - static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("%p, %#lx, %lu, %p, %p.\n", iface, flags, count, samples, status); -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); -+ IMFSample *allocated_sample = NULL; -+ IMFMediaBuffer *buffer = NULL; -+ struct wg_parser_event event; -+ unsigned char *buffer_data; -+ DWORD buffer_len; -+ HRESULT hr = S_OK; - -- return E_NOTIMPL; -+ TRACE("%p, %#lx, %lu, %p, %p.\n", iface, flags, count, samples, status); -+ -+ if (flags) -+ WARN("Unsupported flags %#lx.\n", flags); -+ -+ if (!count) -+ return S_OK; -+ -+ if (count != 1) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (samples[0].dwStreamID != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!converter->stream) -+ { -+ hr = MF_E_TRANSFORM_TYPE_NOT_SET; -+ goto done; -+ } -+ -+ if (!converter->buffer_inflight) -+ { -+ hr = MF_E_TRANSFORM_NEED_MORE_INPUT; -+ goto done; -+ } -+ -+ for (;;) -+ { -+ wg_parser_stream_get_event(converter->stream, &event); -+ -+ switch (event.type) -+ { -+ case WG_PARSER_EVENT_BUFFER: -+ break; -+ -+ case WG_PARSER_EVENT_SEGMENT: -+ continue; -+ -+ default: -+ WARN("Unexpected event, %lu\n", event.type); -+ continue; -+ } -+ break; -+ } -+ -+ if (!samples[0].pSample) -+ { -+ if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) -+ { -+ ERR("Failed to create buffer, hr %#lx.\n", hr); -+ goto done; -+ } -+ -+ if (FAILED(hr = MFCreateSample(&allocated_sample))) -+ { -+ ERR("Failed to create sample, hr %#lx.\n", hr); -+ goto done; -+ } -+ -+ samples[0].pSample = allocated_sample; -+ -+ if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) -+ { -+ ERR("Failed to add buffer, hr %#lx.\n", hr); -+ goto done; -+ } -+ -+ IMFMediaBuffer_Release(buffer); -+ buffer = NULL; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) -+ { -+ ERR("Failed to get buffer from sample, hr %#lx.\n", hr); -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) -+ { -+ ERR("Failed to get buffer size, hr %#lx.\n", hr); -+ goto done; -+ } -+ -+ if (buffer_len < event.u.buffer.size) -+ { -+ WARN("Client's buffer is smaller (%lu bytes) than the output sample (%lu bytes)\n", -+ buffer_len, event.u.buffer.size); -+ -+ hr = MF_E_BUFFERTOOSMALL; -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) -+ { -+ ERR("Failed to set size, hr %#lx.\n", hr); -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) -+ { -+ ERR("Failed to lock buffer hr %#lx.\n", hr); -+ goto done; -+ } -+ -+ if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) -+ { -+ ERR("Failed to copy buffer.\n"); -+ IMFMediaBuffer_Unlock(buffer); -+ hr = E_FAIL; -+ goto done; -+ } -+ -+ IMFMediaBuffer_Unlock(buffer); -+ -+ wg_parser_stream_release_buffer(converter->stream); -+ converter->buffer_inflight = FALSE; -+ -+ if (converter->buffer_pts != -1) -+ IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts); -+ if (converter->buffer_dur != -1) -+ IMFSample_SetSampleDuration(samples[0].pSample, converter->buffer_dur); -+ -+ samples[0].dwStatus = 0; -+ samples[0].pEvents = NULL; -+ -+ done: -+ if (buffer) -+ IMFMediaBuffer_Release(buffer); -+ if (allocated_sample && FAILED(hr)) -+ { -+ IMFSample_Release(allocated_sample); -+ samples[0].pSample = NULL; -+ } -+ LeaveCriticalSection(&converter->cs); -+ return hr; - } - - static const IMFTransformVtbl audio_converter_vtbl = -@@ -645,6 +901,13 @@ HRESULT audio_converter_create(REFIID riid, void **ret) - return hr; - } - -+ if (!(object->parser = wg_parser_create(WG_PARSER_AUDIOCONV, true))) -+ { -+ ERR("Failed to create audio converter due to GStreamer error.\n"); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_OUTOFMEMORY; -+ } -+ - *ret = &object->IMFTransform_iface; - return S_OK; - } -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index e5d87716734..df5e48ef3c9 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -160,6 +160,7 @@ enum wg_parser_type - WG_PARSER_AVIDEMUX, - WG_PARSER_MPEGAUDIOPARSE, - WG_PARSER_WAVPARSE, -+ WG_PARSER_AUDIOCONV, - }; - - struct wg_parser_create_params -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 30cd9504de6..5b5873e57b3 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -2389,6 +2389,66 @@ static BOOL wave_parser_init_gst(struct wg_parser *parser) - return TRUE; - } - -+static BOOL audio_convert_init_gst(struct wg_parser *parser) -+{ -+ struct wg_parser_stream *stream; -+ GstElement *convert, *resampler; -+ int ret; -+ -+ if (parser->seekable) -+ return FALSE; -+ -+ if (parser->expected_stream_count != 1) -+ return FALSE; -+ -+ if (parser->input_format.major_type != WG_MAJOR_TYPE_AUDIO) -+ return FALSE; -+ -+ if (!(convert = create_element("audioconvert", "base"))) -+ return FALSE; -+ -+ gst_bin_add(GST_BIN(parser->container), convert); -+ -+ if (!(resampler = create_element("audioresample", "base"))) -+ return FALSE; -+ -+ gst_bin_add(GST_BIN(parser->container), resampler); -+ -+ gst_element_link(convert, resampler); -+ -+ parser->their_sink = gst_element_get_static_pad(convert, "sink"); -+ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) -+ { -+ GST_ERROR("Failed to link sink pads, error %d.\n", ret); -+ return FALSE; -+ } -+ -+ if (!(stream = create_stream(parser))) -+ return FALSE; -+ -+ stream->their_src = gst_element_get_static_pad(resampler, "src"); -+ gst_object_ref(stream->their_src); -+ if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0) -+ { -+ GST_ERROR("Failed to link source pads, error %d.\n", ret); -+ return FALSE; -+ } -+ gst_pad_set_active(stream->my_sink, 1); -+ -+ parser->no_more_pads = true; -+ -+ gst_element_set_state(parser->container, GST_STATE_PAUSED); -+ gst_pad_set_active(parser->my_src, 1); -+ ret = gst_element_get_state(parser->container, NULL, NULL, -1); -+ if (ret == GST_STATE_CHANGE_FAILURE) -+ { -+ GST_ERROR("Failed to play stream.\n"); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ - static void init_gstreamer_once(void) - { - char arg0[] = "wine"; -@@ -2435,6 +2495,7 @@ static NTSTATUS wg_parser_create(void *args) - [WG_PARSER_AVIDEMUX] = avi_parser_init_gst, - [WG_PARSER_MPEGAUDIOPARSE] = mpeg_audio_parser_init_gst, - [WG_PARSER_WAVPARSE] = wave_parser_init_gst, -+ [WG_PARSER_AUDIOCONV] = audio_convert_init_gst, - }; - - static pthread_once_t once = PTHREAD_ONCE_INIT; -From ff8ebfefc9224ca03ecd142e904847771727ee3d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 15 Dec 2021 13:30:39 +0100 -Subject: [PATCH] winegstreamer: Implement ::Process(Input/Output) for color - conversion transform. - ---- - dlls/winegstreamer/colorconvert.c | 276 +++++++++++++++++++++++++++++- - dlls/winegstreamer/unixlib.h | 1 + - dlls/winegstreamer/wg_parser.c | 54 ++++++ - 3 files changed, 326 insertions(+), 5 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index baf429d42f9..99788bf7f92 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -51,6 +51,10 @@ struct color_converter - IMFMediaType *input_type; - IMFMediaType *output_type; - CRITICAL_SECTION cs; -+ BOOL buffer_inflight; -+ LONGLONG buffer_pts, buffer_dur; -+ struct wg_parser *parser; -+ struct wg_parser_stream *stream; - }; - - static struct color_converter *impl_color_converter_from_IMFTransform(IMFTransform *iface) -@@ -98,6 +102,10 @@ static ULONG WINAPI color_converter_Release(IMFTransform *iface) - DeleteCriticalSection(&transform->cs); - if (transform->output_type) - IMFMediaType_Release(transform->output_type); -+ if (transform->stream) -+ wg_parser_disconnect(transform->parser); -+ if (transform->parser) -+ wg_parser_destroy(transform->parser); - free(transform); - } - -@@ -319,6 +327,7 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); - UINT64 input_framesize, output_framesize; - GUID major_type, subtype; -+ struct wg_format format; - unsigned int i; - HRESULT hr; - -@@ -336,6 +345,11 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - - if (converter->input_type) - { -+ if (converter->stream) -+ { -+ wg_parser_disconnect(converter->parser); -+ converter->stream = NULL; -+ } - IMFMediaType_Release(converter->input_type); - converter->input_type = NULL; - } -@@ -375,6 +389,10 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - - LeaveCriticalSection(&converter->cs); - -+ mf_media_type_to_wg_format(type, &format); -+ if (!format.major_type) -+ return MF_E_INVALIDTYPE; -+ - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - -@@ -394,6 +412,21 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - converter->input_type = NULL; - } - -+ if (converter->stream) -+ { -+ wg_parser_disconnect(converter->parser); -+ converter->stream = NULL; -+ } -+ -+ if (converter->input_type && converter->output_type) -+ { -+ struct wg_format output_format; -+ mf_media_type_to_wg_format(converter->output_type, &output_format); -+ -+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format))) -+ converter->stream = wg_parser_get_stream(converter->parser, 0); -+ } -+ - LeaveCriticalSection(&converter->cs); - - return hr; -@@ -404,6 +437,7 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); - UINT64 input_framesize, output_framesize; - GUID major_type, subtype; -+ struct wg_format format; - unsigned int i; - HRESULT hr; - -@@ -421,6 +455,11 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - - if (converter->output_type) - { -+ if (converter->stream) -+ { -+ wg_parser_disconnect(converter->parser); -+ converter->stream = NULL; -+ } - IMFMediaType_Release(converter->output_type); - converter->output_type = NULL; - } -@@ -460,6 +499,10 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - - LeaveCriticalSection(&converter->cs); - -+ mf_media_type_to_wg_format(type, &format); -+ if (!format.major_type) -+ return MF_E_INVALIDTYPE; -+ - if (flags & MFT_SET_TYPE_TEST_ONLY) - return S_OK; - -@@ -479,9 +522,24 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - converter->output_type = NULL; - } - -+ if (converter->stream) -+ { -+ wg_parser_disconnect(converter->parser); -+ converter->stream = NULL; -+ } -+ -+ if (converter->input_type && converter->output_type) -+ { -+ struct wg_format input_format; -+ mf_media_type_to_wg_format(converter->input_type, &input_format); -+ -+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format))) -+ converter->stream = wg_parser_get_stream(converter->parser, 0); -+ } -+ - LeaveCriticalSection(&converter->cs); - -- return S_OK; -+ return hr; - } - - static HRESULT WINAPI color_converter_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -@@ -567,17 +625,218 @@ static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_ME - - static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ IMFMediaBuffer *buffer = NULL; -+ unsigned char *buffer_data; -+ DWORD buffer_size; -+ uint64_t offset; -+ uint32_t size; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("%p, %u, %p, %#x.\n", iface, id, sample, flags); -+ -+ if (flags) -+ WARN("Unsupported flags %#x.\n", flags); -+ -+ if (id != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!converter->stream) -+ { -+ hr = MF_E_TRANSFORM_TYPE_NOT_SET; -+ goto done; -+ } -+ -+ if (converter->buffer_inflight) -+ { -+ hr = MF_E_NOTACCEPTING; -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size))) -+ goto done; -+ -+ for (;;) -+ { -+ if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) -+ continue; -+ -+ wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); -+ -+ if (buffer_size <= size) -+ break; -+ -+ buffer_data += size; -+ buffer_size -= size; -+ } -+ -+ IMFMediaBuffer_Unlock(buffer); -+ converter->buffer_inflight = TRUE; -+ if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) -+ converter->buffer_pts = -1; -+ if (FAILED(IMFSample_GetSampleDuration(sample, &converter->buffer_dur))) -+ converter->buffer_dur = -1; -+ -+done: -+ if (buffer) -+ IMFMediaBuffer_Release(buffer); -+ LeaveCriticalSection(&converter->cs); -+ return hr; - } - - static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ IMFSample *allocated_sample = NULL; -+ IMFMediaBuffer *buffer = NULL; -+ struct wg_parser_event event; -+ unsigned char *buffer_data; -+ DWORD buffer_len; -+ HRESULT hr = S_OK; - -- return E_NOTIMPL; -+ TRACE("%p, %#x, %u, %p, %p.\n", iface, flags, count, samples, status); -+ -+ if (flags) -+ WARN("Unsupported flags %#x.\n", flags); -+ -+ if (!count) -+ return S_OK; -+ -+ if (count != 1) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ if (samples[0].dwStreamID != 0) -+ return MF_E_INVALIDSTREAMNUMBER; -+ -+ EnterCriticalSection(&converter->cs); -+ -+ if (!converter->stream) -+ { -+ hr = MF_E_TRANSFORM_TYPE_NOT_SET; -+ goto done; -+ } -+ -+ if (!converter->buffer_inflight) -+ { -+ hr = MF_E_TRANSFORM_NEED_MORE_INPUT; -+ goto done; -+ } -+ -+ for (;;) -+ { -+ wg_parser_stream_get_event(converter->stream, &event); -+ -+ switch (event.type) -+ { -+ case WG_PARSER_EVENT_BUFFER: -+ break; -+ -+ case WG_PARSER_EVENT_SEGMENT: -+ continue; -+ -+ default: -+ WARN("Unexpected event, %u\n", event.type); -+ continue; -+ } -+ break; -+ } -+ -+ if (!samples[0].pSample) -+ { -+ if (FAILED(hr = MFCreateMemoryBuffer(event.u.buffer.size, &buffer))) -+ { -+ ERR("Failed to create buffer, hr %#x.\n", hr); -+ goto done; -+ } -+ -+ if (FAILED(hr = MFCreateSample(&allocated_sample))) -+ { -+ ERR("Failed to create sample, hr %#x.\n", hr); -+ goto done; -+ } -+ -+ samples[0].pSample = allocated_sample; -+ -+ if (FAILED(hr = IMFSample_AddBuffer(samples[0].pSample, buffer))) -+ { -+ ERR("Failed to add buffer, hr %#x.\n", hr); -+ goto done; -+ } -+ -+ IMFMediaBuffer_Release(buffer); -+ buffer = NULL; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &buffer))) -+ { -+ ERR("Failed to get buffer from sample, hr %#x.\n", hr); -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_GetMaxLength(buffer, &buffer_len))) -+ { -+ ERR("Failed to get buffer size, hr %#x.\n", hr); -+ goto done; -+ } -+ -+ if (buffer_len < event.u.buffer.size) -+ { -+ WARN("Client's buffer is smaller (%u bytes) than the output sample (%u bytes)\n", -+ buffer_len, event.u.buffer.size); -+ -+ hr = MF_E_BUFFERTOOSMALL; -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_SetCurrentLength(buffer, event.u.buffer.size))) -+ { -+ ERR("Failed to set size, hr %#x.\n", hr); -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, NULL))) -+ { -+ ERR("Failed to lock buffer hr %#x.\n", hr); -+ goto done; -+ } -+ -+ if (!wg_parser_stream_copy_buffer(converter->stream, buffer_data, 0, event.u.buffer.size)) -+ { -+ ERR("Failed to copy buffer.\n"); -+ IMFMediaBuffer_Unlock(buffer); -+ hr = E_FAIL; -+ goto done; -+ } -+ -+ IMFMediaBuffer_Unlock(buffer); -+ -+ wg_parser_stream_release_buffer(converter->stream); -+ converter->buffer_inflight = FALSE; -+ -+ if (converter->buffer_pts != -1) -+ IMFSample_SetSampleTime(samples[0].pSample, converter->buffer_pts); -+ if (converter->buffer_dur != -1) -+ IMFSample_SetSampleDuration(samples[0].pSample, converter->buffer_dur); -+ -+ samples[0].dwStatus = 0; -+ samples[0].pEvents = NULL; -+ -+ done: -+ if (buffer) -+ IMFMediaBuffer_Release(buffer); -+ if (FAILED(hr) && allocated_sample) -+ { -+ IMFSample_Release(allocated_sample); -+ samples[0].pSample = NULL; -+ } -+ LeaveCriticalSection(&converter->cs); -+ return hr; - } - - static const IMFTransformVtbl color_converter_vtbl = -@@ -625,6 +884,13 @@ HRESULT color_converter_create(REFIID riid, void **ret) - InitializeCriticalSection(&object->cs); - object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": color_converter_lock"); - -+ if (!(object->parser = wg_parser_create(WG_PARSER_VIDEOCONV, true))) -+ { -+ ERR("Failed to create video converter due to GStreamer error.\n"); -+ IMFTransform_Release(&object->IMFTransform_iface); -+ return E_OUTOFMEMORY; -+ } -+ - *ret = &object->IMFTransform_iface; - return S_OK; - } -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index df5e48ef3c9..17b5c606014 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -161,6 +161,7 @@ enum wg_parser_type - WG_PARSER_MPEGAUDIOPARSE, - WG_PARSER_WAVPARSE, - WG_PARSER_AUDIOCONV, -+ WG_PARSER_VIDEOCONV, - }; - - struct wg_parser_create_params -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 5b5873e57b3..94327bb2870 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -2449,6 +2449,59 @@ static BOOL audio_convert_init_gst(struct wg_parser *parser) - return TRUE; - } - -+static BOOL video_convert_init_gst(struct wg_parser *parser) -+{ -+ struct wg_parser_stream *stream; -+ GstElement *convert; -+ int ret; -+ -+ if (parser->seekable) -+ return FALSE; -+ -+ if (parser->expected_stream_count != 1) -+ return FALSE; -+ -+ if (parser->input_format.major_type != WG_MAJOR_TYPE_VIDEO) -+ return FALSE; -+ -+ if (!(convert = create_element("videoconvert", "base"))) -+ return FALSE; -+ -+ gst_bin_add(GST_BIN(parser->container), convert); -+ -+ parser->their_sink = gst_element_get_static_pad(convert, "sink"); -+ if ((ret = gst_pad_link(parser->my_src, parser->their_sink)) < 0) -+ { -+ GST_ERROR("Failed to link sink pads, error %d.\n", ret); -+ return FALSE; -+ } -+ -+ if (!(stream = create_stream(parser))) -+ return FALSE; -+ -+ stream->their_src = gst_element_get_static_pad(convert, "src"); -+ gst_object_ref(stream->their_src); -+ if ((ret = gst_pad_link(stream->their_src, stream->my_sink)) < 0) -+ { -+ GST_ERROR("Failed to link source pads, error %d.\n", ret); -+ return FALSE; -+ } -+ gst_pad_set_active(stream->my_sink, 1); -+ -+ parser->no_more_pads = true; -+ -+ gst_element_set_state(parser->container, GST_STATE_PAUSED); -+ gst_pad_set_active(parser->my_src, 1); -+ ret = gst_element_get_state(parser->container, NULL, NULL, -1); -+ if (ret == GST_STATE_CHANGE_FAILURE) -+ { -+ GST_ERROR("Failed to play stream.\n"); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ - static void init_gstreamer_once(void) - { - char arg0[] = "wine"; -@@ -2496,6 +2549,7 @@ static NTSTATUS wg_parser_create(void *args) - [WG_PARSER_MPEGAUDIOPARSE] = mpeg_audio_parser_init_gst, - [WG_PARSER_WAVPARSE] = wave_parser_init_gst, - [WG_PARSER_AUDIOCONV] = audio_convert_init_gst, -+ [WG_PARSER_VIDEOCONV] = video_convert_init_gst, - }; - - static pthread_once_t once = PTHREAD_ONCE_INIT; -From 9aa63940259baea543e0d66026765f2cc55aa150 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 18 Mar 2021 15:25:17 -0400 -Subject: [PATCH] winegstreamer: Implement MF_SD_LANGUAGE. - ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/main.c | 12 ++++++++++++ - dlls/winegstreamer/media_source.c | 20 +++++++++++++++++++- - dlls/winegstreamer/unixlib.h | 8 ++++++++ - dlls/winegstreamer/wg_parser.c | 30 ++++++++++++++++++++++++++++++ - 5 files changed, 70 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 0cbc7e24a09..dc2cbfff80d 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -94,6 +94,7 @@ void wg_parser_stream_notify_qos(struct wg_parser_stream *stream, - - /* Returns the duration in 100-nanosecond units. */ - uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream); -+bool wg_parser_stream_get_language(struct wg_parser_stream *stream, char *buffer, uint32_t size); - /* start_pos and stop_pos are in 100-nanosecond units. */ - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags); -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 0b6d9885136..6e8c5f76796 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -251,6 +251,18 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) - return params.duration; - } - -+bool wg_parser_stream_get_language(struct wg_parser_stream *stream, char *buffer, uint32_t size) -+{ -+ struct wg_parser_stream_get_language_params params = -+ { -+ .stream = stream, -+ .buffer = buffer, -+ .size = size, -+ }; -+ -+ return !__wine_unix_call(unix_handle, unix_wg_parser_stream_get_language, ¶ms); -+} -+ - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) - { -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 777a66ee2de..ba705bd9834 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -1483,7 +1483,25 @@ static HRESULT media_source_constructor(IMFByteStream *bytestream, struct media_ - descriptors = malloc(object->stream_count * sizeof(IMFStreamDescriptor *)); - for (i = 0; i < object->stream_count; i++) - { -- IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, &descriptors[object->stream_count - 1 - i]); -+ IMFStreamDescriptor **descriptor = &descriptors[object->stream_count - 1 - i]; -+ char language[128]; -+ DWORD language_len; -+ WCHAR *languageW; -+ -+ IMFMediaStream_GetStreamDescriptor(&object->streams[i]->IMFMediaStream_iface, descriptor); -+ -+ if (wg_parser_stream_get_language(object->streams[i]->wg_stream, language, sizeof(language))) -+ { -+ if ((language_len = MultiByteToWideChar(CP_UTF8, 0, language, -1, NULL, 0))) -+ { -+ languageW = malloc(language_len * sizeof(WCHAR)); -+ if (MultiByteToWideChar(CP_UTF8, 0, language, -1, languageW, language_len)) -+ { -+ IMFStreamDescriptor_SetString(*descriptor, &MF_SD_LANGUAGE, languageW); -+ } -+ free(languageW); -+ } -+ } - } - - if (FAILED(hr = MFCreatePresentationDescriptor(object->stream_count, descriptors, &object->pres_desc))) -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 17b5c606014..fdcecfc96d5 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -254,6 +254,13 @@ struct wg_parser_stream_get_duration_params - UINT64 duration; - }; - -+struct wg_parser_stream_get_language_params -+{ -+ struct wg_parser_stream *stream; -+ char *buffer; -+ UINT32 size; -+}; -+ - struct wg_parser_stream_seek_params - { - struct wg_parser_stream *stream; -@@ -290,6 +297,7 @@ enum unix_funcs - unix_wg_parser_stream_notify_qos, - - unix_wg_parser_stream_get_duration, -+ unix_wg_parser_stream_get_language, - unix_wg_parser_stream_seek, - - unix_wg_parser_stream_drain, -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 94327bb2870..f87c5dade83 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -110,6 +110,7 @@ struct wg_parser_stream - bool flushing, eos, enabled, has_caps; - - uint64_t duration; -+ gchar *language_code; - }; - - static enum wg_audio_format wg_audio_format_from_gst(GstAudioFormat format) -@@ -933,6 +934,14 @@ static NTSTATUS wg_parser_stream_get_duration(void *args) - return S_OK; - } - -+static NTSTATUS wg_parser_stream_get_language(void *args) -+{ -+ struct wg_parser_stream_get_language_params *params = args; -+ if (params->stream->language_code) -+ lstrcpynA(params->buffer, params->stream->language_code, params->size); -+ return params->stream->language_code ? S_OK : E_FAIL; -+} -+ - static NTSTATUS wg_parser_stream_seek(void *args) - { - GstSeekType start_type = GST_SEEK_TYPE_SET, stop_type = GST_SEEK_TYPE_SET; -@@ -1383,6 +1392,9 @@ static void free_stream(struct wg_parser_stream *stream) - pthread_cond_destroy(&stream->event_cond); - pthread_cond_destroy(&stream->event_empty_cond); - -+ if (stream->language_code) -+ g_free(stream->language_code); -+ - free(stream); - } - -@@ -1993,6 +2005,22 @@ static gboolean src_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) - return ret; - } - -+static gchar *query_language(GstPad *pad) -+{ -+ GstTagList *tag_list; -+ GstEvent *tag_event; -+ gchar *ret = NULL; -+ -+ if ((tag_event = gst_pad_get_sticky_event(pad, GST_EVENT_TAG, 0))) -+ { -+ gst_event_parse_tag(tag_event, &tag_list); -+ gst_tag_list_get_string(tag_list, "language-code", &ret); -+ gst_event_unref(tag_event); -+ } -+ -+ return ret; -+} -+ - static HRESULT wg_parser_connect_inner(struct wg_parser *parser) - { - GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE("wine_src", -@@ -2128,6 +2156,7 @@ static NTSTATUS wg_parser_connect(void *args) - pthread_cond_wait(&parser->init_cond, &parser->mutex); - } - } -+ stream->language_code = query_language(stream->their_src); - } - - pthread_mutex_unlock(&parser->mutex); -@@ -2623,6 +2652,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - X(wg_parser_stream_notify_qos), - - X(wg_parser_stream_get_duration), -+ X(wg_parser_stream_get_language), - X(wg_parser_stream_seek), - - X(wg_parser_stream_drain), -From 3fca1522e47e9de671dffe904cceaba12b2a2b6f Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 22 Mar 2021 15:50:51 -0400 -Subject: [PATCH] winegstreamer: Implement MFT_MESSAGE_COMMAND_FLUSH for media - converters. - ---- - dlls/winegstreamer/audioconvert.c | 20 ++++++++++++++++++++ - dlls/winegstreamer/colorconvert.c | 23 +++++++++++++++++++++++ - 2 files changed, 43 insertions(+) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 7c38eff8c79..4e6dfee4e10 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -614,11 +614,31 @@ static HRESULT WINAPI audio_converter_ProcessEvent(IMFTransform *iface, DWORD id - - static HRESULT WINAPI audio_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { -+ struct audio_converter *converter = impl_audio_converter_from_IMFTransform(iface); -+ struct wg_parser_event event; -+ - TRACE("%p, %u, %Iu.\n", iface, message, param); - - switch(message) - { - case MFT_MESSAGE_COMMAND_FLUSH: -+ { -+ EnterCriticalSection(&converter->cs); -+ if (!converter->buffer_inflight) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return S_OK; -+ } -+ -+ while (event.type != WG_PARSER_EVENT_BUFFER) -+ wg_parser_stream_get_event(converter->stream, &event); -+ -+ wg_parser_stream_release_buffer(converter->stream); -+ converter->buffer_inflight = FALSE; -+ -+ LeaveCriticalSection(&converter->cs); -+ return S_OK; -+ } - case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: - return S_OK; - default: -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 99788bf7f92..6cad0c1706d 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -610,11 +610,31 @@ static HRESULT WINAPI color_converter_ProcessEvent(IMFTransform *iface, DWORD id - - static HRESULT WINAPI color_converter_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { -+ struct color_converter *converter = impl_color_converter_from_IMFTransform(iface); -+ struct wg_parser_event event; -+ - TRACE("%p, %u %lu.\n", iface, message, param); - - switch(message) - { - case MFT_MESSAGE_COMMAND_FLUSH: -+ { -+ EnterCriticalSection(&converter->cs); -+ if (!converter->buffer_inflight) -+ { -+ LeaveCriticalSection(&converter->cs); -+ return S_OK; -+ } -+ -+ while (event.type != WG_PARSER_EVENT_BUFFER) -+ wg_parser_stream_get_event(converter->stream, &event); -+ -+ wg_parser_stream_release_buffer(converter->stream); -+ converter->buffer_inflight = FALSE; -+ -+ LeaveCriticalSection(&converter->cs); -+ return S_OK; -+ } - case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: - return S_OK; - default: -@@ -664,7 +684,10 @@ static HRESULT WINAPI color_converter_ProcessInput(IMFTransform *iface, DWORD id - for (;;) - { - if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) -+ { -+ TRACE("sink unconnected\n"); - continue; -+ } - - wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); - -From f4e344edf522b75f319eb8243ae2c3dfec13893b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 15 Dec 2021 10:30:26 +0100 -Subject: [PATCH] winegstreamer: Add videobox element and aperture support. - ---- - dlls/winegstreamer/audioconvert.c | 4 +-- - dlls/winegstreamer/colorconvert.c | 4 +-- - dlls/winegstreamer/decode_transform.c | 23 ++++++++++++++- - dlls/winegstreamer/gst_private.h | 4 +-- - dlls/winegstreamer/main.c | 6 ++-- - dlls/winegstreamer/media_source.c | 2 +- - dlls/winegstreamer/quartz_parser.c | 2 +- - dlls/winegstreamer/unixlib.h | 10 +++++++ - dlls/winegstreamer/wg_parser.c | 42 +++++++++++++++++++++++++-- - dlls/winegstreamer/wm_reader.c | 6 ++-- - 10 files changed, 86 insertions(+), 17 deletions(-) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 4e6dfee4e10..50d003e4e34 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -417,7 +417,7 @@ static HRESULT WINAPI audio_converter_SetInputType(IMFTransform *iface, DWORD id - struct wg_format output_format; - mf_media_type_to_wg_format(converter->output_type, &output_format); - -- if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format))) -+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL))) - converter->stream = wg_parser_get_stream(converter->parser, 0); - } - -@@ -513,7 +513,7 @@ static HRESULT WINAPI audio_converter_SetOutputType(IMFTransform *iface, DWORD i - struct wg_format input_format; - mf_media_type_to_wg_format(converter->input_type, &input_format); - -- if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format))) -+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL))) - converter->stream = wg_parser_get_stream(converter->parser, 0); - } - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 6cad0c1706d..476851fa43a 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -423,7 +423,7 @@ static HRESULT WINAPI color_converter_SetInputType(IMFTransform *iface, DWORD id - struct wg_format output_format; - mf_media_type_to_wg_format(converter->output_type, &output_format); - -- if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format))) -+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &format, 1, &output_format, NULL))) - converter->stream = wg_parser_get_stream(converter->parser, 0); - } - -@@ -533,7 +533,7 @@ static HRESULT WINAPI color_converter_SetOutputType(IMFTransform *iface, DWORD i - struct wg_format input_format; - mf_media_type_to_wg_format(converter->input_type, &input_format); - -- if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format))) -+ if (SUCCEEDED(hr = wg_parser_connect_unseekable(converter->parser, &input_format, 1, &format, NULL))) - converter->stream = wg_parser_get_stream(converter->parser, 0); - } - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index 6f1363ff1f3..04d46a73c3d 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -641,6 +641,9 @@ static DWORD CALLBACK helper_thread_func(PVOID ctx) - case HELP_REQ_START_PARSER: - { - struct wg_format input_format, output_format; -+ struct wg_rect wg_aperture = {0}; -+ MFVideoArea *aperture = NULL; -+ UINT32 aperture_size; - - decoder->help_request.type = HELP_REQ_NONE; - LeaveCriticalSection(&decoder->help_cs); -@@ -648,7 +651,25 @@ static DWORD CALLBACK helper_thread_func(PVOID ctx) - mf_media_type_to_wg_format(decoder->input_type, &input_format); - mf_media_type_to_wg_format(decoder->output_type, &output_format); - -- wg_parser_connect_unseekable(decoder->wg_parser, &input_format, 1, &output_format); -+ if (SUCCEEDED(IMFMediaType_GetAllocatedBlob(decoder->output_type, -+ &MF_MT_MINIMUM_DISPLAY_APERTURE, (UINT8 **) &aperture, &aperture_size))) -+ { -+ TRACE("Decoded media's aperture: x: %u %u/65536, y: %u %u/65536, area: %u x %u\n", -+ aperture->OffsetX.value, aperture->OffsetX.fract, -+ aperture->OffsetY.value, aperture->OffsetY.fract, aperture->Area.cx, aperture->Area.cy); -+ -+ /* TODO: verify aperture params? */ -+ -+ wg_aperture.left = aperture->OffsetX.value; -+ wg_aperture.top = aperture->OffsetY.value; -+ wg_aperture.right = aperture->Area.cx; -+ wg_aperture.bottom = aperture->Area.cy; -+ -+ CoTaskMemFree(aperture); -+ } -+ -+ wg_parser_connect_unseekable(decoder->wg_parser, -+ &input_format, 1, &output_format, aperture ? &wg_aperture : NULL); - - EnterCriticalSection(&decoder->event_cs); - while (!decoder->helper_thread_shutdown && decoder->event.type != PIPELINE_EVENT_NONE) -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index dc2cbfff80d..c41010265af 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -69,7 +69,7 @@ void wg_parser_destroy(struct wg_parser *parser) DECLSPEC_HIDDEN; - - HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size); - HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format, -- uint32_t stream_count, const struct wg_format *out_formats); -+ uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures); - void wg_parser_disconnect(struct wg_parser *parser); - - void wg_parser_begin_flush(struct wg_parser *parser); -@@ -82,7 +82,7 @@ uint32_t wg_parser_get_stream_count(struct wg_parser *parser) DECLSPEC_HIDDEN; - struct wg_parser_stream *wg_parser_get_stream(struct wg_parser *parser, uint32_t index); - - void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, struct wg_format *format); --void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format); -+void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture); - void wg_parser_stream_disable(struct wg_parser_stream *stream); - - bool wg_parser_stream_get_event(struct wg_parser_stream *stream, struct wg_parser_event *event); -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 6e8c5f76796..93fffa13807 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -90,7 +90,7 @@ HRESULT wg_parser_connect(struct wg_parser *parser, uint64_t file_size) - } - - HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_format *in_format, -- uint32_t stream_count, const struct wg_format *out_formats) -+ uint32_t stream_count, const struct wg_format *out_formats, const struct wg_rect *apertures) - { - struct wg_parser_connect_unseekable_params params = - { -@@ -98,6 +98,7 @@ HRESULT wg_parser_connect_unseekable(struct wg_parser *parser, const struct wg_f - .in_format = in_format, - .stream_count = stream_count, - .out_formats = out_formats, -+ .apertures = apertures, - }; - - return __wine_unix_call(unix_handle, unix_wg_parser_connect_unseekable, ¶ms); -@@ -179,12 +180,13 @@ void wg_parser_stream_get_preferred_format(struct wg_parser_stream *stream, stru - __wine_unix_call(unix_handle, unix_wg_parser_stream_get_preferred_format, ¶ms); - } - --void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format) -+void wg_parser_stream_enable(struct wg_parser_stream *stream, const struct wg_format *format, const struct wg_rect *aperture) - { - struct wg_parser_stream_enable_params params = - { - .stream = stream, - .format = format, -+ .aperture = aperture, - }; - - __wine_unix_call(unix_handle, unix_wg_parser_stream_enable, ¶ms); -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index ba705bd9834..8994616bbdb 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -357,7 +357,7 @@ static void start_pipeline(struct media_source *source, struct source_async_comm - IMFMediaTypeHandler_GetCurrentMediaType(mth, ¤t_mt); - - mf_media_type_to_wg_format(current_mt, &format); -- wg_parser_stream_enable(stream->wg_stream, &format); -+ wg_parser_stream_enable(stream->wg_stream, &format, NULL); - - IMFMediaType_Release(current_mt); - IMFMediaTypeHandler_Release(mth); -diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c -index b636db9de32..eee85d884e5 100644 ---- a/dlls/winegstreamer/quartz_parser.c -+++ b/dlls/winegstreamer/quartz_parser.c -@@ -1536,7 +1536,7 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface, - - ret = amt_to_wg_format(&pin->pin.pin.mt, &format); - assert(ret); -- wg_parser_stream_enable(pin->wg_stream, &format); -+ wg_parser_stream_enable(pin->wg_stream, &format, NULL); - - /* We do need to drop any buffers that might have been sent with the old - * caps, but this will be handled in parser_init_stream(). */ -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index fdcecfc96d5..5946621fb9d 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -117,6 +117,14 @@ struct wg_format - } u; - }; - -+struct wg_rect -+{ -+ uint32_t left; -+ uint32_t right; -+ uint32_t top; -+ uint32_t bottom; -+}; -+ - enum wg_parser_event_type - { - WG_PARSER_EVENT_NONE = 0, -@@ -183,6 +191,7 @@ struct wg_parser_connect_unseekable_params - const struct wg_format *in_format; - UINT32 stream_count; - const struct wg_format *out_formats; -+ const struct wg_rect *apertures; - }; - - struct wg_parser_get_next_read_offset_params -@@ -223,6 +232,7 @@ struct wg_parser_stream_enable_params - { - struct wg_parser_stream *stream; - const struct wg_format *format; -+ const struct wg_rect *aperture; - }; - - struct wg_parser_stream_get_event_params -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index f87c5dade83..0472daf88aa 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -98,9 +98,10 @@ struct wg_parser_stream - struct wg_parser *parser; - - GstPad *their_src, *post_sink, *post_src, *my_sink; -- GstElement *flip; -+ GstElement *flip, *box; - GstSegment segment; - struct wg_format preferred_format, current_format; -+ struct wg_rect aperture; - - pthread_cond_t event_cond, event_empty_cond; - struct wg_parser_event event; -@@ -792,6 +793,7 @@ static NTSTATUS wg_parser_stream_enable(void *args) - const struct wg_parser_stream_enable_params *params = args; - struct wg_parser_stream *stream = params->stream; - const struct wg_format *format = params->format; -+ const struct wg_rect *aperture = params->aperture; - - if (!stream->parser->seekable) - return S_OK; -@@ -827,6 +829,18 @@ static NTSTATUS wg_parser_stream_enable(void *args) - } - - gst_util_set_object_arg(G_OBJECT(stream->flip), "method", flip ? "vertical-flip" : "none"); -+ -+ if (aperture) -+ { -+ if (aperture->left) -+ g_object_set(G_OBJECT(stream->box), "left", -aperture->left, NULL); -+ if (aperture->top) -+ g_object_set(G_OBJECT(stream->box), "top", -aperture->top, NULL); -+ if (aperture->right) -+ g_object_set(G_OBJECT(stream->box), "right", aperture->right - format->u.video.width, NULL); -+ if (aperture->bottom) -+ g_object_set(G_OBJECT(stream->box), "bottom", aperture->bottom - format->u.video.height, NULL); -+ } - } - - gst_pad_push_event(stream->my_sink, gst_event_new_reconfigure()); -@@ -1419,7 +1433,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - - if (!strcmp(name, "video/x-raw")) - { -- GstElement *capssetter, *deinterlace, *vconv, *flip, *vconv2; -+ GstElement *capssetter, *deinterlace, *vconv, *flip, *box, *vconv2; - - /* Hack?: Flatten down the colorimetry to default values, without - * actually modifying the video at all. -@@ -1485,11 +1499,26 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - if (!(flip = create_element("videoflip", "good"))) - goto out; - -+ if (!(box = create_element("videbox", "base"))) -+ goto out; -+ - /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert - * to do the final conversion. */ - if (!(vconv2 = create_element("videoconvert", "base"))) - goto out; - -+ if (!parser->seekable) -+ { -+ if (stream->aperture.left) -+ g_object_set(G_OBJECT(box), "left", -stream->aperture.left, NULL); -+ if (stream->aperture.bottom) -+ g_object_set(G_OBJECT(box), "top", -stream->aperture.top, NULL); -+ if (stream->aperture.right) -+ g_object_set(G_OBJECT(box), "right", stream->aperture.right - stream->current_format.u.video.width, NULL); -+ if (stream->aperture.bottom) -+ g_object_set(G_OBJECT(box), "bottom", stream->aperture.bottom - stream->current_format.u.video.height, NULL); -+ } -+ - /* The bin takes ownership of these elements. */ - gst_bin_add(GST_BIN(parser->container), capssetter); - gst_element_sync_state_with_parent(capssetter); -@@ -1499,17 +1528,21 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - gst_element_sync_state_with_parent(vconv); - gst_bin_add(GST_BIN(parser->container), flip); - gst_element_sync_state_with_parent(flip); -+ gst_bin_add(GST_BIN(parser->container), box); -+ gst_element_sync_state_with_parent(box); - gst_bin_add(GST_BIN(parser->container), vconv2); - gst_element_sync_state_with_parent(vconv2); - - gst_element_link(capssetter, deinterlace); - gst_element_link(deinterlace, vconv); - gst_element_link(vconv, flip); -- gst_element_link(flip, vconv2); -+ gst_element_link(flip, box); -+ gst_element_link(box, vconv2); - - stream->post_sink = gst_element_get_static_pad(capssetter, "sink"); - stream->post_src = gst_element_get_static_pad(vconv2, "src"); - stream->flip = flip; -+ stream->box = box; - } - else if (!strcmp(name, "audio/x-raw")) - { -@@ -2200,6 +2233,7 @@ static NTSTATUS wg_parser_connect_unseekable(void *args) - const struct wg_parser_connect_unseekable_params *params = args; - const struct wg_format *out_formats = params->out_formats; - const struct wg_format *in_format = params->in_format; -+ const struct wg_rect *apertures = params->apertures; - uint32_t stream_count = params->stream_count; - struct wg_parser *parser = params->parser; - unsigned int i; -@@ -2222,6 +2256,8 @@ static NTSTATUS wg_parser_connect_unseekable(void *args) - { - parser->streams[i] = calloc(1, sizeof(*parser->streams[i])); - parser->streams[i]->current_format = out_formats[i]; -+ if (apertures) -+ parser->streams[i]->aperture = apertures[i]; - parser->streams[i]->enabled = true; - } - -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index 73c8fdf4332..ab49045ddab 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -1509,7 +1509,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) - * video type will be BGR. */ - stream->format.u.video.format = WG_VIDEO_FORMAT_BGR; - } -- wg_parser_stream_enable(stream->wg_stream, &stream->format); -+ wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL); - } - - wg_parser_end_flush(reader->wg_parser); -@@ -1776,7 +1776,7 @@ HRESULT wm_reader_set_output_props(struct wm_reader *reader, DWORD output, - } - - stream->format = format; -- wg_parser_stream_enable(stream->wg_stream, &format); -+ wg_parser_stream_enable(stream->wg_stream, &format, NULL); - - /* Re-decode any buffers that might have been generated with the old format. - * -@@ -1989,7 +1989,7 @@ HRESULT wm_reader_set_streams_selected(struct wm_reader *reader, WORD count, - FIXME("Ignoring selection %#x for stream %u; treating as enabled.\n", - selections[i], stream_numbers[i]); - TRACE("Enabling stream %u.\n", stream_numbers[i]); -- wg_parser_stream_enable(stream->wg_stream, &stream->format); -+ wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL); - } - } - -From e8b5885acc6f2c446815e94ce8860d57651d1d36 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 18 Mar 2021 16:20:50 -0400 -Subject: [PATCH] winegstreamer: Only require videobox element for parser when - needed. - ---- - dlls/winegstreamer/wg_parser.c | 38 ++++++++++++++++++++++++++++------ - 1 file changed, 32 insertions(+), 6 deletions(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 0472daf88aa..64e763ad109 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -832,6 +832,15 @@ static NTSTATUS wg_parser_stream_enable(void *args) - - if (aperture) - { -+ if (!stream->box && (stream->aperture.left || stream->aperture.top || -+ (stream->aperture.right && stream->aperture.right != stream->current_format.u.video.width) || -+ (stream->aperture.bottom && stream->aperture.bottom != stream->current_format.u.video.height))) -+ { -+ fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"good\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ return E_FAIL; -+ } -+ - if (aperture->left) - g_object_set(G_OBJECT(stream->box), "left", -aperture->left, NULL); - if (aperture->top) -@@ -1499,8 +1508,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - if (!(flip = create_element("videoflip", "good"))) - goto out; - -- if (!(box = create_element("videbox", "base"))) -- goto out; -+ box = gst_element_factory_make("videobox", NULL); - - /* videoflip does not support 15 and 16-bit RGB so add a second videoconvert - * to do the final conversion. */ -@@ -1509,6 +1517,14 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - - if (!parser->seekable) - { -+ if (!box && (stream->aperture.left || stream->aperture.top || -+ (stream->aperture.right && stream->aperture.right != stream->current_format.u.video.width) || -+ (stream->aperture.bottom && stream->aperture.bottom != stream->current_format.u.video.height))) -+ { -+ fprintf(stderr, "winegstreamer: failed to create videobox, are %u-bit GStreamer \"good\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ goto out; -+ } - if (stream->aperture.left) - g_object_set(G_OBJECT(box), "left", -stream->aperture.left, NULL); - if (stream->aperture.bottom) -@@ -1528,16 +1544,26 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - gst_element_sync_state_with_parent(vconv); - gst_bin_add(GST_BIN(parser->container), flip); - gst_element_sync_state_with_parent(flip); -- gst_bin_add(GST_BIN(parser->container), box); -- gst_element_sync_state_with_parent(box); -+ if (box) -+ { -+ gst_bin_add(GST_BIN(parser->container), box); -+ gst_element_sync_state_with_parent(box); -+ } - gst_bin_add(GST_BIN(parser->container), vconv2); - gst_element_sync_state_with_parent(vconv2); - - gst_element_link(capssetter, deinterlace); - gst_element_link(deinterlace, vconv); - gst_element_link(vconv, flip); -- gst_element_link(flip, box); -- gst_element_link(box, vconv2); -+ if (box) -+ { -+ gst_element_link(flip, box); -+ gst_element_link(box, vconv2); -+ } -+ else -+ { -+ gst_element_link(flip, vconv2); -+ } - - stream->post_sink = gst_element_get_static_pad(capssetter, "sink"); - stream->post_src = gst_element_get_static_pad(vconv2, "src"); -From 9c1dc35ed69e4e82142338b4a1d391c8361c30ae Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 7 Jan 2022 10:04:49 -0600 -Subject: [PATCH] winegstreamer: Feed full buffer in audio converter - ProcessInput - -In push mode, we can ignore the size of the request. wg_parser will -forward the entire buffer to gst. - -CW-Bug-Id: #19859 ---- - dlls/winegstreamer/audioconvert.c | 17 ++++++----------- - 1 file changed, 6 insertions(+), 11 deletions(-) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 50d003e4e34..aa9a2984806 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -685,20 +685,15 @@ static HRESULT WINAPI audio_converter_ProcessInput(IMFTransform *iface, DWORD id - if (FAILED(hr = IMFMediaBuffer_Lock(buffer, &buffer_data, NULL, &buffer_size))) - goto done; - -- for (;;) -+ if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) - { -- if (!wg_parser_get_next_read_offset(converter->parser, &offset, &size)) -- continue; -- -- wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, min(buffer_size, size)); -- -- if (buffer_size <= size) -- break; -- -- buffer_data += size; -- buffer_size -= size; -+ hr = MF_E_UNEXPECTED; -+ IMFMediaBuffer_Unlock(buffer); -+ goto done; - } - -+ wg_parser_push_data(converter->parser, WG_READ_SUCCESS, buffer_data, buffer_size); -+ - IMFMediaBuffer_Unlock(buffer); - converter->buffer_inflight = TRUE; - if (FAILED(IMFSample_GetSampleTime(sample, &converter->buffer_pts))) -From 3b1192cfbe01f057db2acd23a5d7e622fb5c8e4d Mon Sep 17 00:00:00 2001 -From: Nikolay Sivov -Date: Wed, 12 Jan 2022 22:48:35 +0300 -Subject: [PATCH] winegstreamer: Add MFVideoFormat_ARGB32 output for the - source. - -(cherry picked from commit 9812591f0003c5c611faa59ab9b3cb73a85be637) - -CW-Bug-Id: #19975 ---- - dlls/winegstreamer/media_source.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/media_source.c b/dlls/winegstreamer/media_source.c -index 8994616bbdb..7d28fb26636 100644 ---- a/dlls/winegstreamer/media_source.c -+++ b/dlls/winegstreamer/media_source.c -@@ -872,7 +872,7 @@ static HRESULT new_media_stream(struct media_source *source, - static HRESULT media_stream_init_desc(struct media_stream *stream) - { - IMFMediaTypeHandler *type_handler = NULL; -- IMFMediaType *stream_types[6]; -+ IMFMediaType *stream_types[7]; - struct wg_format format; - DWORD type_count = 0; - unsigned int i; -@@ -891,6 +891,7 @@ static HRESULT media_stream_init_desc(struct media_stream *stream) - &MFVideoFormat_YUY2, - &MFVideoFormat_IYUV, - &MFVideoFormat_I420, -+ &MFVideoFormat_ARGB32, - }; - - IMFMediaType *base_type = mf_media_type_from_wg_format(&format); -From a1b83527438d93bd2a8e8bd15c3597cd7d79f007 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 17 Jan 2022 14:06:43 +0100 -Subject: [PATCH] winegstreamer: Return S_OK from WMA decoder ProcessMessage. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/wma_decoder.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index c939691c123..12c0de74195 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -515,7 +515,7 @@ static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFM - static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -- return E_NOTIMPL; -+ return S_OK; - } - - static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -From a7abf29970fadc9493cae9c50d25487324f5c315 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 26 Jan 2022 21:24:07 +0100 -Subject: [PATCH] winegstreamer: Introduce new wg_transform struct. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/gst_private.h | 3 ++ - dlls/winegstreamer/main.c | 14 +++++++ - dlls/winegstreamer/unix_private.h | 31 ++++++++++++++ - dlls/winegstreamer/unixlib.h | 8 ++++ - dlls/winegstreamer/wg_parser.c | 20 +++++++-- - dlls/winegstreamer/wg_transform.c | 69 +++++++++++++++++++++++++++++++ - dlls/winegstreamer/wma_decoder.c | 20 +++++++++ - 8 files changed, 162 insertions(+), 4 deletions(-) - create mode 100644 dlls/winegstreamer/unix_private.h - create mode 100644 dlls/winegstreamer/wg_transform.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index c53e914e246..52295418f0f 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -13,6 +13,7 @@ C_SRCS = \ - mfplat.c \ - quartz_parser.c \ - wg_parser.c \ -+ wg_transform.c \ - wm_asyncreader.c \ - wm_reader.c \ - wm_syncreader.c \ -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 222bce3b2c7..df82b229143 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -96,6 +96,9 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) DECLSPEC_HIDDEN; - -+struct wg_transform *wg_transform_create(void) DECLSPEC_HIDDEN; -+void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; -+ - unsigned int wg_format_get_max_size(const struct wg_format *format); - - HRESULT avi_splitter_create(IUnknown *outer, IUnknown **out) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 260dd208e2f..f23fa3abcdf 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -254,6 +254,20 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); - } - -+struct wg_transform *wg_transform_create(void) -+{ -+ struct wg_transform_create_params params = {0}; -+ -+ if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) -+ return NULL; -+ return params.transform; -+} -+ -+void wg_transform_destroy(struct wg_transform *transform) -+{ -+ __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - if (reason == DLL_PROCESS_ATTACH) -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -new file mode 100644 -index 00000000000..375d33e7728 ---- /dev/null -+++ b/dlls/winegstreamer/unix_private.h -@@ -0,0 +1,31 @@ -+/* -+ * winegstreamer Unix library interface -+ * -+ * Copyright 2020-2021 Zebediah Figura 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 -+ */ -+ -+#ifndef __WINE_WINEGSTREAMER_UNIX_PRIVATE_H -+#define __WINE_WINEGSTREAMER_UNIX_PRIVATE_H -+ -+#include "unixlib.h" -+ -+extern bool init_gstreamer(void) DECLSPEC_HIDDEN; -+ -+extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; -+extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -+ -+#endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 82bb534b938..c8b98da3a64 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -217,6 +217,11 @@ struct wg_parser_stream_seek_params - DWORD start_flags, stop_flags; - }; - -+struct wg_transform_create_params -+{ -+ struct wg_transform *transform; -+}; -+ - enum unix_funcs - { - unix_wg_parser_create, -@@ -250,6 +255,9 @@ enum unix_funcs - unix_wg_parser_stream_get_duration, - unix_wg_parser_stream_get_language, - unix_wg_parser_stream_seek, -+ -+ unix_wg_transform_create, -+ unix_wg_transform_destroy, - - unix_wg_parser_stream_drain, - }; -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 013566b25e9..ac8c5a2b95c 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -37,7 +37,7 @@ - #include "winternl.h" - #include "dshow.h" - --#include "unixlib.h" -+#include "unix_private.h" - - typedef enum - { -@@ -51,7 +51,7 @@ typedef enum - * debug logging instead of Wine debug logging. In order to be safe we forbid - * any use of Wine debug logging in this entire file. */ - --GST_DEBUG_CATEGORY_STATIC(wine); -+GST_DEBUG_CATEGORY(wine); - #define GST_CAT_DEFAULT wine - - typedef BOOL (*init_gst_cb)(struct wg_parser *parser); -@@ -1963,6 +1963,16 @@ static void init_gstreamer_once(void) - gst_version_string(), GST_VERSION_MAJOR, GST_VERSION_MINOR, GST_VERSION_MICRO); - } - -+bool init_gstreamer(void) -+{ -+ static pthread_once_t init_once = PTHREAD_ONCE_INIT; -+ -+ if (pthread_once(&init_once, init_gstreamer_once)) -+ return false; -+ -+ return true; -+} -+ - static NTSTATUS wg_parser_create(void *args) - { - static const init_gst_cb init_funcs[] = -@@ -1973,11 +1983,10 @@ static NTSTATUS wg_parser_create(void *args) - [WG_PARSER_WAVPARSE] = wave_parser_init_gst, - }; - -- static pthread_once_t once = PTHREAD_ONCE_INIT; - struct wg_parser_create_params *params = args; - struct wg_parser *parser; - -- if (pthread_once(&once, init_gstreamer_once)) -+ if (!init_gstreamer()) - return E_FAIL; - - if (!(parser = calloc(1, sizeof(*parser)))) -@@ -2053,4 +2062,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - X(wg_parser_stream_get_duration), - X(wg_parser_stream_get_language), - X(wg_parser_stream_seek), -+ -+ X(wg_transform_create), -+ X(wg_transform_destroy), - - X(wg_parser_stream_drain), - }; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -new file mode 100644 -index 00000000000..822740da0d7 ---- /dev/null -+++ b/dlls/winegstreamer/wg_transform.c -@@ -0,0 +1,69 @@ -+/* -+ * GStreamer transform backend -+ * -+ * 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 -+ */ -+ -+#if 0 -+#pragma makedep unix -+#endif -+ -+#include "config.h" -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "winternl.h" -+#include "dshow.h" -+ -+#include "unix_private.h" -+ -+GST_DEBUG_CATEGORY_EXTERN(wine); -+#define GST_CAT_DEFAULT wine -+ -+struct wg_transform -+{ -+}; -+ -+NTSTATUS wg_transform_destroy(void *args) -+{ -+ struct wg_transform *transform = args; -+ -+ free(transform); -+ return S_OK; -+} -+ -+NTSTATUS wg_transform_create(void *args) -+{ -+ struct wg_transform_create_params *params = args; -+ struct wg_transform *transform; -+ -+ if (!init_gstreamer()) -+ return E_FAIL; -+ -+ if (!(transform = calloc(1, sizeof(*transform)))) -+ return E_OUTOFMEMORY; -+ -+ GST_INFO("Created winegstreamer transform %p.", transform); -+ params->transform = transform; -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index 847387d3c22..1544e8e4c9b 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -53,6 +53,8 @@ struct wma_decoder - LONG refcount; - IMFMediaType *input_type; - IMFMediaType *output_type; -+ -+ struct wg_transform *wg_transform; - }; - - static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) -@@ -60,6 +62,19 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) - return CONTAINING_RECORD(iface, struct wma_decoder, IUnknown_inner); - } - -+static HRESULT try_create_wg_transform(struct wma_decoder *decoder) -+{ -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); -+ -+ decoder->wg_transform = wg_transform_create(); -+ if (decoder->wg_transform) -+ return S_OK; -+ -+ WARN("Failed to create wg_transform.\n"); -+ return E_FAIL; -+} -+ - static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out) - { - struct wma_decoder *decoder = impl_from_IUnknown(iface); -@@ -104,6 +119,8 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) - - if (!refcount) - { -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) -@@ -438,6 +455,9 @@ static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMF - if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) - goto failed; - -+ if (FAILED(hr = try_create_wg_transform(decoder))) -+ goto failed; -+ - return S_OK; - - failed: -From 182c97dcfd8f52da51b5e59c661b6d9ed408b5f0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:02:52 +0100 -Subject: [PATCH] winegstreamer: Introduce new wg_encoded_format struct. - -And use it for decoder transform input types. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 84 ++++++++++++++++++++++++++++++++ - dlls/winegstreamer/unixlib.h | 25 ++++++++++ - dlls/winegstreamer/wma_decoder.c | 12 +++++ - 4 files changed, 122 insertions(+) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index df82b229143..cec52e976ec 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -117,6 +117,7 @@ extern HRESULT mfplat_DllRegisterServer(void) DECLSPEC_HIDDEN; - - IMFMediaType *mf_media_type_from_wg_format(const struct wg_format *format); - void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format); -+void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format); - - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index a111bbe196d..61c7fe28a63 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -760,3 +760,87 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) - else - FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); - } -+ -+static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg_encoded_format *format, -+ UINT32 version) -+{ -+ UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; -+ BYTE codec_data[64]; -+ -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate))) -+ { -+ FIXME("Sample rate is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_NUM_CHANNELS, &channels))) -+ { -+ FIXME("Channel count is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_align))) -+ { -+ FIXME("Block alignment is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &depth))) -+ { -+ FIXME("Depth is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) -+ { -+ FIXME("Codec data is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &bytes_per_second))) -+ { -+ FIXME("Bitrate is not set.\n"); -+ bytes_per_second = 0; -+ } -+ -+ format->encoded_type = WG_ENCODED_TYPE_WMA; -+ format->u.xwma.version = version; -+ format->u.xwma.bitrate = bytes_per_second * 8; -+ format->u.xwma.rate = rate; -+ format->u.xwma.depth = depth; -+ format->u.xwma.channels = channels; -+ format->u.xwma.block_align = block_align; -+ format->u.xwma.codec_data_len = codec_data_len; -+ memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); -+} -+ -+void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format) -+{ -+ GUID major_type, subtype; -+ -+ memset(format, 0, sizeof(*format)); -+ -+ if (FAILED(IMFMediaType_GetMajorType(type, &major_type))) -+ { -+ FIXME("Major type is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ { -+ FIXME("Subtype is not set.\n"); -+ return; -+ } -+ -+ if (IsEqualGUID(&major_type, &MFMediaType_Audio)) -+ { -+ if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1)) -+ mf_media_type_to_wg_encoded_format_wma(type, format, 1); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8)) -+ mf_media_type_to_wg_encoded_format_wma(type, format, 2); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9)) -+ mf_media_type_to_wg_encoded_format_wma(type, format, 3); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) -+ mf_media_type_to_wg_encoded_format_wma(type, format, 4); -+ else -+ FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); -+ } -+ else -+ { -+ FIXME("Unimplemented major type %s.\n", debugstr_guid(&major_type)); -+ } -+} -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index c8b98da3a64..ea46de4cce1 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -91,6 +91,31 @@ struct wg_format - } u; - }; - -+struct wg_encoded_format -+{ -+ enum wg_encoded_type -+ { -+ WG_ENCODED_TYPE_UNKNOWN, -+ WG_ENCODED_TYPE_WMA, -+ WG_ENCODED_TYPE_XMA, -+ } encoded_type; -+ -+ union -+ { -+ struct -+ { -+ uint32_t version; -+ uint32_t bitrate; -+ uint32_t rate; -+ uint32_t depth; -+ uint32_t channels; -+ uint32_t block_align; -+ uint32_t codec_data_len; -+ unsigned char codec_data[64]; -+ } xwma; -+ } u; -+}; -+ - enum wg_parser_event_type - { - WG_PARSER_EVENT_NONE = 0, -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index 1544e8e4c9b..2b543426524 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -64,8 +64,20 @@ static inline struct wma_decoder *impl_from_IUnknown(IUnknown *iface) - - static HRESULT try_create_wg_transform(struct wma_decoder *decoder) - { -+ struct wg_encoded_format input_format; -+ struct wg_format output_format; -+ - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); -+ decoder->wg_transform = NULL; -+ -+ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); -+ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ mf_media_type_to_wg_format(decoder->output_type, &output_format); -+ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) -+ return MF_E_INVALIDMEDIATYPE; - - decoder->wg_transform = wg_transform_create(); - if (decoder->wg_transform) -From 4d41b5a70a95a76f1c4863f4bd1cbab7ca2cc9cb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:22:59 +0100 -Subject: [PATCH] winegstreamer: Create static pads on wg_transform struct. - -With caps created from the input / output formats. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/gst_private.h | 3 +- - dlls/winegstreamer/main.c | 9 ++- - dlls/winegstreamer/unix_private.h | 1 + - dlls/winegstreamer/unixlib.h | 2 + - dlls/winegstreamer/wg_parser.c | 2 +- - dlls/winegstreamer/wg_transform.c | 93 +++++++++++++++++++++++++++++++ - dlls/winegstreamer/wma_decoder.c | 2 +- - 7 files changed, 107 insertions(+), 5 deletions(-) - -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index cec52e976ec..5d198f57dc7 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -96,7 +96,8 @@ uint64_t wg_parser_stream_get_duration(struct wg_parser_stream *stream) DECLSPEC - void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - uint64_t start_pos, uint64_t stop_pos, DWORD start_flags, DWORD stop_flags) DECLSPEC_HIDDEN; - --struct wg_transform *wg_transform_create(void) DECLSPEC_HIDDEN; -+struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, -+ const struct wg_format *output_format) DECLSPEC_HIDDEN; - void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; - - unsigned int wg_format_get_max_size(const struct wg_format *format); -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index f23fa3abcdf..6dfa9eb5c82 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -254,9 +254,14 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - __wine_unix_call(unix_handle, unix_wg_parser_stream_seek, ¶ms); - } - --struct wg_transform *wg_transform_create(void) -+struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, -+ const struct wg_format *output_format) - { -- struct wg_transform_create_params params = {0}; -+ struct wg_transform_create_params params = -+ { -+ .input_format = input_format, -+ .output_format = output_format, -+ }; - - if (__wine_unix_call(unix_handle, unix_wg_transform_create, ¶ms)) - return NULL; -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index 375d33e7728..38349eb5e8d 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -24,6 +24,7 @@ - #include "unixlib.h" - - extern bool init_gstreamer(void) DECLSPEC_HIDDEN; -+extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; - - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index ea46de4cce1..96cda2e25aa 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -245,6 +245,8 @@ struct wg_parser_stream_seek_params - struct wg_transform_create_params - { - struct wg_transform *transform; -+ const struct wg_encoded_format *input_format; -+ const struct wg_format *output_format; - }; - - enum unix_funcs -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index ac8c5a2b95c..e7e80ecfddf 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -463,7 +463,7 @@ static GstCaps *wg_format_to_caps_video(const struct wg_format *format) - return caps; - } - --static GstCaps *wg_format_to_caps(const struct wg_format *format) -+GstCaps *wg_format_to_caps(const struct wg_format *format) - { - switch (format->major_type) - { -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 822740da0d7..146cdd87ae7 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -42,12 +42,77 @@ GST_DEBUG_CATEGORY_EXTERN(wine); - - struct wg_transform - { -+ GstPad *my_src, *my_sink; - }; - -+static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) -+{ -+ GstBuffer *buffer; -+ GstCaps *caps; -+ -+ if (format->encoded_type == WG_ENCODED_TYPE_WMA) -+ caps = gst_caps_new_empty_simple("audio/x-wma"); -+ else -+ caps = gst_caps_new_empty_simple("audio/x-xma"); -+ -+ if (format->u.xwma.version) -+ gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); -+ if (format->u.xwma.bitrate) -+ gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.xwma.bitrate, NULL); -+ if (format->u.xwma.rate) -+ gst_caps_set_simple(caps, "rate", G_TYPE_INT, format->u.xwma.rate, NULL); -+ if (format->u.xwma.depth) -+ gst_caps_set_simple(caps, "depth", G_TYPE_INT, format->u.xwma.depth, NULL); -+ if (format->u.xwma.channels) -+ gst_caps_set_simple(caps, "channels", G_TYPE_INT, format->u.xwma.channels, NULL); -+ if (format->u.xwma.block_align) -+ gst_caps_set_simple(caps, "block_align", G_TYPE_INT, format->u.xwma.block_align, NULL); -+ -+ if (format->u.xwma.codec_data_len) -+ { -+ buffer = gst_buffer_new_and_alloc(format->u.xwma.codec_data_len); -+ gst_buffer_fill(buffer, 0, format->u.xwma.codec_data, format->u.xwma.codec_data_len); -+ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); -+ gst_buffer_unref(buffer); -+ } -+ -+ return caps; -+} -+ -+static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format) -+{ -+ switch (format->encoded_type) -+ { -+ case WG_ENCODED_TYPE_UNKNOWN: -+ return NULL; -+ case WG_ENCODED_TYPE_WMA: -+ case WG_ENCODED_TYPE_XMA: -+ return wg_format_to_caps_xwma(format); -+ } -+ assert(0); -+ return NULL; -+} -+ -+static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) -+{ -+ struct wg_transform *transform = gst_pad_get_element_private(pad); -+ -+ GST_INFO("transform %p, buffer %p.", transform, buffer); -+ -+ gst_buffer_unref(buffer); -+ -+ return GST_FLOW_OK; -+} -+ - NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; - -+ if (transform->my_sink) -+ g_object_unref(transform->my_sink); -+ if (transform->my_src) -+ g_object_unref(transform->my_src); -+ - free(transform); - return S_OK; - } -@@ -55,7 +120,11 @@ NTSTATUS wg_transform_destroy(void *args) - NTSTATUS wg_transform_create(void *args) - { - struct wg_transform_create_params *params = args; -+ struct wg_encoded_format input_format = *params->input_format; -+ struct wg_format output_format = *params->output_format; -+ GstCaps *src_caps, *sink_caps; - struct wg_transform *transform; -+ GstPadTemplate *template; - - if (!init_gstreamer()) - return E_FAIL; -@@ -63,7 +132,31 @@ NTSTATUS wg_transform_create(void *args) - if (!(transform = calloc(1, sizeof(*transform)))) - return E_OUTOFMEMORY; - -+ src_caps = wg_encoded_format_to_caps(&input_format); -+ assert(src_caps); -+ sink_caps = wg_format_to_caps(&output_format); -+ assert(sink_caps); -+ -+ template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); -+ assert(template); -+ transform->my_src = gst_pad_new_from_template(template, "src"); -+ g_object_unref(template); -+ assert(transform->my_src); -+ -+ template = gst_pad_template_new("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps); -+ assert(template); -+ transform->my_sink = gst_pad_new_from_template(template, "sink"); -+ g_object_unref(template); -+ assert(transform->my_sink); -+ -+ gst_pad_set_element_private(transform->my_sink, transform); -+ gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); -+ - GST_INFO("Created winegstreamer transform %p.", transform); - params->transform = transform; -+ -+ gst_caps_unref(src_caps); -+ gst_caps_unref(sink_caps); -+ - return S_OK; - } -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index 2b543426524..db6c8a677f6 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -79,7 +79,7 @@ static HRESULT try_create_wg_transform(struct wma_decoder *decoder) - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - -- decoder->wg_transform = wg_transform_create(); -+ decoder->wg_transform = wg_transform_create(&input_format, &output_format); - if (decoder->wg_transform) - return S_OK; - -From fc86c0b5360ddc02071ea5cca2b95d2c8df8309e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:24:27 +0100 -Subject: [PATCH] winegstreamer: Lookup, create and link a decoder element. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/wg_transform.c | 140 +++++++++++++++++++++++++++++- - 1 file changed, 138 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 146cdd87ae7..a436d8316dd 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -42,7 +42,9 @@ GST_DEBUG_CATEGORY_EXTERN(wine); - - struct wg_transform - { -+ GstElement *container; - GstPad *my_src, *my_sink; -+ GstPad *their_sink, *their_src; - }; - - static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) -@@ -108,6 +110,22 @@ NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; - -+ if (transform->container) -+ gst_element_set_state(transform->container, GST_STATE_NULL); -+ -+ if (transform->their_src && transform->my_sink) -+ gst_pad_unlink(transform->their_src, transform->my_sink); -+ if (transform->their_sink && transform->my_src) -+ gst_pad_unlink(transform->my_src, transform->their_sink); -+ -+ if (transform->their_sink) -+ g_object_unref(transform->their_sink); -+ if (transform->their_src) -+ g_object_unref(transform->their_src); -+ -+ if (transform->container) -+ g_object_unref(transform->container); -+ - if (transform->my_sink) - g_object_unref(transform->my_sink); - if (transform->my_src) -@@ -117,14 +135,85 @@ NTSTATUS wg_transform_destroy(void *args) - return S_OK; - } - -+static GstElement *try_create_transform(GstCaps *src_caps, GstCaps *sink_caps) -+{ -+ GstElement *element = NULL; -+ GList *tmp, *transforms; -+ gchar *type; -+ -+ transforms = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_ANY, -+ GST_RANK_MARGINAL); -+ -+ tmp = gst_element_factory_list_filter(transforms, src_caps, GST_PAD_SINK, FALSE); -+ gst_plugin_feature_list_free(transforms); -+ transforms = tmp; -+ -+ tmp = gst_element_factory_list_filter(transforms, sink_caps, GST_PAD_SRC, FALSE); -+ gst_plugin_feature_list_free(transforms); -+ transforms = tmp; -+ -+ transforms = g_list_sort(transforms, gst_plugin_feature_rank_compare_func); -+ for (tmp = transforms; tmp != NULL && element == NULL; tmp = tmp->next) -+ { -+ type = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(tmp->data)); -+ element = gst_element_factory_create(GST_ELEMENT_FACTORY(tmp->data), NULL); -+ if (!element) -+ GST_WARNING("Failed to create %s element.", type); -+ } -+ gst_plugin_feature_list_free(transforms); -+ -+ if (element) -+ GST_INFO("Created %s element %p.", type, element); -+ else -+ { -+ gchar *src_str = gst_caps_to_string(src_caps), *sink_str = gst_caps_to_string(sink_caps); -+ GST_WARNING("Failed to create transform matching caps %s / %s.", src_str, sink_str); -+ g_free(sink_str); -+ g_free(src_str); -+ } -+ -+ return element; -+} -+ -+static bool transform_append_element(struct wg_transform *transform, GstElement *element, -+ GstElement **first, GstElement **last) -+{ -+ gchar *name = gst_element_get_name(element); -+ -+ if (!gst_bin_add(GST_BIN(transform->container), element)) -+ { -+ GST_ERROR("Failed to add %s element to bin.", name); -+ g_free(name); -+ return false; -+ } -+ -+ if (*last && !gst_element_link(*last, element)) -+ { -+ GST_ERROR("Failed to link %s element.", name); -+ g_free(name); -+ return false; -+ } -+ -+ GST_INFO("Created %s element %p.", name, element); -+ g_free(name); -+ -+ if (!*first) -+ *first = element; -+ -+ *last = element; -+ return true; -+} -+ - NTSTATUS wg_transform_create(void *args) - { - struct wg_transform_create_params *params = args; - struct wg_encoded_format input_format = *params->input_format; - struct wg_format output_format = *params->output_format; -- GstCaps *src_caps, *sink_caps; -+ GstElement *first = NULL, *last = NULL, *element; - struct wg_transform *transform; -+ GstCaps *src_caps, *sink_caps; - GstPadTemplate *template; -+ int ret; - - if (!init_gstreamer()) - return E_FAIL; -@@ -137,6 +226,24 @@ NTSTATUS wg_transform_create(void *args) - sink_caps = wg_format_to_caps(&output_format); - assert(sink_caps); - -+ transform->container = gst_bin_new("wg_transform"); -+ assert(transform->container); -+ -+ if (!(element = try_create_transform(src_caps, sink_caps)) || -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ -+ if (!(transform->their_sink = gst_element_get_static_pad(first, "sink"))) -+ { -+ GST_ERROR("Failed to find target sink pad."); -+ goto failed; -+ } -+ if (!(transform->their_src = gst_element_get_static_pad(last, "src"))) -+ { -+ GST_ERROR("Failed to find target src pad."); -+ goto failed; -+ } -+ - template = gst_pad_template_new("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps); - assert(template); - transform->my_src = gst_pad_new_from_template(template, "src"); -@@ -152,11 +259,40 @@ NTSTATUS wg_transform_create(void *args) - gst_pad_set_element_private(transform->my_sink, transform); - gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); - -+ if ((ret = gst_pad_link(transform->my_src, transform->their_sink)) < 0) -+ { -+ GST_ERROR("Failed to link sink pads, error %d.", ret); -+ goto failed; -+ } -+ if ((ret = gst_pad_link(transform->their_src, transform->my_sink)) < 0) -+ { -+ GST_ERROR("Failed to link source pads, error %d.", ret); -+ goto failed; -+ } -+ -+ if (!(ret = gst_pad_set_active(transform->my_sink, 1))) -+ GST_WARNING("Failed to activate my_sink."); -+ if (!(ret = gst_pad_set_active(transform->my_src, 1))) -+ GST_WARNING("Failed to activate my_src."); -+ -+ gst_element_set_state(transform->container, GST_STATE_PAUSED); -+ ret = gst_element_get_state(transform->container, NULL, NULL, -1); -+ if (ret == GST_STATE_CHANGE_FAILURE) -+ { -+ GST_ERROR("Failed to play stream.\n"); -+ goto failed; -+ } -+ - GST_INFO("Created winegstreamer transform %p.", transform); - params->transform = transform; - -+failed: - gst_caps_unref(src_caps); - gst_caps_unref(sink_caps); - -- return S_OK; -+ if (params->transform) -+ return S_OK; -+ -+ wg_transform_destroy(transform); -+ return E_FAIL; - } -From b2444dde8ad804accd68eec6af8e254c1ff6d866 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:25:20 +0100 -Subject: [PATCH] winegstreamer: Send stream-start and caps events on creation. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/wg_transform.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index a436d8316dd..d87b8cfa2c4 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -213,6 +213,7 @@ NTSTATUS wg_transform_create(void *args) - struct wg_transform *transform; - GstCaps *src_caps, *sink_caps; - GstPadTemplate *template; -+ GstSegment *segment; - int ret; - - if (!init_gstreamer()) -@@ -283,6 +284,30 @@ NTSTATUS wg_transform_create(void *args) - goto failed; - } - -+ if (!gst_pad_push_event(transform->my_src, gst_event_new_stream_start("stream"))) -+ { -+ GST_ERROR("Failed to send stream-start."); -+ goto failed; -+ } -+ -+ if (!gst_pad_push_event(transform->my_src, gst_event_new_caps(src_caps))) -+ { -+ GST_ERROR("Failed to set stream caps."); -+ goto failed; -+ } -+ -+ segment = gst_segment_new(); -+ gst_segment_init(segment, GST_FORMAT_TIME); -+ segment->start = 0; -+ segment->stop = -1; -+ ret = gst_pad_push_event(transform->my_src, gst_event_new_segment(segment)); -+ gst_segment_free(segment); -+ if (!ret) -+ { -+ GST_ERROR("Failed to start new segment."); -+ goto failed; -+ } -+ - GST_INFO("Created winegstreamer transform %p.", transform); - params->transform = transform; - - -From 0254d2b54694435894b7f2d305b7863727632253 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:25:58 +0100 -Subject: [PATCH] winegstreamer: Add an audioconverter and audioresampler - elements. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/unix_private.h | 1 + - dlls/winegstreamer/wg_parser.c | 2 +- - dlls/winegstreamer/wg_transform.c | 23 +++++++++++++++++++++-- - 3 files changed, 23 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index 38349eb5e8d..e6b0f3636f7 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -24,6 +24,7 @@ - #include "unixlib.h" - - extern bool init_gstreamer(void) DECLSPEC_HIDDEN; -+extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; - extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; - - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index e7e80ecfddf..c19ff2ab4ed 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1092,7 +1092,7 @@ static gboolean sink_query_cb(GstPad *pad, GstObject *parent, GstQuery *query) - } - } - --static GstElement *create_element(const char *name, const char *plugin_set) -+GstElement *create_element(const char *name, const char *plugin_set) - { - GstElement *element; - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index d87b8cfa2c4..d96923594e2 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -210,9 +210,10 @@ NTSTATUS wg_transform_create(void *args) - struct wg_encoded_format input_format = *params->input_format; - struct wg_format output_format = *params->output_format; - GstElement *first = NULL, *last = NULL, *element; -+ GstCaps *raw_caps, *src_caps, *sink_caps; - struct wg_transform *transform; -- GstCaps *src_caps, *sink_caps; - GstPadTemplate *template; -+ const gchar *media_type; - GstSegment *segment; - int ret; - -@@ -226,14 +227,31 @@ NTSTATUS wg_transform_create(void *args) - assert(src_caps); - sink_caps = wg_format_to_caps(&output_format); - assert(sink_caps); -+ media_type = gst_structure_get_name(gst_caps_get_structure(sink_caps, 0)); -+ raw_caps = gst_caps_new_empty_simple(media_type); -+ assert(raw_caps); - - transform->container = gst_bin_new("wg_transform"); - assert(transform->container); - -- if (!(element = try_create_transform(src_caps, sink_caps)) || -+ if (!(element = try_create_transform(src_caps, raw_caps)) || - !transform_append_element(transform, element, &first, &last)) - goto failed; - -+ switch (output_format.major_type) -+ { -+ case WG_MAJOR_TYPE_AUDIO: -+ if (!(element = create_element("audioconvert", "base")) || -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ if (!(element = create_element("audioresample", "base")) || -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ break; -+ default: -+ break; -+ } -+ - if (!(transform->their_sink = gst_element_get_static_pad(first, "sink"))) - { - GST_ERROR("Failed to find target sink pad."); -@@ -312,6 +330,7 @@ NTSTATUS wg_transform_create(void *args) - params->transform = transform; - - failed: -+ gst_caps_unref(raw_caps); - gst_caps_unref(src_caps); - gst_caps_unref(sink_caps); - -From 13979069d466f0ec837c5bc57e5aff0076d8757d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:28:54 +0100 -Subject: [PATCH] winegstreamer: Implement WMA decoder ProcessInput. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/mf/tests/mf.c | 6 ----- - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/main.c | 12 +++++++++ - dlls/winegstreamer/unix_private.h | 1 + - dlls/winegstreamer/unixlib.h | 9 +++++++ - dlls/winegstreamer/wg_parser.c | 2 ++ - dlls/winegstreamer/wg_transform.c | 22 ++++++++++++++++ - dlls/winegstreamer/wma_decoder.c | 43 +++++++++++++++++++++++++++++-- - 8 files changed, 88 insertions(+), 8 deletions(-) - -diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c -index b9e2a3b940f..e5d01599934 100644 ---- a/dlls/mf/tests/mf.c -+++ b/dlls/mf/tests/mf.c -@@ -5987,25 +5987,20 @@ static void test_wma_decoder(void) - - sample = create_sample(wma_encoded_data, wma_block_size / 2); - hr = IMFTransform_ProcessInput(transform, 0, sample, 0); -- todo_wine - ok(hr == S_OK, "ProcessInput returned %#x\n", hr); - ret = IMFSample_Release(sample); - ok(ret == 0, "Release returned %u\n", ret); - sample = create_sample(wma_encoded_data + wma_block_size, wma_block_size - wma_block_size / 2); - hr = IMFTransform_ProcessInput(transform, 0, sample, 0); -- todo_wine - ok(hr == S_OK, "ProcessInput returned %#x\n", hr); - ret = IMFSample_Release(sample); - ok(ret == 0, "Release returned %u\n", ret); - sample = create_sample(wma_encoded_data, wma_block_size); - hr = IMFTransform_ProcessInput(transform, 0, sample, 0); -- todo_wine - ok(hr == S_OK, "ProcessInput returned %#x\n", hr); - hr = IMFTransform_ProcessInput(transform, 0, sample, 0); -- todo_wine - ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#x\n", hr); - ret = IMFSample_Release(sample); -- todo_wine - ok(ret == 1, "Release returned %u\n", ret); - - /* As output_info.dwFlags doesn't have MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES -@@ -6028,7 +6023,6 @@ static void test_wma_decoder(void) - - sample = create_sample(wma_encoded_data, wma_block_size); - hr = IMFTransform_ProcessInput(transform, 0, sample, 0); -- todo_wine - ok(hr == MF_E_NOTACCEPTING, "ProcessInput returned %#x\n", hr); - ret = IMFSample_Release(sample); - ok(ret == 0, "Release returned %u\n", ret); -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 5d198f57dc7..0fb8aee70ba 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -99,6 +99,7 @@ void wg_parser_stream_seek(struct wg_parser_stream *stream, double rate, - struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_format, - const struct wg_format *output_format) DECLSPEC_HIDDEN; - void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; -+HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) DECLSPEC_HIDDEN; - - unsigned int wg_format_get_max_size(const struct wg_format *format); - -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index 6dfa9eb5c82..b315d0ce7c1 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -273,6 +273,18 @@ void wg_transform_destroy(struct wg_transform *transform) - __wine_unix_call(unix_handle, unix_wg_transform_destroy, transform); - } - -+HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) -+{ -+ struct wg_transform_push_data_params params = -+ { -+ .transform = transform, -+ .data = data, -+ .size = size, -+ }; -+ -+ return __wine_unix_call(unix_handle, unix_wg_transform_push_data, ¶ms); -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - if (reason == DLL_PROCESS_ATTACH) -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index e6b0f3636f7..baa7f81926c 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -29,5 +29,6 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE - - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -+extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; - - #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 96cda2e25aa..da283196ff3 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -249,6 +249,13 @@ struct wg_transform_create_params - const struct wg_format *output_format; - }; - -+struct wg_transform_push_data_params -+{ -+ struct wg_transform *transform; -+ const void *data; -+ UINT32 size; -+}; -+ - enum unix_funcs - { - unix_wg_parser_create, -@@ -287,6 +294,8 @@ enum unix_funcs - unix_wg_transform_destroy, - - unix_wg_parser_stream_drain, -+ -+ unix_wg_transform_push_data, - }; - - #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index c19ff2ab4ed..64c53c6ac98 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -2056,4 +2056,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - X(wg_transform_destroy), - - X(wg_parser_stream_drain), -+ -+ X(wg_transform_push_data), - }; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index d96923594e2..2137c4c8821 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -34,6 +34,7 @@ - - #include "winternl.h" - #include "dshow.h" -+#include "mferror.h" - - #include "unix_private.h" - -@@ -340,3 +341,24 @@ NTSTATUS wg_transform_create(void *args) - wg_transform_destroy(transform); - return E_FAIL; - } -+ -+NTSTATUS wg_transform_push_data(void *args) -+{ -+ struct wg_transform_push_data_params *params = args; -+ struct wg_transform *transform = params->transform; -+ GstBuffer *buffer; -+ GstFlowReturn ret; -+ -+ buffer = gst_buffer_new_and_alloc(params->size); -+ gst_buffer_fill(buffer, 0, params->data, params->size); -+ -+ ret = gst_pad_push(transform->my_src, buffer); -+ if (ret) -+ { -+ GST_ERROR("Failed to push buffer %d", ret); -+ return MF_E_NOTACCEPTING; -+ } -+ -+ GST_INFO("Pushed %u bytes", params->size); -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index db6c8a677f6..c9472bde019 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -54,6 +54,7 @@ struct wma_decoder - IMFMediaType *input_type; - IMFMediaType *output_type; - -+ IMFSample *input_sample; - struct wg_transform *wg_transform; - }; - -@@ -131,6 +132,8 @@ static ULONG WINAPI unknown_Release(IUnknown *iface) - - if (!refcount) - { -+ if (decoder->input_sample) -+ IMFSample_Release(decoder->input_sample); - if (decoder->wg_transform) - wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) -@@ -523,8 +526,44 @@ static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_ - - static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("iface %p, id %lu, sample %p, flags %#lx stub!\n", iface, id, sample, flags); -- return E_NOTIMPL; -+ struct wma_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaBuffer *media_buffer; -+ MFT_INPUT_STREAM_INFO info; -+ DWORD buffer_size; -+ BYTE *buffer; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %lu, sample %p, flags %#lx.\n", iface, id, sample, flags); -+ -+ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (decoder->input_sample) -+ return MF_E_NOTACCEPTING; -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_GetCurrentLength(media_buffer, &buffer_size))) -+ return hr; -+ -+ if (!(buffer_size = (buffer_size / info.cbSize) * info.cbSize)) -+ return S_OK; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, NULL))) -+ goto done; -+ -+ if (SUCCEEDED(hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size))) -+ IMFSample_AddRef((decoder->input_sample = sample)); -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; - } - - static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -From e12af1d2882e9291038dddee1928a53f443841f3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:31:44 +0100 -Subject: [PATCH] winegstreamer: Implement WMA decoder ProcessOutput. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/mf/tests/mf.c | 19 ++------ - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/main.c | 11 +++++ - dlls/winegstreamer/unix_private.h | 1 + - dlls/winegstreamer/unixlib.h | 19 ++++++++ - dlls/winegstreamer/wg_parser.c | 1 + - dlls/winegstreamer/wg_transform.c | 76 ++++++++++++++++++++++++++++++- - dlls/winegstreamer/wma_decoder.c | 59 +++++++++++++++++++++++- - 8 files changed, 169 insertions(+), 18 deletions(-) - -diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c -index e5d01599934..c4d318a9e43 100644 ---- a/dlls/mf/tests/mf.c -+++ b/dlls/mf/tests/mf.c -@@ -6009,16 +6009,13 @@ static void test_wma_decoder(void) - status = 0xdeadbeef; - memset(&output, 0, sizeof(output)); - hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); -- todo_wine - ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); - ok(output.dwStreamID == 0, "got dwStreamID %u\n", output.dwStreamID); - ok(!output.pSample, "got pSample %p\n", output.pSample); -- todo_wine - ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE || - broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) /* Win7 */, - "got dwStatus %#x\n", output.dwStatus); - ok(!output.pEvents, "got pEvents %p\n", output.pEvents); -- todo_wine - ok(status == 0, "got status %#x\n", status); - - sample = create_sample(wma_encoded_data, wma_block_size); -@@ -6030,14 +6027,11 @@ static void test_wma_decoder(void) - status = 0xdeadbeef; - memset(&output, 0, sizeof(output)); - hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); -- todo_wine - ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); - ok(!output.pSample, "got pSample %p\n", output.pSample); -- todo_wine - ok(output.dwStatus == MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE || - broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE)) /* Win7 */, - "got dwStatus %#x\n", output.dwStatus); -- todo_wine - ok(status == 0, "got status %#x\n", status); - - i = 1; -@@ -6071,7 +6065,6 @@ static void test_wma_decoder(void) - hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - } - -- todo_wine - ok(hr == S_OK, "ProcessOutput returned %#x\n", hr); - ok(output.pSample == sample, "got pSample %p\n", output.pSample); - -@@ -6084,7 +6077,8 @@ static void test_wma_decoder(void) - "got dwStatus %#x\n", output.dwStatus); - ok(status == 0, "got status %#x\n", status); - if (output.dwStatus == MFT_OUTPUT_DATA_BUFFER_INCOMPLETE || -- broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7))) -+ broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7)) || -+ !strcmp(winetest_platform, "wine")) - { - check_sample(sample, wma_decoded_data, sizeof(wma_decoded_data), NULL); - i += sizeof(wma_decoded_data); -@@ -6103,14 +6097,12 @@ static void test_wma_decoder(void) - output.pSample = sample; - hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); - } -- todo_wine -- ok(i == 0xe000, "ProcessOutput produced %#x bytes\n", i); -+ if (!strcmp(winetest_platform, "wine")) ok(i == 0x10000, "ProcessOutput produced %#x bytes\n", i); -+ else ok(i == 0xe000, "ProcessOutput produced %#x bytes\n", i); - -- todo_wine - ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); - ok(output.pSample == sample, "got pSample %p\n", output.pSample); - ok(output.dwStatus == 0, "got dwStatus %#x\n", output.dwStatus); -- todo_wine - ok(status == 0, "got status %#x\n", status); - ret = IMFSample_Release(sample); - ok(ret == 0, "Release returned %u\n", ret); -@@ -6120,13 +6112,11 @@ static void test_wma_decoder(void) - memset(&output, 0, sizeof(output)); - output.pSample = sample; - hr = IMFTransform_ProcessOutput(transform, 0, 1, &output, &status); -- todo_wine - ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "ProcessOutput returned %#x\n", hr); - ok(output.pSample == sample, "got pSample %p\n", output.pSample); - ok(output.dwStatus == 0 || - broken(output.dwStatus == (MFT_OUTPUT_DATA_BUFFER_INCOMPLETE|7)) /* Win7 */, - "got dwStatus %#x\n", output.dwStatus); -- todo_wine - ok(status == 0, "got status %#x\n", status); - check_sample(sample, NULL, 0, NULL); - ret = IMFSample_Release(sample); -@@ -6134,7 +6124,6 @@ static void test_wma_decoder(void) - - sample = create_sample(wma_encoded_data, wma_block_size); - hr = IMFTransform_ProcessInput(transform, 0, sample, 0); -- todo_wine - ok(hr == S_OK, "ProcessInput returned %#x\n", hr); - - ret = IMFTransform_Release(transform); -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 0fb8aee70ba..ead2bac4edd 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -100,6 +100,7 @@ struct wg_transform *wg_transform_create(const struct wg_encoded_format *input_f - const struct wg_format *output_format) DECLSPEC_HIDDEN; - void wg_transform_destroy(struct wg_transform *transform) DECLSPEC_HIDDEN; - HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, uint32_t size) DECLSPEC_HIDDEN; -+HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) DECLSPEC_HIDDEN; - - unsigned int wg_format_get_max_size(const struct wg_format *format); - -diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c -index b315d0ce7c1..3533fd59104 100644 ---- a/dlls/winegstreamer/main.c -+++ b/dlls/winegstreamer/main.c -@@ -285,6 +285,17 @@ HRESULT wg_transform_push_data(struct wg_transform *transform, const void *data, - return __wine_unix_call(unix_handle, unix_wg_transform_push_data, ¶ms); - } - -+HRESULT wg_transform_read_data(struct wg_transform *transform, struct wg_sample *sample) -+{ -+ struct wg_transform_read_data_params params = -+ { -+ .transform = transform, -+ .sample = sample, -+ }; -+ -+ return __wine_unix_call(unix_handle, unix_wg_transform_read_data, ¶ms); -+} -+ - BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, void *reserved) - { - if (reason == DLL_PROCESS_ATTACH) -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index baa7f81926c..1b055436ba5 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -30,5 +30,6 @@ extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDE - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_push_data(void *args) DECLSPEC_HIDDEN; -+extern NTSTATUS wg_transform_read_data(void *args) DECLSPEC_HIDDEN; - - #endif /* __WINE_WINEGSTREAMER_UNIX_PRIVATE_H */ -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index da283196ff3..e7d80147fe5 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -256,6 +256,24 @@ struct wg_transform_push_data_params - UINT32 size; - }; - -+enum wg_sample_flags -+{ -+ WG_SAMPLE_FLAG_INCOMPLETE = 1, -+}; -+ -+struct wg_sample -+{ -+ UINT32 flags; -+ BYTE *data; -+ UINT32 size; -+}; -+ -+struct wg_transform_read_data_params -+{ -+ struct wg_transform *transform; -+ struct wg_sample *sample; -+}; -+ - enum unix_funcs - { - unix_wg_parser_create, -@@ -307,6 +325,7 @@ enum unix_funcs - unix_wg_parser_stream_drain, - - unix_wg_transform_push_data, -+ unix_wg_transform_read_data, - }; - - #endif /* __WINE_WINEGSTREAMER_UNIXLIB_H */ -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 64c53c6ac98..19c2c661253 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -2058,4 +2058,5 @@ const unixlib_entry_t __wine_unix_call_funcs[] = - X(wg_parser_stream_drain), - - X(wg_transform_push_data), -+ X(wg_transform_read_data), - }; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 2137c4c8821..1f8b35920b4 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -38,14 +38,24 @@ - - #include "unix_private.h" - -+#include "wine/list.h" -+ - GST_DEBUG_CATEGORY_EXTERN(wine); - #define GST_CAT_DEFAULT wine - -+struct wg_transform_sample -+{ -+ struct list entry; -+ GstSample *sample; -+}; -+ - struct wg_transform - { - GstElement *container; - GstPad *my_src, *my_sink; - GstPad *their_sink, *their_src; -+ pthread_mutex_t mutex; -+ struct list samples; - }; - - static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) -@@ -99,17 +109,29 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format - static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, GstBuffer *buffer) - { - struct wg_transform *transform = gst_pad_get_element_private(pad); -+ struct wg_transform_sample *sample; - - GST_INFO("transform %p, buffer %p.", transform, buffer); - -- gst_buffer_unref(buffer); -+ if (!(sample = malloc(sizeof(*sample)))) -+ GST_ERROR("Failed to allocate transform sample entry"); -+ else -+ { -+ pthread_mutex_lock(&transform->mutex); -+ if (!(sample->sample = gst_sample_new(buffer, NULL, NULL, NULL))) -+ GST_ERROR("Failed to allocate transform sample"); -+ list_add_tail(&transform->samples, &sample->entry); -+ pthread_mutex_unlock(&transform->mutex); -+ } - -+ gst_buffer_unref(buffer); - return GST_FLOW_OK; - } - - NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; -+ struct wg_transform_sample *sample, *next; - - if (transform->container) - gst_element_set_state(transform->container, GST_STATE_NULL); -@@ -132,6 +154,13 @@ NTSTATUS wg_transform_destroy(void *args) - if (transform->my_src) - g_object_unref(transform->my_src); - -+ LIST_FOR_EACH_ENTRY_SAFE(sample, next, &transform->samples, struct wg_transform_sample, entry) -+ { -+ gst_sample_unref(sample->sample); -+ list_remove(&sample->entry); -+ free(sample); -+ } -+ - free(transform); - return S_OK; - } -@@ -224,6 +253,8 @@ NTSTATUS wg_transform_create(void *args) - if (!(transform = calloc(1, sizeof(*transform)))) - return E_OUTOFMEMORY; - -+ list_init(&transform->samples); -+ - src_caps = wg_encoded_format_to_caps(&input_format); - assert(src_caps); - sink_caps = wg_format_to_caps(&output_format); -@@ -362,3 +393,46 @@ NTSTATUS wg_transform_push_data(void *args) - GST_INFO("Pushed %u bytes", params->size); - return S_OK; - } -+ -+NTSTATUS wg_transform_read_data(void *args) -+{ -+ struct wg_transform_read_data_params *params = args; -+ struct wg_transform *transform = params->transform; -+ struct wg_sample *read_sample = params->sample; -+ struct wg_transform_sample *transform_sample; -+ GstBuffer *buffer; -+ struct list *head; -+ GstMapInfo info; -+ -+ pthread_mutex_lock(&transform->mutex); -+ if (!(head = list_head(&transform->samples))) -+ { -+ pthread_mutex_unlock(&transform->mutex); -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ transform_sample = LIST_ENTRY(head, struct wg_transform_sample, entry); -+ buffer = gst_sample_get_buffer(transform_sample->sample); -+ -+ gst_buffer_map(buffer, &info, GST_MAP_READ); -+ if (read_sample->size > info.size) -+ read_sample->size = info.size; -+ memcpy(read_sample->data, info.data, read_sample->size); -+ gst_buffer_unmap(buffer, &info); -+ -+ if (info.size > read_sample->size) -+ { -+ read_sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE; -+ gst_buffer_resize(buffer, read_sample->size, -1); -+ } -+ else -+ { -+ gst_sample_unref(transform_sample->sample); -+ list_remove(&transform_sample->entry); -+ free(transform_sample); -+ } -+ pthread_mutex_unlock(&transform->mutex); -+ -+ GST_INFO("Read %u bytes, flags %#x", read_sample->size, read_sample->flags); -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index c9472bde019..cac345be269 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -569,8 +569,63 @@ static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFS - static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); -- return E_NOTIMPL; -+ struct wma_decoder *decoder = impl_from_IMFTransform(iface); -+ struct wg_sample wg_sample = {0}; -+ IMFMediaBuffer *media_buffer; -+ MFT_OUTPUT_STREAM_INFO info; -+ DWORD buffer_size; -+ HRESULT hr; -+ -+ TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); -+ -+ if (count > 1) -+ { -+ FIXME("Not implemented count %lu\n", count); -+ return E_NOTIMPL; -+ } -+ -+ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *status = 0; -+ samples[0].dwStatus = 0; -+ if (!samples[0].pSample) -+ { -+ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &buffer_size, NULL))) -+ goto done; -+ wg_sample.size = buffer_size; -+ -+ if (wg_sample.size < info.cbSize) -+ hr = MF_E_BUFFERTOOSMALL; -+ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -+ { -+ if (wg_sample.flags & WG_SAMPLE_FLAG_INCOMPLETE) -+ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; -+ } -+ else -+ { -+ if (decoder->input_sample) -+ IMFSample_Release(decoder->input_sample); -+ decoder->input_sample = NULL; -+ wg_sample.size = 0; -+ } -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; - } - - static const IMFTransformVtbl transform_vtbl = -From 6cdb3ff4adb3495d9bec127397c277aca0e19205 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:32:39 +0100 -Subject: [PATCH] winegstreamer: Support XMAudio2 input format in WMA decoder. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51931 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52391 -CW-Bug-Id: #19854 ---- - dlls/winegstreamer/mfplat.c | 18 +++++++++++------- - dlls/winegstreamer/wg_transform.c | 10 ++++++++-- - dlls/winegstreamer/wma_decoder.c | 3 +++ - 3 files changed, 22 insertions(+), 9 deletions(-) - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 61c7fe28a63..55287eec5a8 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -29,6 +29,8 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -+DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); -+ - struct video_processor - { - IMFTransform IMFTransform_iface; -@@ -761,8 +763,8 @@ void mf_media_type_to_wg_format(IMFMediaType *type, struct wg_format *format) - FIXME("Unrecognized major type %s.\n", debugstr_guid(&major_type)); - } - --static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg_encoded_format *format, -- UINT32 version) -+static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct wg_encoded_format *format, -+ enum wg_encoded_type encoded_type, UINT32 version) - { - UINT32 rate, depth, channels, block_align, bytes_per_second, codec_data_len; - BYTE codec_data[64]; -@@ -798,7 +800,7 @@ static void mf_media_type_to_wg_encoded_format_wma(IMFMediaType *type, struct wg - bytes_per_second = 0; - } - -- format->encoded_type = WG_ENCODED_TYPE_WMA; -+ format->encoded_type = encoded_type; - format->u.xwma.version = version; - format->u.xwma.bitrate = bytes_per_second * 8; - format->u.xwma.rate = rate; -@@ -829,13 +831,15 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - if (IsEqualGUID(&major_type, &MFMediaType_Audio)) - { - if (IsEqualGUID(&subtype, &MEDIASUBTYPE_MSAUDIO1)) -- mf_media_type_to_wg_encoded_format_wma(type, format, 1); -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 1); - else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV8)) -- mf_media_type_to_wg_encoded_format_wma(type, format, 2); -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 2); - else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudioV9)) -- mf_media_type_to_wg_encoded_format_wma(type, format, 3); -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 3); - else if (IsEqualGUID(&subtype, &MFAudioFormat_WMAudio_Lossless)) -- mf_media_type_to_wg_encoded_format_wma(type, format, 4); -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 4); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) -+ mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_XMA, 2); - else - FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); - } -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 1f8b35920b4..256e77429a0 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -64,12 +64,18 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) - GstCaps *caps; - - if (format->encoded_type == WG_ENCODED_TYPE_WMA) -+ { - caps = gst_caps_new_empty_simple("audio/x-wma"); -+ if (format->u.xwma.version) -+ gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); -+ } - else -+ { - caps = gst_caps_new_empty_simple("audio/x-xma"); -+ if (format->u.xwma.version) -+ gst_caps_set_simple(caps, "xmaversion", G_TYPE_INT, format->u.xwma.version, NULL); -+ } - -- if (format->u.xwma.version) -- gst_caps_set_simple(caps, "wmaversion", G_TYPE_INT, format->u.xwma.version, NULL); - if (format->u.xwma.bitrate) - gst_caps_set_simple(caps, "bitrate", G_TYPE_INT, format->u.xwma.bitrate, NULL); - if (format->u.xwma.rate) -diff --git a/dlls/winegstreamer/wma_decoder.c b/dlls/winegstreamer/wma_decoder.c -index cac345be269..d6ae7d93a39 100644 ---- a/dlls/winegstreamer/wma_decoder.c -+++ b/dlls/winegstreamer/wma_decoder.c -@@ -30,12 +30,15 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(wmadec); - -+DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); -+ - static const GUID *const wma_decoder_input_types[] = - { - &MEDIASUBTYPE_MSAUDIO1, - &MFAudioFormat_WMAudioV8, - &MFAudioFormat_WMAudioV9, - &MFAudioFormat_WMAudio_Lossless, -+ &MFAudioFormat_XMAudio2, - }; - static const GUID *const wma_decoder_output_types[] = - { - -From 1beb998df6007991345072dc64e498fb47a75681 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 18 Jan 2022 13:09:07 +0100 -Subject: [PATCH] winegstreamer: Introduce new H264 decoder transform stub. - -As a remplacement for the previously added transform. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/h264_decoder.c | 279 ++++++++++++++++++++++++++++++ - dlls/winegstreamer/mfplat.c | 27 +++ - 4 files changed, 308 insertions(+) - create mode 100644 dlls/winegstreamer/h264_decoder.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index 52295418f0f..b8c61a316a0 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -10,6 +10,7 @@ C_SRCS = \ - audioconvert.c \ - colorconvert.c \ - decode_transform.c \ -+ h264_decoder.c \ - main.c \ - media_source.c \ - mfplat.c \ -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index ead2bac4edd..7a0078fe2f4 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -124,6 +124,7 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); - -+HRESULT h264_decoder_create(REFIID riid, void **ret); - HRESULT audio_converter_create(REFIID riid, void **ret); - - struct wm_stream -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -new file mode 100644 -index 00000000000..5db72c55151 ---- /dev/null -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -0,0 +1,279 @@ -+/* H264 Decoder Transform -+ * -+ * 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 -+ */ -+ -+#include "gst_private.h" -+ -+#include "mfapi.h" -+#include "mferror.h" -+#include "mfobjects.h" -+#include "mftransform.h" -+#include "wmcodecdsp.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -+ -+struct h264_decoder -+{ -+ IMFTransform IMFTransform_iface; -+ LONG refcount; -+}; -+ -+static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -+{ -+ return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); -+} -+ -+static HRESULT WINAPI h264_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) -+{ -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ -+ TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); -+ -+ if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMFTransform)) -+ *out = &decoder->IMFTransform_iface; -+ else -+ { -+ *out = NULL; -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); -+ return E_NOINTERFACE; -+ } -+ -+ IUnknown_AddRef((IUnknown *)*out); -+ return S_OK; -+} -+ -+static ULONG WINAPI h264_decoder_AddRef(IMFTransform *iface) -+{ -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ ULONG refcount = InterlockedIncrement(&decoder->refcount); -+ -+ TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); -+ -+ return refcount; -+} -+ -+static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) -+{ -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ ULONG refcount = InterlockedDecrement(&decoder->refcount); -+ -+ TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); -+ -+ if (!refcount) -+ free(decoder); -+ -+ return refcount; -+} -+ -+static HRESULT WINAPI h264_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, -+ DWORD *output_minimum, DWORD *output_maximum) -+{ -+ FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n", -+ iface, input_minimum, input_maximum, output_minimum, output_maximum); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -+{ -+ FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, -+ DWORD output_size, DWORD *outputs) -+{ -+ FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p stub!\n", -+ iface, input_size, inputs, output_size, outputs); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -+{ -+ FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -+{ -+ FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -+{ -+ FIXME("iface %p, attributes %p stub!\n", iface, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) -+{ -+ FIXME("iface %p, id %#lx stub!\n", iface, id); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -+{ -+ FIXME("iface %p, streams %lu, ids %p stub!\n", iface, streams, ids); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -+{ -+ FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) -+{ -+ FIXME("iface %p, flags %p stub!\n", iface, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -+{ -+ FIXME("iface %p, lower %s, upper %s stub!\n", iface, -+ wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -+{ -+ FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -+{ -+ FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -+{ -+ FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -+{ -+ FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); -+ return E_NOTIMPL; -+} -+ -+static const IMFTransformVtbl h264_decoder_vtbl = -+{ -+ h264_decoder_QueryInterface, -+ h264_decoder_AddRef, -+ h264_decoder_Release, -+ h264_decoder_GetStreamLimits, -+ h264_decoder_GetStreamCount, -+ h264_decoder_GetStreamIDs, -+ h264_decoder_GetInputStreamInfo, -+ h264_decoder_GetOutputStreamInfo, -+ h264_decoder_GetAttributes, -+ h264_decoder_GetInputStreamAttributes, -+ h264_decoder_GetOutputStreamAttributes, -+ h264_decoder_DeleteInputStream, -+ h264_decoder_AddInputStreams, -+ h264_decoder_GetInputAvailableType, -+ h264_decoder_GetOutputAvailableType, -+ h264_decoder_SetInputType, -+ h264_decoder_SetOutputType, -+ h264_decoder_GetInputCurrentType, -+ h264_decoder_GetOutputCurrentType, -+ h264_decoder_GetInputStatus, -+ h264_decoder_GetOutputStatus, -+ h264_decoder_SetOutputBounds, -+ h264_decoder_ProcessEvent, -+ h264_decoder_ProcessMessage, -+ h264_decoder_ProcessInput, -+ h264_decoder_ProcessOutput, -+}; -+ -+HRESULT h264_decoder_create(REFIID riid, void **ret) -+{ -+ struct h264_decoder *decoder; -+ -+ TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); -+ -+ if (!(decoder = calloc(1, sizeof(*decoder)))) -+ return E_OUTOFMEMORY; -+ -+ decoder->IMFTransform_iface.lpVtbl = &h264_decoder_vtbl; -+ decoder->refcount = 1; -+ -+ *ret = &decoder->IMFTransform_iface; -+ TRACE("Created decoder %p\n", *ret); -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index e1d7a52cc99..6bdf700d5ba 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -400,11 +400,6 @@ static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a - - static const GUID CLSID_WINEAudioConverter = {0x6a170414,0xaad9,0x4693,{0xb8,0x06,0x3a,0x0c,0x47,0xc5,0x70,0xd6}}; - --static HRESULT h264_decoder_create(REFIID riid, void **ret) --{ -- return decode_transform_create(riid, ret, DECODER_TYPE_H264); --} -- - static const struct class_object - { - const GUID *clsid; -@@ -566,7 +561,7 @@ mfts[] = - color_converter_supported_types, - }, - { -- &CLSID_MSAACDecMFT, -+ &CLSID_MSH264DecoderMFT, - &MFT_CATEGORY_VIDEO_DECODER, - h264_decoderW, - MFT_ENUM_FLAG_SYNCMFT, -From d4187ea663f81ccd58e4a9ed671bc2731cdea6c7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 18 Jan 2022 13:33:36 +0100 -Subject: [PATCH] winegstreamer: Return S_OK from H264 decoder GetAttributes. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 5db72c55151..f46d6d77f8e 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -120,7 +120,8 @@ static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWOR - static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) - { - FIXME("iface %p, attributes %p stub!\n", iface, attributes); -- return E_NOTIMPL; -+ -+ return MFCreateAttributes(attributes, 0); - } - - static HRESULT WINAPI h264_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -From a13f8c564234866ae0365c695eee5b01c0ecc302 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 18 Jan 2022 13:33:36 +0100 -Subject: [PATCH] winegstreamer: Return S_OK from H264 decoder ProcessMessage. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index f46d6d77f8e..55f40ad7660 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -216,7 +216,7 @@ static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, I - static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -- return E_NOTIMPL; -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -From aef0b019c04fd73c735f54b34f74fec5d15ec5d2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:54:51 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder SetInputType. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 37 +++++++++++++++++++++++++++++-- - 1 file changed, 35 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 55f40ad7660..e0634bedcaa 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -30,10 +30,16 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - -+static const GUID *h264_decoder_input_types[] = -+{ -+ &MFVideoFormat_H264, -+}; -+ - struct h264_decoder - { - IMFTransform IMFTransform_iface; - LONG refcount; -+ IMFMediaType *input_type; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -78,7 +84,11 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) - TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); - - if (!refcount) -+ { -+ if (decoder->input_type) -+ IMFMediaType_Release(decoder->input_type); - free(decoder); -+ } - - return refcount; - } -@@ -166,8 +176,31 @@ static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, D - - static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ GUID major, subtype; -+ HRESULT hr; -+ ULONG i; -+ -+ TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return E_INVALIDARG; -+ -+ if (!IsEqualGUID(&major, &MFMediaType_Video)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(h264_decoder_input_types); ++i) -+ if (IsEqualGUID(&subtype, h264_decoder_input_types[i])) -+ break; -+ if (i == ARRAY_SIZE(h264_decoder_input_types)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (decoder->input_type) -+ IMFMediaType_Release(decoder->input_type); -+ IMFMediaType_AddRef((decoder->input_type = type)); -+ -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -From d9b859997b6fc2d5d7348205fc2e511c328a9873 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:55:30 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder GetOutputAvailableType. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 141 +++++++++++++++++++++++++++++- - 1 file changed, 138 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index e0634bedcaa..78bf317c36f 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -34,6 +34,14 @@ static const GUID *h264_decoder_input_types[] = - { - &MFVideoFormat_H264, - }; -+static const GUID *h264_decoder_output_types[] = -+{ -+ &MFVideoFormat_NV12, -+ &MFVideoFormat_YV12, -+ &MFVideoFormat_IYUV, -+ &MFVideoFormat_I420, -+ &MFVideoFormat_YUY2, -+}; - - struct h264_decoder - { -@@ -47,6 +55,103 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) - return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); - } - -+static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) -+{ -+ UINT32 value, width, height; -+ UINT64 value64; -+ GUID subtype; -+ HRESULT hr; -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &value64))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_SIZE, &value64))) -+ value64 = (UINT64)1920 << 32 | 1080; -+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, value64))) -+ return hr; -+ } -+ width = value64 >> 32; -+ height = value64; -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FRAME_RATE, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_FRAME_RATE, &value64))) -+ value64 = (UINT64)30000 << 32 | 1001; -+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_RATE, value64))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_PIXEL_ASPECT_RATIO, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT64(default_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64))) -+ value64 = (UINT64)1 << 32 | 1; -+ if (FAILED(hr = IMFMediaType_SetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, value64))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_SAMPLE_SIZE, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_SAMPLE_SIZE, &value))) -+ { -+ if (IsEqualGUID(&subtype, &MFVideoFormat_YUY2)) -+ value = width * height * 2; -+ else -+ value = width * height * 3 / 2; -+ } -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_DEFAULT_STRIDE, &value))) -+ { -+ if (IsEqualGUID(&subtype, &MFVideoFormat_YUY2)) -+ value = width * 2; -+ else -+ value = width; -+ } -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_DEFAULT_STRIDE, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_INTERLACE_MODE, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_INTERLACE_MODE, &value))) -+ value = MFVideoInterlace_MixedInterlaceOrProgressive; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_INTERLACE_MODE, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, &value))) -+ value = 1; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_VIDEO_ROTATION, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_VIDEO_ROTATION, &value))) -+ value = 0; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_VIDEO_ROTATION, value))) -+ return hr; -+ } -+ -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_FIXED_SIZE_SAMPLES, NULL))) -+ { -+ if (!default_type || FAILED(hr = IMFMediaType_GetUINT32(default_type, &MF_MT_FIXED_SIZE_SAMPLES, &value))) -+ value = 1; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, value))) -+ return hr; -+ } -+ -+ return S_OK; -+} -+ - static HRESULT WINAPI h264_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) - { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); -@@ -170,8 +275,38 @@ static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DW - static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaType *media_type; -+ const GUID *output_type; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); -+ -+ if (!decoder->input_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *type = NULL; -+ -+ if (index >= ARRAY_SIZE(h264_decoder_output_types)) -+ return MF_E_NO_MORE_TYPES; -+ output_type = h264_decoder_output_types[index]; -+ -+ if (FAILED(hr = MFCreateMediaType(&media_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) -+ goto done; -+ -+ hr = fill_output_media_type(media_type, NULL); -+ -+done: -+ if (SUCCEEDED(hr)) -+ IMFMediaType_AddRef((*type = media_type)); -+ -+ IMFMediaType_Release(media_type); -+ return hr; - } - - static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -@@ -184,7 +319,7 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, I - TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); - - if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -- FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) - return E_INVALIDARG; - - if (!IsEqualGUID(&major, &MFMediaType_Video)) -From 2ce8f6c136202c16eb903220a2730942b00ae52c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:55:46 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder GetInputAvailableType. - -Required by Shadow Warrior 2. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 23 +++++++++++++++++++++-- - 1 file changed, 21 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 78bf317c36f..7aca79e7a86 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -268,8 +268,27 @@ static HRESULT WINAPI h264_decoder_AddInputStreams(IMFTransform *iface, DWORD st - static HRESULT WINAPI h264_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, - IMFMediaType **type) - { -- FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -- return E_NOTIMPL; -+ IMFMediaType *media_type; -+ const GUID *subtype; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); -+ -+ *type = NULL; -+ -+ if (index >= ARRAY_SIZE(h264_decoder_input_types)) -+ return MF_E_NO_MORE_TYPES; -+ subtype = h264_decoder_input_types[index]; -+ -+ if (FAILED(hr = MFCreateMediaType(&media_type))) -+ return hr; -+ -+ if (SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)) && -+ SUCCEEDED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype))) -+ IMFMediaType_AddRef((*type = media_type)); -+ -+ IMFMediaType_Release(media_type); -+ return hr; - } - - static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -From 14706e4f94cb61177826ac8970e796fc1f572fb4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:56:08 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder SetOutputType. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 39 +++++++++++++++++++++++++++++-- - 1 file changed, 37 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 7aca79e7a86..2cfc1ac0d05 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -48,6 +48,7 @@ struct h264_decoder - IMFTransform IMFTransform_iface; - LONG refcount; - IMFMediaType *input_type; -+ IMFMediaType *output_type; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -192,6 +193,8 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) - { - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); -+ if (decoder->output_type) -+ IMFMediaType_Release(decoder->output_type); - free(decoder); - } - -@@ -350,6 +353,12 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, I - if (i == ARRAY_SIZE(h264_decoder_input_types)) - return MF_E_INVALIDMEDIATYPE; - -+ if (decoder->output_type) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - IMFMediaType_AddRef((decoder->input_type = type)); -@@ -359,8 +368,34 @@ static HRESULT WINAPI h264_decoder_SetInputType(IMFTransform *iface, DWORD id, I - - static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) - { -- FIXME("iface %p, id %#lx, type %p, flags %#lx stub!\n", iface, id, type, flags); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ GUID major, subtype; -+ HRESULT hr; -+ ULONG i; -+ -+ TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); -+ -+ if (!decoder->input_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (!IsEqualGUID(&major, &MFMediaType_Video)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(h264_decoder_output_types); ++i) -+ if (IsEqualGUID(&subtype, h264_decoder_output_types[i])) -+ break; -+ if (i == ARRAY_SIZE(h264_decoder_output_types)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (decoder->output_type) -+ IMFMediaType_Release(decoder->output_type); -+ IMFMediaType_AddRef((decoder->output_type = type)); -+ -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -From da890b23a3504ee9afca1a12a4c29680f33eb458 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:56:23 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder GetInputStreamInfo. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 2cfc1ac0d05..1ccb5f39908 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -225,8 +225,20 @@ static HRESULT WINAPI h264_decoder_GetStreamIDs(IMFTransform *iface, DWORD input - - static HRESULT WINAPI h264_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) - { -- FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ -+ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); -+ -+ if (!decoder->input_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ info->hnsMaxLatency = 0; -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES | MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE; -+ info->cbSize = 0x1000; -+ info->cbMaxLookahead = 0; -+ info->cbAlignment = 0; -+ -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -From 62f0f599b09103652c63d0f1d73eb8ac875ff440 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:56:35 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder GetOutputStreamInfo. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 21 +++++++++++++++++++-- - 1 file changed, 19 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 1ccb5f39908..eadb28cdaaa 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -243,8 +243,25 @@ static HRESULT WINAPI h264_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD - - static HRESULT WINAPI h264_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) - { -- FIXME("iface %p, id %#lx, info %p stub!\n", iface, id, info); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaType *media_type; -+ UINT32 sample_size; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); -+ -+ if (!decoder->input_type || !decoder->output_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ media_type = decoder->output_type; -+ -+ info->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE; -+ if (FAILED(hr = IMFMediaType_GetUINT32(media_type, &MF_MT_SAMPLE_SIZE, &sample_size))) -+ sample_size = 1920 * 1080 * 2; -+ info->cbSize = sample_size; -+ info->cbAlignment = 0; -+ -+ return S_OK; - } - - static HRESULT WINAPI h264_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -From 24312f557589df704155d6870e5e680df87b11ca Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:33:39 +0100 -Subject: [PATCH] winegstreamer: Add H264 encoded format support in - wg_transform. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 36 +++++++++++++++++- - dlls/winegstreamer/mfplat.c | 37 ++++++++++++++++++ - dlls/winegstreamer/unixlib.h | 8 ++++ - dlls/winegstreamer/wg_transform.c | 63 +++++++++++++++++++++++++++++++ - 4 files changed, 143 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index eadb28cdaaa..b7de097fc7d 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -49,6 +49,8 @@ struct h264_decoder - LONG refcount; - IMFMediaType *input_type; - IMFMediaType *output_type; -+ -+ struct wg_transform *wg_transform; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -56,6 +58,30 @@ static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) - return CONTAINING_RECORD(iface, struct h264_decoder, IMFTransform_iface); - } - -+static HRESULT try_create_wg_transform(struct h264_decoder *decoder) -+{ -+ struct wg_encoded_format input_format; -+ struct wg_format output_format; -+ -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); -+ -+ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); -+ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ mf_media_type_to_wg_format(decoder->output_type, &output_format); -+ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ decoder->wg_transform = wg_transform_create(&input_format, &output_format); -+ if (decoder->wg_transform) -+ return S_OK; -+ -+ WARN("Failed to create H264 wg_transform.\n"); -+ return E_FAIL; -+} -+ - static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) - { - UINT32 value, width, height; -@@ -191,6 +217,8 @@ static ULONG WINAPI h264_decoder_Release(IMFTransform *iface) - - if (!refcount) - { -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); - if (decoder->input_type) - IMFMediaType_Release(decoder->input_type); - if (decoder->output_type) -@@ -424,7 +452,13 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, - IMFMediaType_Release(decoder->output_type); - IMFMediaType_AddRef((decoder->output_type = type)); - -- return S_OK; -+ if (FAILED(hr = try_create_wg_transform(decoder))) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ -+ return hr; - } - - static HRESULT WINAPI h264_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 67c11ce75d7..4ff174a2083 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -838,6 +838,36 @@ static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct w - memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); - } - -+static void mf_media_type_to_wg_encoded_format_h264(IMFMediaType *type, struct wg_encoded_format *format) -+{ -+ UINT64 frame_rate, frame_size; -+ UINT32 profile, level; -+ -+ format->encoded_type = WG_ENCODED_TYPE_H264; -+ format->u.h264.width = 0; -+ format->u.h264.height = 0; -+ format->u.h264.fps_n = 1; -+ format->u.h264.fps_d = 1; -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))) -+ { -+ format->u.h264.width = (UINT32)(frame_size >> 32); -+ format->u.h264.height = (UINT32)frame_size; -+ } -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT64(type, &MF_MT_FRAME_RATE, &frame_rate)) && (UINT32)frame_rate) -+ { -+ format->u.h264.fps_n = (UINT32)(frame_rate >> 32); -+ format->u.h264.fps_d = (UINT32)frame_rate; -+ } -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_PROFILE, &profile))) -+ format->u.h264.profile = profile; -+ -+ if (SUCCEEDED(IMFMediaType_GetUINT32(type, &MF_MT_MPEG2_LEVEL, &level))) -+ format->u.h264.level = level; -+} -+ - void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_format *format) - { - GUID major_type, subtype; -@@ -870,6 +900,13 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - else - FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); - } -+ else if (IsEqualGUID(&major_type, &MFMediaType_Video)) -+ { -+ if (IsEqualGUID(&subtype, &MFVideoFormat_H264)) -+ mf_media_type_to_wg_encoded_format_h264(type, format); -+ else -+ FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); -+ } - else - { - FIXME("Unimplemented major type %s.\n", debugstr_guid(&major_type)); -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index e7d80147fe5..7892e2813fc 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -98,6 +98,7 @@ struct wg_encoded_format - WG_ENCODED_TYPE_UNKNOWN, - WG_ENCODED_TYPE_WMA, - WG_ENCODED_TYPE_XMA, -+ WG_ENCODED_TYPE_H264, - } encoded_type; - - union -@@ -113,6 +114,13 @@ struct wg_encoded_format - uint32_t codec_data_len; - unsigned char codec_data[64]; - } xwma; -+ struct -+ { -+ int32_t width, height; -+ uint32_t fps_n, fps_d; -+ uint32_t profile; -+ uint32_t level; -+ } h264; - } u; - }; - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 256e77429a0..2956ddf753b 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -98,6 +98,64 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) - return caps; - } - -+static GstCaps *wg_format_to_caps_h264(const struct wg_encoded_format *format) -+{ -+ const char *profile, *level; -+ GstCaps *caps; -+ -+ caps = gst_caps_new_empty_simple("video/x-h264"); -+ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, "byte-stream", NULL); -+ gst_caps_set_simple(caps, "alignment", G_TYPE_STRING, "au", NULL); -+ -+ if (format->u.h264.width) -+ gst_caps_set_simple(caps, "width", G_TYPE_INT, format->u.h264.width, NULL); -+ if (format->u.h264.height) -+ gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.h264.height, NULL); -+ if (format->u.h264.fps_n || format->u.h264.fps_d) -+ gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.h264.fps_n, format->u.h264.fps_d, NULL); -+ -+ switch (format->u.h264.profile) -+ { -+ case /* eAVEncH264VProfile_Main */ 77: profile = "main"; break; -+ case /* eAVEncH264VProfile_High */ 100: profile = "high"; break; -+ case /* eAVEncH264VProfile_444 */ 244: profile = "high-4:4:4"; break; -+ default: -+ GST_ERROR("Unrecognized H.264 profile attribute %u.", format->u.h264.profile); -+ /* fallthrough */ -+ case 0: profile = NULL; -+ } -+ if (profile) -+ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); -+ -+ switch (format->u.h264.level) -+ { -+ case /* eAVEncH264VLevel1 */ 10: level = "1"; break; -+ case /* eAVEncH264VLevel1_1 */ 11: level = "1.1"; break; -+ case /* eAVEncH264VLevel1_2 */ 12: level = "1.2"; break; -+ case /* eAVEncH264VLevel1_3 */ 13: level = "1.3"; break; -+ case /* eAVEncH264VLevel2 */ 20: level = "2"; break; -+ case /* eAVEncH264VLevel2_1 */ 21: level = "2.1"; break; -+ case /* eAVEncH264VLevel2_2 */ 22: level = "2.2"; break; -+ case /* eAVEncH264VLevel3 */ 30: level = "3"; break; -+ case /* eAVEncH264VLevel3_1 */ 31: level = "3.1"; break; -+ case /* eAVEncH264VLevel3_2 */ 32: level = "3.2"; break; -+ case /* eAVEncH264VLevel4 */ 40: level = "4"; break; -+ case /* eAVEncH264VLevel4_1 */ 41: level = "4.1"; break; -+ case /* eAVEncH264VLevel4_2 */ 42: level = "4.2"; break; -+ case /* eAVEncH264VLevel5 */ 50: level = "5"; break; -+ case /* eAVEncH264VLevel5_1 */ 51: level = "5.1"; break; -+ case /* eAVEncH264VLevel5_2 */ 52: level = "5.2"; break; -+ default: -+ GST_ERROR("Unrecognized H.264 level attribute %u.", format->u.h264.level); -+ /* fallthrough */ -+ case 0: level = NULL; -+ } -+ if (level) -+ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); -+ -+ return caps; -+} -+ - static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format) - { - switch (format->encoded_type) -@@ -107,6 +165,8 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format - case WG_ENCODED_TYPE_WMA: - case WG_ENCODED_TYPE_XMA: - return wg_format_to_caps_xwma(format); -+ case WG_ENCODED_TYPE_H264: -+ return wg_format_to_caps_h264(format); - } - assert(0); - return NULL; -@@ -286,7 +346,10 @@ NTSTATUS wg_transform_create(void *args) - !transform_append_element(transform, element, &first, &last)) - goto failed; - break; -+ case WG_MAJOR_TYPE_VIDEO: -+ break; - default: -+ assert(0); - break; - } - -From 5a8875b0c253f433a3c381a6ad342ef48b0d9a6b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:56:47 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder ProcessInput. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 30 ++++++++++++++++++++++++++++-- - 1 file changed, 28 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index b7de097fc7d..268262a0f18 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -506,8 +506,34 @@ static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSA - - static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) - { -- FIXME("iface %p, id %#lx, sample %p, flags %#lx stub!\n", iface, id, sample, flags); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaBuffer *media_buffer; -+ MFT_INPUT_STREAM_INFO info; -+ DWORD buffer_size; -+ BYTE *buffer; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); -+ -+ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &buffer_size))) -+ goto done; -+ -+ hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size); -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; - } - - static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -From e6a374bd7eba342a3501477e774ea7e58dd7f58f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:57:10 +0100 -Subject: [PATCH] winegstreamer: Implement H264 decoder ProcessOutput. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 50 +++++++++++++++++++++++++++++-- - 1 file changed, 48 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 268262a0f18..44d55ae061f 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -539,8 +539,54 @@ static HRESULT WINAPI h264_decoder_ProcessInput(IMFTransform *iface, DWORD id, I - static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, - MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) - { -- FIXME("iface %p, flags %#lx, count %lu, samples %p, status %p stub!\n", iface, flags, count, samples, status); -- return E_NOTIMPL; -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ struct wg_sample wg_sample = {0}; -+ IMFMediaBuffer *media_buffer; -+ MFT_OUTPUT_STREAM_INFO info; -+ DWORD buffer_size; -+ HRESULT hr; -+ -+ TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); -+ -+ if (count > 1) -+ { -+ FIXME("Not implemented count %lu\n", count); -+ return E_NOTIMPL; -+ } -+ -+ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *status = 0; -+ samples[0].dwStatus = 0; -+ if (!samples[0].pSample) -+ { -+ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &buffer_size, NULL))) -+ goto done; -+ wg_sample.size = buffer_size; -+ -+ if (wg_sample.size < info.cbSize) -+ hr = MF_E_BUFFERTOOSMALL; -+ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -+ hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ if (FAILED(hr)) -+ IMFMediaBuffer_SetCurrentLength(media_buffer, 0); -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; - } - - static const IMFTransformVtbl h264_decoder_vtbl = -From 1f577e3a9cdff29b907ee9bbf999427146c7a0b2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:34:12 +0100 -Subject: [PATCH] winegstreamer: Add timestamps and duration to H264 decoded - samples. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 6 ++++++ - dlls/winegstreamer/unixlib.h | 4 ++++ - dlls/winegstreamer/wg_transform.c | 11 +++++++++++ - 3 files changed, 21 insertions(+) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 44d55ae061f..69e747f1dc0 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -578,7 +578,13 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - if (wg_sample.size < info.cbSize) - hr = MF_E_BUFFERTOOSMALL; - else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -+ { -+ if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_PTS) -+ IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); -+ if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) -+ IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); - hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); -+ } - - IMFMediaBuffer_Unlock(media_buffer); - -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 7892e2813fc..5890780c64c 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -267,6 +267,8 @@ struct wg_transform_push_data_params - enum wg_sample_flags - { - WG_SAMPLE_FLAG_INCOMPLETE = 1, -+ WG_SAMPLE_FLAG_HAS_PTS = 2, -+ WG_SAMPLE_FLAG_HAS_DURATION = 4, - }; - - struct wg_sample -@@ -274,6 +276,8 @@ struct wg_sample - UINT32 flags; - BYTE *data; - UINT32 size; -+ /* pts and duration are in 100-nanosecond units. */ -+ ULONGLONG pts, duration; - }; - - struct wg_transform_read_data_params -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 2956ddf753b..93e777ba39a 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -489,6 +489,17 @@ NTSTATUS wg_transform_read_data(void *args) - memcpy(read_sample->data, info.data, read_sample->size); - gst_buffer_unmap(buffer, &info); - -+ if (buffer->pts != GST_CLOCK_TIME_NONE) -+ { -+ read_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; -+ read_sample->pts = buffer->pts / 100; -+ } -+ if (buffer->duration != GST_CLOCK_TIME_NONE) -+ { -+ read_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; -+ read_sample->duration = buffer->duration / 100; -+ } -+ - if (info.size > read_sample->size) - { - read_sample->flags |= WG_SAMPLE_FLAG_INCOMPLETE; -From 5519610d889b79df7109ab8fe0c0002de9d78eeb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:57:36 +0100 -Subject: [PATCH] winegstreamer: Support dynamic wg_transform video format - change. - -For: Call of Duty III, Mortal Kombat 11, Shadow Warrior 2, -Yakuza 4 Remastered, Hard Reset Redux. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 26 ++++++++++++- - dlls/winegstreamer/unix_private.h | 2 + - dlls/winegstreamer/unixlib.h | 1 + - dlls/winegstreamer/wg_parser.c | 4 +- - dlls/winegstreamer/wg_transform.c | 61 ++++++++++++++++++++++++++++++- - 5 files changed, 89 insertions(+), 5 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 69e747f1dc0..219790128da 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -51,6 +51,7 @@ struct h264_decoder - IMFMediaType *output_type; - - struct wg_transform *wg_transform; -+ struct wg_format wg_format; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -378,7 +379,7 @@ static HRESULT WINAPI h264_decoder_GetOutputAvailableType(IMFTransform *iface, D - if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) - goto done; - -- hr = fill_output_media_type(media_type, NULL); -+ hr = fill_output_media_type(media_type, decoder->output_type); - - done: - if (SUCCEEDED(hr)) -@@ -427,6 +428,7 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, - { - struct h264_decoder *decoder = impl_from_IMFTransform(iface); - GUID major, subtype; -+ BOOL identical; - HRESULT hr; - ULONG i; - -@@ -449,7 +451,13 @@ static HRESULT WINAPI h264_decoder_SetOutputType(IMFTransform *iface, DWORD id, - return MF_E_INVALIDMEDIATYPE; - - if (decoder->output_type) -+ { -+ if (SUCCEEDED(hr = IMFMediaType_Compare(decoder->output_type, (IMFAttributes *)type, -+ MF_ATTRIBUTES_MATCH_THEIR_ITEMS, &identical)) && identical) -+ return S_OK; - IMFMediaType_Release(decoder->output_type); -+ } -+ - IMFMediaType_AddRef((decoder->output_type = type)); - - if (FAILED(hr = try_create_wg_transform(decoder))) -@@ -543,6 +551,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - struct wg_sample wg_sample = {0}; - IMFMediaBuffer *media_buffer; - MFT_OUTPUT_STREAM_INFO info; -+ IMFMediaType *media_type; - DWORD buffer_size; - HRESULT hr; - -@@ -575,6 +584,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - goto done; - wg_sample.size = buffer_size; - -+ wg_sample.format = &decoder->wg_format; - if (wg_sample.size < info.cbSize) - hr = MF_E_BUFFERTOOSMALL; - else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -@@ -585,6 +595,20 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); - hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); - } -+ else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) -+ { -+ media_type = mf_media_type_from_wg_format(&decoder->wg_format); -+ IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, wg_sample.size); -+ IMFMediaType_DeleteItem(media_type, &MF_MT_FRAME_RATE); -+ IMFMediaType_DeleteItem(decoder->output_type, &MF_MT_DEFAULT_STRIDE); -+ fill_output_media_type(media_type, decoder->output_type); -+ -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = media_type; -+ -+ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; -+ *status |= MFT_OUTPUT_DATA_BUFFER_FORMAT_CHANGE; -+ } - - IMFMediaBuffer_Unlock(media_buffer); - -diff --git a/dlls/winegstreamer/unix_private.h b/dlls/winegstreamer/unix_private.h -index 1b055436ba5..88566ab1db5 100644 ---- a/dlls/winegstreamer/unix_private.h -+++ b/dlls/winegstreamer/unix_private.h -@@ -26,6 +26,8 @@ - extern bool init_gstreamer(void) DECLSPEC_HIDDEN; - extern GstElement *create_element(const char *name, const char *plugin_set) DECLSPEC_HIDDEN; - extern GstCaps *wg_format_to_caps(const struct wg_format *format) DECLSPEC_HIDDEN; -+extern void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) DECLSPEC_HIDDEN; -+extern bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) DECLSPEC_HIDDEN; - - extern NTSTATUS wg_transform_create(void *args) DECLSPEC_HIDDEN; - extern NTSTATUS wg_transform_destroy(void *args) DECLSPEC_HIDDEN; -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 5890780c64c..2e9625fed4e 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -278,6 +278,7 @@ struct wg_sample - UINT32 size; - /* pts and duration are in 100-nanosecond units. */ - ULONGLONG pts, duration; -+ struct wg_format *format; - }; - - struct wg_transform_read_data_params -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 19c2c661253..9e1fc5d1357 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -308,7 +308,7 @@ static void wg_format_from_caps_video_cinepak(struct wg_format *format, const Gs - format->u.video.fps_d = fps_d; - } - --static void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) -+void wg_format_from_caps(struct wg_format *format, const GstCaps *caps) - { - const GstStructure *structure = gst_caps_get_structure(caps, 0); - const char *name = gst_structure_get_name(structure); -@@ -478,7 +478,7 @@ GstCaps *wg_format_to_caps(const struct wg_format *format) - return NULL; - } - --static bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) -+bool wg_format_compare(const struct wg_format *a, const struct wg_format *b) - { - if (a->major_type != b->major_type) - return false; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 93e777ba39a..df37b4e8543 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -56,6 +56,7 @@ struct wg_transform - GstPad *their_sink, *their_src; - pthread_mutex_t mutex; - struct list samples; -+ GstCaps *sink_caps; - }; - - static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) -@@ -184,7 +185,7 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst - else - { - pthread_mutex_lock(&transform->mutex); -- if (!(sample->sample = gst_sample_new(buffer, NULL, NULL, NULL))) -+ if (!(sample->sample = gst_sample_new(buffer, transform->sink_caps, NULL, NULL))) - GST_ERROR("Failed to allocate transform sample"); - list_add_tail(&transform->samples, &sample->entry); - pthread_mutex_unlock(&transform->mutex); -@@ -194,6 +195,38 @@ static GstFlowReturn transform_sink_chain_cb(GstPad *pad, GstObject *parent, Gst - return GST_FLOW_OK; - } - -+static gboolean transform_sink_event_cb(GstPad *pad, GstObject *parent, GstEvent *event) -+{ -+ struct wg_transform *transform = gst_pad_get_element_private(pad); -+ -+ GST_INFO("transform %p, type \"%s\".", transform, GST_EVENT_TYPE_NAME(event)); -+ -+ switch (event->type) -+ { -+ case GST_EVENT_CAPS: -+ { -+ GstCaps *caps; -+ gchar *str; -+ -+ gst_event_parse_caps(event, &caps); -+ str = gst_caps_to_string(caps); -+ GST_WARNING("Got caps \"%s\".", str); -+ g_free(str); -+ -+ pthread_mutex_lock(&transform->mutex); -+ gst_caps_unref(transform->sink_caps); -+ transform->sink_caps = gst_caps_ref(caps); -+ pthread_mutex_unlock(&transform->mutex); -+ break; -+ } -+ default: -+ GST_WARNING("Ignoring \"%s\" event.", GST_EVENT_TYPE_NAME(event)); -+ } -+ -+ gst_event_unref(event); -+ return TRUE; -+} -+ - NTSTATUS wg_transform_destroy(void *args) - { - struct wg_transform *transform = args; -@@ -311,7 +344,7 @@ NTSTATUS wg_transform_create(void *args) - GstPadTemplate *template; - const gchar *media_type; - GstSegment *segment; -- int ret; -+ int i, ret; - - if (!init_gstreamer()) - return E_FAIL; -@@ -329,6 +362,7 @@ NTSTATUS wg_transform_create(void *args) - raw_caps = gst_caps_new_empty_simple(media_type); - assert(raw_caps); - -+ transform->sink_caps = gst_caps_copy(sink_caps); - transform->container = gst_bin_new("wg_transform"); - assert(transform->container); - -@@ -347,6 +381,12 @@ NTSTATUS wg_transform_create(void *args) - goto failed; - break; - case WG_MAJOR_TYPE_VIDEO: -+ if (!(element = create_element("videoconvert", "base")) || -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ for (i = 0; i < gst_caps_get_size(sink_caps); ++i) -+ gst_structure_remove_fields(gst_caps_get_structure(sink_caps, i), -+ "width", "height", NULL); - break; - default: - assert(0); -@@ -377,6 +417,7 @@ NTSTATUS wg_transform_create(void *args) - assert(transform->my_sink); - - gst_pad_set_element_private(transform->my_sink, transform); -+ gst_pad_set_event_function(transform->my_sink, transform_sink_event_cb); - gst_pad_set_chain_function(transform->my_sink, transform_sink_chain_cb); - - if ((ret = gst_pad_link(transform->my_src, transform->their_sink)) < 0) -@@ -469,9 +510,11 @@ NTSTATUS wg_transform_read_data(void *args) - struct wg_transform *transform = params->transform; - struct wg_sample *read_sample = params->sample; - struct wg_transform_sample *transform_sample; -+ struct wg_format buffer_format; - GstBuffer *buffer; - struct list *head; - GstMapInfo info; -+ GstCaps *caps; - - pthread_mutex_lock(&transform->mutex); - if (!(head = list_head(&transform->samples))) -@@ -483,6 +526,20 @@ NTSTATUS wg_transform_read_data(void *args) - transform_sample = LIST_ENTRY(head, struct wg_transform_sample, entry); - buffer = gst_sample_get_buffer(transform_sample->sample); - -+ if (read_sample->format) -+ { -+ if (!(caps = gst_sample_get_caps(transform_sample->sample))) -+ caps = transform->sink_caps; -+ wg_format_from_caps(&buffer_format, caps); -+ if (!wg_format_compare(read_sample->format, &buffer_format)) -+ { -+ *read_sample->format = buffer_format; -+ read_sample->size = gst_buffer_get_size(buffer); -+ pthread_mutex_unlock(&transform->mutex); -+ return MF_E_TRANSFORM_STREAM_CHANGE; -+ } -+ } -+ - gst_buffer_map(buffer, &info, GST_MAP_READ); - if (read_sample->size > info.size) - read_sample->size = info.size; -From 653649989217881800aa20f66f209ef4825e2d38 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:58:20 +0100 -Subject: [PATCH] winegstreamer: Fixup H264 decoder NV12 plane alignment. - -To match what native does. Many games that use the H264 decoder directly -rely on this as they hardcode various aspects of the alignment in their -logic (and each game a different one). - -Note: There may be a way to have it done by GStreamer, as libav natively -decode H264 into aligned planes, but somehow and somewhere in the chain -the planes are re-aligned. - -Hard Reset Redux crashes if MF_MT_MINIMUM_DISPLAY_APERTURE attribute is -set (and it doesn't need it as its videos are 720p). - -For: Call of Duty III, Shadow Warrior 2. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 40 +++++++++++++++++++++++++++++++ - 1 file changed, 40 insertions(+) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 219790128da..66ecfad84de 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -86,6 +86,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) - static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *default_type) - { - UINT32 value, width, height; -+ MFVideoArea aperture = {0}; - UINT64 value64; - GUID subtype; - HRESULT hr; -@@ -177,6 +178,17 @@ static HRESULT fill_output_media_type(IMFMediaType *media_type, IMFMediaType *de - return hr; - } - -+ if (FAILED(hr = IMFMediaType_GetItem(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, NULL))) -+ { -+ if (default_type && SUCCEEDED(hr = IMFMediaType_GetBlob(default_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, -+ (BYTE *)&aperture, sizeof(aperture), NULL))) -+ { -+ if (FAILED(hr = IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, -+ (BYTE *)&aperture, sizeof(aperture)))) -+ return hr; -+ } -+ } -+ - return S_OK; - } - -@@ -551,7 +563,9 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - struct wg_sample wg_sample = {0}; - IMFMediaBuffer *media_buffer; - MFT_OUTPUT_STREAM_INFO info; -+ MFVideoArea aperture = {0}; - IMFMediaType *media_type; -+ UINT32 align, offset; - DWORD buffer_size; - HRESULT hr; - -@@ -593,6 +607,17 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); - if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) - IMFSample_SetSampleDuration(samples[0].pSample, wg_sample.duration); -+ -+ if (decoder->wg_format.u.video.format == WG_VIDEO_FORMAT_NV12 && -+ (align = decoder->wg_format.u.video.height & 15)) -+ { -+ offset = decoder->wg_format.u.video.width * decoder->wg_format.u.video.height; -+ align = (16 - align) * decoder->wg_format.u.video.width; -+ memmove(wg_sample.data + offset + align, wg_sample.data + offset, -+ wg_sample.size - offset); -+ wg_sample.size += align; -+ } -+ - hr = IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); - } - else if (hr == MF_E_TRANSFORM_STREAM_CHANGE) -@@ -603,6 +628,21 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - IMFMediaType_DeleteItem(decoder->output_type, &MF_MT_DEFAULT_STRIDE); - fill_output_media_type(media_type, decoder->output_type); - -+ if (decoder->wg_format.u.video.format == WG_VIDEO_FORMAT_NV12 && -+ (align = decoder->wg_format.u.video.height & 15)) -+ { -+ aperture.Area.cx = decoder->wg_format.u.video.width; -+ aperture.Area.cy = decoder->wg_format.u.video.height; -+ IMFMediaType_SetBlob(media_type, &MF_MT_MINIMUM_DISPLAY_APERTURE, -+ (BYTE *)&aperture, sizeof(aperture)); -+ -+ aperture.Area.cy += 16 - align; -+ IMFMediaType_SetUINT64(media_type, &MF_MT_FRAME_SIZE, -+ (UINT64)aperture.Area.cx << 32 | aperture.Area.cy); -+ IMFMediaType_SetUINT32(media_type, &MF_MT_SAMPLE_SIZE, -+ aperture.Area.cx * aperture.Area.cy * 3 / 2); -+ } -+ - IMFMediaType_Release(decoder->output_type); - decoder->output_type = media_type; - -From 3f86ff74c2a8a82913bbb35d9ee4f90eca855976 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 21:46:08 +0100 -Subject: [PATCH] winegstreamer: Use an optional h264parse wg_transform - element. - -Required for Mortal Kombat 11. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/wg_transform.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index df37b4e8543..e3b7d8ed056 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -366,6 +366,17 @@ NTSTATUS wg_transform_create(void *args) - transform->container = gst_bin_new("wg_transform"); - assert(transform->container); - -+ switch (input_format.encoded_type) -+ { -+ case WG_ENCODED_TYPE_H264: -+ if ((element = create_element("h264parse", "base")) && -+ !transform_append_element(transform, element, &first, &last)) -+ goto failed; -+ break; -+ default: -+ break; -+ } -+ - if (!(element = try_create_transform(src_caps, raw_caps)) || - !transform_append_element(transform, element, &first, &last)) - goto failed; -From bc56611bc058a0b6bd6c517d35055d5e78826b29 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 10 Feb 2022 09:58:32 +0100 -Subject: [PATCH] HACK: winegstreamer: Fake H264 timestamps if framerate cannot - be trusted. - -Fixes MK11 video framerate. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 12 ++++++++++++ - dlls/winegstreamer/wg_transform.c | 10 ++++++++-- - 2 files changed, 20 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index 66ecfad84de..ba6e681890b 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -52,6 +52,7 @@ struct h264_decoder - - struct wg_transform *wg_transform; - struct wg_format wg_format; -+ ULONGLONG last_pts; - }; - - static struct h264_decoder *impl_from_IMFTransform(IMFTransform *iface) -@@ -75,6 +76,7 @@ static HRESULT try_create_wg_transform(struct h264_decoder *decoder) - if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) - return MF_E_INVALIDMEDIATYPE; - -+ decoder->last_pts = 0; - decoder->wg_transform = wg_transform_create(&input_format, &output_format); - if (decoder->wg_transform) - return S_OK; -@@ -567,6 +569,7 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - IMFMediaType *media_type; - UINT32 align, offset; - DWORD buffer_size; -+ UINT64 framerate; - HRESULT hr; - - TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); -@@ -603,6 +606,15 @@ static HRESULT WINAPI h264_decoder_ProcessOutput(IMFTransform *iface, DWORD flag - hr = MF_E_BUFFERTOOSMALL; - else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) - { -+ if (!(wg_sample.flags & (WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION))) -+ { -+ IMFMediaType_GetUINT64(decoder->output_type, &MF_MT_FRAME_RATE, &framerate); -+ wg_sample.pts = decoder->last_pts; -+ wg_sample.duration = (UINT64)10000000 * (UINT32)framerate / (framerate >> 32); -+ wg_sample.flags |= (WG_SAMPLE_FLAG_HAS_PTS|WG_SAMPLE_FLAG_HAS_DURATION); -+ decoder->last_pts += wg_sample.duration; -+ } -+ - if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_PTS) - IMFSample_SetSampleTime(samples[0].pSample, wg_sample.pts); - if (wg_sample.flags & WG_SAMPLE_FLAG_HAS_DURATION) -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index e3b7d8ed056..1c9dc6f72bb 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -522,6 +522,7 @@ NTSTATUS wg_transform_read_data(void *args) - struct wg_sample *read_sample = params->sample; - struct wg_transform_sample *transform_sample; - struct wg_format buffer_format; -+ bool broken_timestamp = false; - GstBuffer *buffer; - struct list *head; - GstMapInfo info; -@@ -549,6 +550,11 @@ NTSTATUS wg_transform_read_data(void *args) - pthread_mutex_unlock(&transform->mutex); - return MF_E_TRANSFORM_STREAM_CHANGE; - } -+ -+ if (buffer_format.major_type == WG_MAJOR_TYPE_VIDEO -+ && buffer_format.u.video.fps_n <= 1 -+ && buffer_format.u.video.fps_d <= 1) -+ broken_timestamp = true; - } - - gst_buffer_map(buffer, &info, GST_MAP_READ); -@@ -557,12 +563,12 @@ NTSTATUS wg_transform_read_data(void *args) - memcpy(read_sample->data, info.data, read_sample->size); - gst_buffer_unmap(buffer, &info); - -- if (buffer->pts != GST_CLOCK_TIME_NONE) -+ if (buffer->pts != GST_CLOCK_TIME_NONE && !broken_timestamp) - { - read_sample->flags |= WG_SAMPLE_FLAG_HAS_PTS; - read_sample->pts = buffer->pts / 100; - } -- if (buffer->duration != GST_CLOCK_TIME_NONE) -+ if (buffer->duration != GST_CLOCK_TIME_NONE && !broken_timestamp) - { - read_sample->flags |= WG_SAMPLE_FLAG_HAS_DURATION; - read_sample->duration = buffer->duration / 100; -From 700febaaa6cfa82a10625bc48e780d365aa2f006 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 8 Feb 2022 11:21:39 +0100 -Subject: [PATCH] winegstreamer: Reset internal format on BEGIN_STREAMING - message. - -In order to regenerate a MF_E_TRANSFORM_STREAM_CHANGE status on next -successful ProcessOutput. CoD: Black Ops 3 depends on this, or crashes -if MF_E_TRANSFORM_STREAM_CHANGE isn't returned when the campaign intro -video begins to play. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45988 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49715 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52183 -CW-Bug-Id: #16839 -CW-Bug-Id: #18678 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/h264_decoder.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/dlls/winegstreamer/h264_decoder.c b/dlls/winegstreamer/h264_decoder.c -index ba6e681890b..ede0bd36bce 100644 ---- a/dlls/winegstreamer/h264_decoder.c -+++ b/dlls/winegstreamer/h264_decoder.c -@@ -522,7 +522,19 @@ static HRESULT WINAPI h264_decoder_ProcessEvent(IMFTransform *iface, DWORD id, I - - static HRESULT WINAPI h264_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) - { -+ struct h264_decoder *decoder = impl_from_IMFTransform(iface); -+ - FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -+ -+ switch (message) -+ { -+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING: -+ memset(&decoder->wg_format, 0, sizeof(decoder->wg_format)); -+ break; -+ default: -+ break; -+ } -+ - return S_OK; - } - -From 36f27ef3ce2e9226724eaa4e31843ae436897217 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 Jan 2022 14:36:32 +0100 -Subject: [PATCH] winegstreamer: Reimplement AAC decoder using wg_transform. - -For Call of Duty III, possibly others. This will need to be split. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47084 -CW-Bug-Id: #19362 ---- - dlls/winegstreamer/Makefile.in | 1 + - dlls/winegstreamer/aac_decoder.c | 622 ++++++++++++++++++++++++++++++ - dlls/winegstreamer/gst_private.h | 1 + - dlls/winegstreamer/mfplat.c | 73 ++++ - dlls/winegstreamer/unixlib.h | 8 + - dlls/winegstreamer/wg_transform.c | 48 +++ - 6 files changed, 753 insertions(+) - create mode 100644 dlls/winegstreamer/aac_decoder.c - -diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in -index b8c61a316a0..71d741519f2 100644 ---- a/dlls/winegstreamer/Makefile.in -+++ b/dlls/winegstreamer/Makefile.in -@@ -7,6 +7,7 @@ EXTRAINCL = $(GSTREAMER_CFLAGS) - EXTRALIBS = $(GSTREAMER_LIBS) $(PTHREAD_LIBS) - - C_SRCS = \ -+ aac_decoder.c \ - audioconvert.c \ - h264_decoder.c \ - main.c \ -diff --git a/dlls/winegstreamer/aac_decoder.c b/dlls/winegstreamer/aac_decoder.c -new file mode 100644 -index 00000000000..3b3383a52ab ---- /dev/null -+++ b/dlls/winegstreamer/aac_decoder.c -@@ -0,0 +1,622 @@ -+/* AAC Decoder Transform -+ * -+ * 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 -+ */ -+ -+#include "gst_private.h" -+ -+#include "mfapi.h" -+#include "mferror.h" -+#include "mfobjects.h" -+#include "mftransform.h" -+#include "wmcodecdsp.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(mfplat); -+ -+static const GUID *aac_decoder_input_types[] = -+{ -+ &MFAudioFormat_AAC, -+}; -+static const GUID *aac_decoder_output_types[] = -+{ -+ &MFAudioFormat_PCM, -+ &MFAudioFormat_Float, -+}; -+ -+struct aac_decoder -+{ -+ IMFTransform IMFTransform_iface; -+ LONG refcount; -+ IMFMediaType *input_type; -+ IMFMediaType *output_type; -+ -+ IMFSample *input_sample; -+ struct wg_transform *wg_transform; -+}; -+ -+static struct aac_decoder *impl_from_IMFTransform(IMFTransform *iface) -+{ -+ return CONTAINING_RECORD(iface, struct aac_decoder, IMFTransform_iface); -+} -+ -+static void try_create_wg_transform(struct aac_decoder *decoder) -+{ -+ struct wg_encoded_format input_format; -+ struct wg_format output_format; -+ -+ if (!decoder->input_type || !decoder->output_type) -+ return; -+ -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); -+ -+ mf_media_type_to_wg_encoded_format(decoder->input_type, &input_format); -+ if (input_format.encoded_type == WG_ENCODED_TYPE_UNKNOWN) -+ return; -+ -+ mf_media_type_to_wg_format(decoder->output_type, &output_format); -+ if (output_format.major_type == WG_MAJOR_TYPE_UNKNOWN) -+ return; -+ -+ decoder->wg_transform = wg_transform_create(&input_format, &output_format); -+ if (!decoder->wg_transform) -+ WARN("Failed to create wg_transform.\n"); -+} -+ -+static HRESULT WINAPI aac_decoder_QueryInterface(IMFTransform *iface, REFIID iid, void **out) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ -+ TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); -+ -+ if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IMFTransform)) -+ *out = &decoder->IMFTransform_iface; -+ else -+ { -+ *out = NULL; -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); -+ return E_NOINTERFACE; -+ } -+ -+ IUnknown_AddRef((IUnknown *)*out); -+ return S_OK; -+} -+ -+static ULONG WINAPI aac_decoder_AddRef(IMFTransform *iface) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ ULONG refcount = InterlockedIncrement(&decoder->refcount); -+ -+ TRACE("iface %p increasing refcount to %lu.\n", decoder, refcount); -+ -+ return refcount; -+} -+ -+static ULONG WINAPI aac_decoder_Release(IMFTransform *iface) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ ULONG refcount = InterlockedDecrement(&decoder->refcount); -+ -+ TRACE("iface %p decreasing refcount to %lu.\n", decoder, refcount); -+ -+ if (!refcount) -+ { -+ if (decoder->input_sample) -+ IMFSample_Release(decoder->input_sample); -+ if (decoder->wg_transform) -+ wg_transform_destroy(decoder->wg_transform); -+ if (decoder->input_type) -+ IMFMediaType_Release(decoder->input_type); -+ if (decoder->output_type) -+ IMFMediaType_Release(decoder->output_type); -+ free(decoder); -+ } -+ -+ return refcount; -+} -+ -+static HRESULT WINAPI aac_decoder_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum, DWORD *input_maximum, -+ DWORD *output_minimum, DWORD *output_maximum) -+{ -+ FIXME("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p stub!\n", -+ iface, input_minimum, input_maximum, output_minimum, output_maximum); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs) -+{ -+ FIXME("iface %p, inputs %p, outputs %p stub!\n", iface, inputs, outputs); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs, -+ DWORD output_size, DWORD *outputs) -+{ -+ FIXME("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p stub!\n", -+ iface, input_size, inputs, output_size, outputs); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ UINT32 block_alignment; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); -+ -+ if (!decoder->input_type || !decoder->output_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) -+ return hr; -+ -+ info->hnsMaxLatency = 0; -+ info->dwFlags = MFT_INPUT_STREAM_WHOLE_SAMPLES|MFT_INPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER -+ |MFT_INPUT_STREAM_FIXED_SAMPLE_SIZE|MFT_INPUT_STREAM_HOLDS_BUFFERS; -+ info->cbSize = 0; -+ info->cbMaxLookahead = 0; -+ info->cbAlignment = 0; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ UINT32 channel_count, block_alignment; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, info %p.\n", iface, id, info); -+ -+ if (!decoder->input_type || !decoder->output_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) -+ return hr; -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->output_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment))) -+ return hr; -+ -+ info->dwFlags = 0; -+ info->cbSize = 0x1800 * block_alignment * channel_count; -+ info->cbAlignment = 0; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI aac_decoder_GetAttributes(IMFTransform *iface, IMFAttributes **attributes) -+{ -+ FIXME("iface %p, attributes %p stub!\n", iface, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, -+ IMFAttributes **attributes) -+{ -+ FIXME("iface %p, id %#lx, attributes %p stub!\n", iface, id, attributes); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_DeleteInputStream(IMFTransform *iface, DWORD id) -+{ -+ FIXME("iface %p, id %#lx stub!\n", iface, id); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids) -+{ -+ FIXME("iface %p, streams %lu, ids %p stub!\n", iface, streams, ids); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, index %#lx, type %p stub!\n", iface, id, index, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index, -+ IMFMediaType **type) -+{ -+ UINT32 channel_count, sample_size, sample_rate, block_alignment; -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaType *media_type; -+ const GUID *output_type; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type); -+ -+ if (!decoder->input_type) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *type = NULL; -+ -+ if (index >= ARRAY_SIZE(aac_decoder_output_types)) -+ return MF_E_NO_MORE_TYPES; -+ index = ARRAY_SIZE(aac_decoder_output_types) - index - 1; -+ output_type = aac_decoder_output_types[index]; -+ -+ if (FAILED(hr = MFCreateMediaType(&media_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, output_type))) -+ goto done; -+ -+ if (IsEqualGUID(output_type, &MFAudioFormat_Float)) -+ sample_size = 32; -+ else if (IsEqualGUID(output_type, &MFAudioFormat_PCM)) -+ sample_size = 16; -+ else -+ { -+ FIXME("Subtype %s not implemented!\n", debugstr_guid(output_type)); -+ hr = E_NOTIMPL; -+ goto done; -+ } -+ -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_NUM_CHANNELS, &channel_count))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaType_GetUINT32(decoder->input_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sample_rate))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, sample_rate))) -+ goto done; -+ -+ block_alignment = sample_size * channel_count / 8; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, sample_rate * block_alignment))) -+ goto done; -+ -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1))) -+ goto done; -+ if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1))) -+ goto done; -+ -+done: -+ if (SUCCEEDED(hr)) -+ IMFMediaType_AddRef((*type = media_type)); -+ -+ IMFMediaType_Release(media_type); -+ return hr; -+} -+ -+static HRESULT WINAPI aac_decoder_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ MF_ATTRIBUTE_TYPE item_type; -+ GUID major, subtype; -+ HRESULT hr; -+ ULONG i; -+ -+ TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (!IsEqualGUID(&major, &MFMediaType_Audio)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(aac_decoder_input_types); ++i) -+ if (IsEqualGUID(&subtype, aac_decoder_input_types[i])) -+ break; -+ if (i == ARRAY_SIZE(aac_decoder_input_types)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_USER_DATA, &item_type)) || -+ item_type != MF_ATTRIBUTE_BLOB) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (!decoder->input_type && FAILED(hr = MFCreateMediaType(&decoder->input_type))) -+ return hr; -+ -+ if (decoder->output_type) -+ { -+ IMFMediaType_Release(decoder->output_type); -+ decoder->output_type = NULL; -+ } -+ -+ return IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->input_type); -+} -+ -+static HRESULT WINAPI aac_decoder_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ MF_ATTRIBUTE_TYPE item_type; -+ ULONG i, sample_size; -+ GUID major, subtype; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags); -+ -+ if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) || -+ FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype))) -+ return hr; -+ -+ if (!IsEqualGUID(&major, &MFMediaType_Audio)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ for (i = 0; i < ARRAY_SIZE(aac_decoder_output_types); ++i) -+ if (IsEqualGUID(&subtype, aac_decoder_output_types[i])) -+ break; -+ if (i == ARRAY_SIZE(aac_decoder_output_types)) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (IsEqualGUID(&subtype, &MFAudioFormat_Float)) -+ sample_size = 32; -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_PCM)) -+ sample_size = 16; -+ else -+ { -+ FIXME("Subtype %s not implemented!\n", debugstr_guid(&subtype)); -+ hr = E_NOTIMPL; -+ return hr; -+ } -+ -+ if (FAILED(IMFMediaType_SetUINT32(decoder->input_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size))) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &item_type)) || -+ item_type != MF_ATTRIBUTE_UINT32) -+ return MF_E_INVALIDMEDIATYPE; -+ -+ if (!decoder->output_type && FAILED(hr = MFCreateMediaType(&decoder->output_type))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)decoder->output_type))) -+ return hr; -+ -+ try_create_wg_transform(decoder); -+ return S_OK; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type) -+{ -+ FIXME("iface %p, id %#lx, type %p stub!\n", iface, id, type); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags) -+{ -+ FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_GetOutputStatus(IMFTransform *iface, DWORD *flags) -+{ -+ FIXME("iface %p, flags %p stub!\n", iface, flags); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper) -+{ -+ FIXME("iface %p, lower %s, upper %s stub!\n", iface, -+ wine_dbgstr_longlong(lower), wine_dbgstr_longlong(upper)); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event) -+{ -+ FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI aac_decoder_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param) -+{ -+ FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param); -+ return S_OK; -+} -+ -+static HRESULT WINAPI aac_decoder_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ IMFMediaBuffer *media_buffer; -+ MFT_INPUT_STREAM_INFO info; -+ DWORD buffer_size; -+ BYTE *buffer; -+ HRESULT hr; -+ -+ TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags); -+ -+ if (FAILED(hr = IMFTransform_GetInputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ if (decoder->input_sample) -+ return MF_E_NOTACCEPTING; -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &buffer, NULL, &buffer_size))) -+ goto done; -+ -+ if (SUCCEEDED(hr = wg_transform_push_data(decoder->wg_transform, buffer, buffer_size))) -+ IMFSample_AddRef((decoder->input_sample = sample)); -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; -+} -+ -+static HRESULT WINAPI aac_decoder_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count, -+ MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status) -+{ -+ struct aac_decoder *decoder = impl_from_IMFTransform(iface); -+ struct wg_sample wg_sample = {0}; -+ IMFMediaBuffer *media_buffer; -+ MFT_OUTPUT_STREAM_INFO info; -+ DWORD buffer_size; -+ HRESULT hr; -+ -+ TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status); -+ -+ if (count > 1) -+ { -+ FIXME("Not implemented count %lu\n", count); -+ return E_NOTIMPL; -+ } -+ -+ if (FAILED(hr = IMFTransform_GetOutputStreamInfo(iface, 0, &info))) -+ return hr; -+ -+ if (!decoder->wg_transform) -+ return MF_E_TRANSFORM_TYPE_NOT_SET; -+ -+ *status = 0; -+ samples[0].dwStatus = 0; -+ if (!samples[0].pSample) -+ { -+ samples[0].dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE; -+ return MF_E_TRANSFORM_NEED_MORE_INPUT; -+ } -+ -+ if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(samples[0].pSample, &media_buffer))) -+ return hr; -+ -+ if (FAILED(hr = IMFMediaBuffer_Lock(media_buffer, &wg_sample.data, &buffer_size, NULL))) -+ goto done; -+ wg_sample.size = buffer_size; -+ -+ if (wg_sample.size < info.cbSize) -+ hr = MF_E_BUFFERTOOSMALL; -+ else if (SUCCEEDED(hr = wg_transform_read_data(decoder->wg_transform, &wg_sample))) -+ { -+ if (wg_sample.flags & WG_SAMPLE_FLAG_INCOMPLETE) -+ samples[0].dwStatus |= MFT_OUTPUT_DATA_BUFFER_INCOMPLETE; -+ } -+ else -+ { -+ if (decoder->input_sample) -+ IMFSample_Release(decoder->input_sample); -+ decoder->input_sample = NULL; -+ } -+ -+ IMFMediaBuffer_Unlock(media_buffer); -+ -+done: -+ IMFMediaBuffer_SetCurrentLength(media_buffer, wg_sample.size); -+ IMFMediaBuffer_Release(media_buffer); -+ return hr; -+} -+ -+static const IMFTransformVtbl aac_decoder_vtbl = -+{ -+ aac_decoder_QueryInterface, -+ aac_decoder_AddRef, -+ aac_decoder_Release, -+ aac_decoder_GetStreamLimits, -+ aac_decoder_GetStreamCount, -+ aac_decoder_GetStreamIDs, -+ aac_decoder_GetInputStreamInfo, -+ aac_decoder_GetOutputStreamInfo, -+ aac_decoder_GetAttributes, -+ aac_decoder_GetInputStreamAttributes, -+ aac_decoder_GetOutputStreamAttributes, -+ aac_decoder_DeleteInputStream, -+ aac_decoder_AddInputStreams, -+ aac_decoder_GetInputAvailableType, -+ aac_decoder_GetOutputAvailableType, -+ aac_decoder_SetInputType, -+ aac_decoder_SetOutputType, -+ aac_decoder_GetInputCurrentType, -+ aac_decoder_GetOutputCurrentType, -+ aac_decoder_GetInputStatus, -+ aac_decoder_GetOutputStatus, -+ aac_decoder_SetOutputBounds, -+ aac_decoder_ProcessEvent, -+ aac_decoder_ProcessMessage, -+ aac_decoder_ProcessInput, -+ aac_decoder_ProcessOutput, -+}; -+ -+HRESULT aac_decoder_create(REFIID riid, void **ret) -+{ -+ struct aac_decoder *decoder; -+ -+ TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret); -+ -+ if (!(decoder = calloc(1, sizeof(*decoder)))) -+ return E_OUTOFMEMORY; -+ -+ decoder->IMFTransform_iface.lpVtbl = &aac_decoder_vtbl; -+ decoder->refcount = 1; -+ -+ *ret = &decoder->IMFTransform_iface; -+ TRACE("Created decoder %p\n", *ret); -+ return S_OK; -+} -diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h -index 7a0078fe2f4..70ba964a917 100644 ---- a/dlls/winegstreamer/gst_private.h -+++ b/dlls/winegstreamer/gst_private.h -@@ -124,6 +124,7 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - - HRESULT winegstreamer_stream_handler_create(REFIID riid, void **obj); - -+HRESULT aac_decoder_create(REFIID riid, void **ret); - HRESULT h264_decoder_create(REFIID riid, void **ret); - HRESULT audio_converter_create(REFIID riid, void **ret); - -diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c -index 4ff174a2083..008e95d46bf 100644 ---- a/dlls/winegstreamer/mfplat.c -+++ b/dlls/winegstreamer/mfplat.c -@@ -30,6 +30,7 @@ - WINE_DEFAULT_DEBUG_CHANNEL(mfplat); - - DEFINE_MEDIATYPE_GUID(MFAudioFormat_XMAudio2, 0x0166); -+DEFINE_MEDIATYPE_GUID(MFAudioFormat_RAW_AAC, WAVE_FORMAT_RAW_AAC1); - - struct video_processor - { -@@ -446,6 +448,19 @@ static const GUID *const audio_converter_supported_types[] = - &MFAudioFormat_Float, - }; - -+static WCHAR aac_decoderW[] = L"AAC Audio Decoder MFT"; -+static const GUID *aac_decoder_input_types[] = -+{ -+ &MFAudioFormat_AAC, -+ &MFAudioFormat_RAW_AAC, -+ &MFAudioFormat_ADTS, -+}; -+static const GUID *aac_decoder_output_types[] = -+{ -+ &MFAudioFormat_Float, -+ &MFAudioFormat_PCM, -+}; -+ - static WCHAR wma_decoderW[] = L"WMAudio Decoder MFT"; - static const GUID *const wma_decoder_input_types[] = - { -@@ -500,6 +515,17 @@ mfts[] = - ARRAY_SIZE(audio_converter_supported_types), - audio_converter_supported_types, - }, -+ { -+ &CLSID_MSAACDecMFT, -+ &MFT_CATEGORY_AUDIO_DECODER, -+ aac_decoderW, -+ MFT_ENUM_FLAG_SYNCMFT, -+ &MFMediaType_Audio, -+ ARRAY_SIZE(aac_decoder_input_types), -+ aac_decoder_input_types, -+ ARRAY_SIZE(aac_decoder_output_types), -+ aac_decoder_output_types, -+ }, - { - &CLSID_WMADecMediaObject, - &MFT_CATEGORY_AUDIO_DECODER, -@@ -838,6 +864,51 @@ static void mf_media_type_to_wg_encoded_format_xwma(IMFMediaType *type, struct w - memcpy(format->u.xwma.codec_data, codec_data, codec_data_len); - } - -+static void mf_media_type_to_wg_encoded_format_aac(IMFMediaType *type, struct wg_encoded_format *format) -+{ -+ UINT32 codec_data_len, payload_type, profile_level_indication; -+ BYTE codec_data[64]; -+ -+ /* Audio specific config is stored at after HEAACWAVEINFO in MF_MT_USER_DATA -+ * https://docs.microsoft.com/en-us/windows/win32/api/mmreg/ns-mmreg-heaacwaveformat -+ */ -+ struct -+ { -+ WORD payload_type; -+ WORD profile_level_indication; -+ WORD type; -+ WORD reserved1; -+ DWORD reserved2; -+ } *aac_info = (void *)codec_data; -+ -+ if (FAILED(IMFMediaType_GetBlob(type, &MF_MT_USER_DATA, codec_data, sizeof(codec_data), &codec_data_len))) -+ { -+ FIXME("Codec data is not set.\n"); -+ return; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_PAYLOAD_TYPE, &payload_type))) -+ { -+ FIXME("AAC payload type is not set.\n"); -+ payload_type = aac_info->payload_type; -+ } -+ if (FAILED(IMFMediaType_GetUINT32(type, &MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION, &profile_level_indication))) -+ { -+ FIXME("AAC provile level indication is not set.\n"); -+ profile_level_indication = aac_info->profile_level_indication; -+ } -+ -+ format->encoded_type = WG_ENCODED_TYPE_AAC; -+ format->u.aac.payload_type = payload_type; -+ format->u.aac.profile_level_indication = profile_level_indication; -+ format->u.aac.codec_data_len = 0; -+ -+ if (codec_data_len > sizeof(*aac_info)) -+ { -+ format->u.aac.codec_data_len = codec_data_len - sizeof(*aac_info); -+ memcpy(format->u.aac.codec_data, codec_data + sizeof(*aac_info), codec_data_len - sizeof(*aac_info)); -+ } -+} -+ - static void mf_media_type_to_wg_encoded_format_h264(IMFMediaType *type, struct wg_encoded_format *format) - { - UINT64 frame_rate, frame_size; -@@ -897,6 +968,8 @@ void mf_media_type_to_wg_encoded_format(IMFMediaType *type, struct wg_encoded_fo - mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_WMA, 4); - else if (IsEqualGUID(&subtype, &MFAudioFormat_XMAudio2)) - mf_media_type_to_wg_encoded_format_xwma(type, format, WG_ENCODED_TYPE_XMA, 2); -+ else if (IsEqualGUID(&subtype, &MFAudioFormat_AAC)) -+ mf_media_type_to_wg_encoded_format_aac(type, format); - else - FIXME("Unimplemented audio subtype %s.\n", debugstr_guid(&subtype)); - } -diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h -index 2e9625fed4e..1566748def5 100644 ---- a/dlls/winegstreamer/unixlib.h -+++ b/dlls/winegstreamer/unixlib.h -@@ -98,6 +98,7 @@ struct wg_encoded_format - WG_ENCODED_TYPE_UNKNOWN, - WG_ENCODED_TYPE_WMA, - WG_ENCODED_TYPE_XMA, -+ WG_ENCODED_TYPE_AAC, - WG_ENCODED_TYPE_H264, - } encoded_type; - -@@ -115,6 +116,13 @@ struct wg_encoded_format - unsigned char codec_data[64]; - } xwma; - struct -+ { -+ uint32_t payload_type; -+ uint32_t profile_level_indication; -+ uint32_t codec_data_len; -+ unsigned char codec_data[64]; -+ } aac; -+ struct - { - int32_t width, height; - uint32_t fps_n, fps_d; -diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c -index 1c9dc6f72bb..775ac14e6a5 100644 ---- a/dlls/winegstreamer/wg_transform.c -+++ b/dlls/winegstreamer/wg_transform.c -@@ -99,6 +99,52 @@ static GstCaps *wg_format_to_caps_xwma(const struct wg_encoded_format *format) - return caps; - } - -+static GstCaps *wg_format_to_caps_aac(const struct wg_encoded_format *format) -+{ -+ const char *profile, *level, *stream_format; -+ GstBuffer *buffer; -+ GstCaps *caps; -+ -+ caps = gst_caps_new_empty_simple("audio/mpeg"); -+ gst_caps_set_simple(caps, "mpegversion", G_TYPE_INT, 4, NULL); -+ -+ switch (format->u.aac.payload_type) -+ { -+ case 0: stream_format = "raw"; break; -+ case 1: stream_format = "adts"; break; -+ case 2: stream_format = "adif"; break; -+ case 3: stream_format = "loas"; break; -+ default: stream_format = "raw"; break; -+ } -+ if (stream_format) -+ gst_caps_set_simple(caps, "stream-format", G_TYPE_STRING, stream_format, NULL); -+ -+ switch (format->u.aac.profile_level_indication) -+ { -+ case 0x29: profile = "lc"; level = "2"; break; -+ case 0x2A: profile = "lc"; level = "4"; break; -+ case 0x2B: profile = "lc"; level = "5"; break; -+ default: -+ GST_FIXME("Unrecognized profile-level-indication %u\n", format->u.aac.profile_level_indication); -+ /* fallthrough */ -+ case 0x00: case 0xFE: profile = level = NULL; break; /* unspecified */ -+ } -+ if (profile) -+ gst_caps_set_simple(caps, "profile", G_TYPE_STRING, profile, NULL); -+ if (level) -+ gst_caps_set_simple(caps, "level", G_TYPE_STRING, level, NULL); -+ -+ if (format->u.aac.codec_data_len) -+ { -+ buffer = gst_buffer_new_and_alloc(format->u.aac.codec_data_len); -+ gst_buffer_fill(buffer, 0, format->u.aac.codec_data, format->u.aac.codec_data_len); -+ gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL); -+ gst_buffer_unref(buffer); -+ } -+ -+ return caps; -+} -+ - static GstCaps *wg_format_to_caps_h264(const struct wg_encoded_format *format) - { - const char *profile, *level; -@@ -166,6 +212,8 @@ static GstCaps *wg_encoded_format_to_caps(const struct wg_encoded_format *format - case WG_ENCODED_TYPE_WMA: - case WG_ENCODED_TYPE_XMA: - return wg_format_to_caps_xwma(format); -+ case WG_ENCODED_TYPE_AAC: -+ return wg_format_to_caps_aac(format); - case WG_ENCODED_TYPE_H264: - return wg_format_to_caps_h264(format); - } -From 7ec3158fe73bbe005f18c67f4c2c6c0f9dd14334 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 24 Jan 2022 00:46:03 -0500 -Subject: [PATCH] winegstreamer: After failing to create decodebin parser, try - protonvideoconv. - ---- - dlls/winegstreamer/wg_parser.c | 69 +++++++++++++++++++++++++++++++++- - 1 file changed, 68 insertions(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 0db0519ff98..178c47d5d32 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -91,6 +91,8 @@ struct wg_parser - - bool unlimited_buffering; - struct wg_format input_format; -+ -+ bool use_mediaconv; - }; - - struct wg_parser_stream -@@ -943,6 +945,34 @@ static GstAutoplugSelectResult autoplug_select_cb(GstElement *bin, GstPad *pad, - return GST_AUTOPLUG_SELECT_TRY; - } - -+static gint find_videoconv_cb(gconstpointer a, gconstpointer b) -+{ -+ const GValue *val_a = a, *val_b = b; -+ GstElementFactory *factory_a = g_value_get_object(val_a), *factory_b = g_value_get_object(val_b); -+ const char *name_a = gst_element_factory_get_longname(factory_a), *name_b = gst_element_factory_get_longname(factory_b); -+ -+ if (!strcmp(name_a, "Proton video converter")) -+ return -1; -+ if (!strcmp(name_b, "Proton video converter")) -+ return 1; -+ return 0; -+} -+ -+static GValueArray *autoplug_sort_cb(GstElement *bin, GstPad *pad, -+ GstCaps *caps, GValueArray *factories, gpointer user) -+{ -+ struct wg_parser *parser = user; -+ GValueArray *ret = g_value_array_copy(factories); -+ -+ if (!parser->use_mediaconv) -+ return NULL; -+ -+ GST_DEBUG("parser %p.", parser); -+ -+ g_value_array_sort(ret, find_videoconv_cb); -+ return ret; -+} -+ - static void no_more_pads_cb(GstElement *element, gpointer user) - { - struct wg_parser *parser = user; -@@ -1801,9 +1831,12 @@ static gboolean src_activate_mode_cb(GstPad *pad, GstObject *parent, GstPadMode - return FALSE; - } - -+static BOOL decodebin_parser_init_gst(struct wg_parser *parser); -+ - static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer user) - { - struct wg_parser *parser = user; -+ const GstStructure *structure; - gchar *dbg_info = NULL; - GError *err = NULL; - -@@ -1838,6 +1871,21 @@ static GstBusSyncReply bus_handler_cb(GstBus *bus, GstMessage *msg, gpointer use - pthread_cond_signal(&parser->init_cond); - break; - -+ case GST_MESSAGE_ELEMENT: -+ structure = gst_message_get_structure(msg); -+ if (gst_structure_has_name(structure, "missing-plugin")) -+ { -+ pthread_mutex_lock(&parser->mutex); -+ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) -+ { -+ GST_WARNING("Autoplugged element failed to initialise, trying again with protonvideoconvert."); -+ parser->error = true; -+ pthread_cond_signal(&parser->init_cond); -+ } -+ pthread_mutex_unlock(&parser->mutex); -+ } -+ break; -+ - default: - break; - } -@@ -1976,6 +2024,7 @@ static NTSTATUS wg_parser_connect(void *args) - { - const struct wg_parser_connect_params *params = args; - struct wg_parser *parser = params->parser; -+ bool use_mediaconv = false; - unsigned int i; - HRESULT hr; - int ret; -@@ -1993,9 +2042,16 @@ static NTSTATUS wg_parser_connect(void *args) - if (!parser->pull_mode) - gst_pad_set_active(parser->my_src, 1); - ret = gst_element_get_state(parser->container, NULL, NULL, -1); -+ - if (ret == GST_STATE_CHANGE_FAILURE) - { -- GST_ERROR("Failed to play stream.\n"); -+ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst && parser->pull_mode) -+ { -+ GST_WARNING("Failed to play media, trying again with protonvideoconvert."); -+ use_mediaconv = true; -+ } -+ else -+ GST_ERROR("Failed to play stream.\n"); - goto out; - } - -@@ -2005,6 +2061,8 @@ static NTSTATUS wg_parser_connect(void *args) - pthread_cond_wait(&parser->init_cond, &parser->mutex); - if (parser->error) - { -+ if (!parser->use_mediaconv && parser->init_gst == decodebin_parser_init_gst) -+ use_mediaconv = true; - pthread_mutex_unlock(&parser->mutex); - goto out; - } -@@ -2113,6 +2171,14 @@ static NTSTATUS wg_parser_connect(void *args) - pthread_mutex_unlock(&parser->mutex); - pthread_cond_signal(&parser->read_cond); - -+ if (use_mediaconv) -+ { -+ parser->use_mediaconv = true; -+ hr = wg_parser_connect(args); -+ parser->use_mediaconv = false; -+ return hr; -+ } -+ - return E_FAIL; - } - -@@ -2227,6 +2293,7 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) - g_signal_connect(element, "pad-added", G_CALLBACK(pad_added_cb), parser); - g_signal_connect(element, "pad-removed", G_CALLBACK(pad_removed_cb), parser); - g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); -+ g_signal_connect(element, "autoplug-sort", G_CALLBACK(autoplug_sort_cb), parser); - g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); - - parser->their_sink = gst_element_get_static_pad(element, "sink"); -From 62f18137cb5ff9b468079d7d1f26a512bdb66c90 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 15 Feb 2022 10:51:42 +0100 -Subject: [PATCH] fixup! winegstreamer: After failing to create decodebin - parser, try protonvideoconv. - ---- - dlls/winegstreamer/wg_parser.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 89a64339413..337953db78d 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -30,6 +30,7 @@ - #include - #include - -+#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_30 - #include - #include - #include -From 90c099fcb690675226493994c445df025ad00076 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Mon, 7 Feb 2022 17:19:31 -0600 -Subject: [PATCH] winegstreamer: Release stream_cs on error in stream_thread(). - -This fixes a deadlock when trying to skip video in Persona 4 Golden. - -Signed-off-by: Zebediah Figura -Signed-off-by: Alexandre Julliard -(cherry picked from commit fc5719e4c57079b19bde8d169bf0b55194649e73) ---- - dlls/winegstreamer/wm_asyncreader.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/winegstreamer/wm_asyncreader.c b/dlls/winegstreamer/wm_asyncreader.c -index aa15a5a77f9..12b63cd4ac1 100644 ---- a/dlls/winegstreamer/wm_asyncreader.c -+++ b/dlls/winegstreamer/wm_asyncreader.c -@@ -146,6 +146,7 @@ static DWORD WINAPI stream_thread(void *arg) - else if (hr != NS_E_NO_MORE_SAMPLES) - { - ERR("Failed to get sample, hr %#lx.\n", hr); -+ LeaveCriticalSection(&reader->stream_cs); - return 0; - } - } -From e55e47086014d7a7be94da17b4be7cf312e8ad80 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Fri, 4 Feb 2022 16:44:54 -0600 -Subject: [PATCH] HACK: winegstreamer: Report BGRx for Persona 4 Golden. - ---- - dlls/winegstreamer/wm_reader.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index ab49045ddab..8d004662599 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -1508,6 +1508,17 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) - * Shadowgrounds provides wmv3 video and assumes that the initial - * video type will be BGR. */ - stream->format.u.video.format = WG_VIDEO_FORMAT_BGR; -+ { -+ /* HACK: Persona 4 Golden tries to read compressed samples, and -+ * then autoplug them via quartz to a filter that only accepts -+ * BGRx. This is not trivial to implement. Return BGRx from the -+ * wmvcore reader for now. */ -+ -+ const char *id = getenv("SteamGameId"); -+ -+ if (id && !strcmp(id, "1113000")) -+ stream->format.u.video.format = WG_VIDEO_FORMAT_BGRx; -+ } - } - wg_parser_stream_enable(stream->wg_stream, &stream->format, NULL); - } -From 3e920115088e5320e7615ccb3fbe8403cc41e497 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Thu, 28 Oct 2021 17:46:32 -0500 -Subject: [PATCH] winegstreamer: Use unlimited buffering for the WM reader - objects. - ---- - dlls/winegstreamer/wm_reader.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index 8d004662599..594b16e318b 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -1455,7 +1455,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) - HRESULT hr; - WORD i; - -- if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, false))) -+ if (!(wg_parser = wg_parser_create(WG_PARSER_DECODEBIN, true))) - return E_OUTOFMEMORY; - - reader->wg_parser = wg_parser; -From fbf46aeef3db5b3a9a58441ab6fd62501c183afb Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Thu, 28 Oct 2021 17:47:48 -0500 -Subject: [PATCH] HACK: winegstreamer: Report streams in reverse order for - wmvcore. - ---- - dlls/winegstreamer/wm_reader.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winegstreamer/wm_reader.c b/dlls/winegstreamer/wm_reader.c -index 594b16e318b..905ce7306c8 100644 ---- a/dlls/winegstreamer/wm_reader.c -+++ b/dlls/winegstreamer/wm_reader.c -@@ -1484,7 +1484,7 @@ static HRESULT init_stream(struct wm_reader *reader, QWORD file_size) - { - struct wm_stream *stream = &reader->streams[i]; - -- stream->wg_stream = wg_parser_get_stream(reader->wg_parser, i); -+ stream->wg_stream = wg_parser_get_stream(reader->wg_parser, reader->stream_count - i - 1); - stream->reader = reader; - stream->index = i; - stream->selection = WMT_ON; -From a85f7beb182e020211e653312c5b954b7c754b78 Mon Sep 17 00:00:00 2001 -From: Thomas Crider -Date: Wed, 23 Feb 2022 01:30:09 -0700 -Subject: [PATCH] winegstreamer: remove WG_PARSER_EVENT_SEGMENT in colorconvert - due to removal in commit f51b2ca - ---- - dlls/winegstreamer/colorconvert.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/dlls/winegstreamer/colorconvert.c b/dlls/winegstreamer/colorconvert.c -index 476851fa43a..aeb103592e7 100644 ---- a/dlls/winegstreamer/colorconvert.c -+++ b/dlls/winegstreamer/colorconvert.c -@@ -760,9 +760,6 @@ static HRESULT WINAPI color_converter_ProcessOutput(IMFTransform *iface, DWORD f - case WG_PARSER_EVENT_BUFFER: - break; - -- case WG_PARSER_EVENT_SEGMENT: -- continue; -- - default: - WARN("Unexpected event, %u\n", event.type); - continue; --- -2.35.1 - -From 3f6c3ed368ab02ef9f90a0bd2174d8c6e790b789 Mon Sep 17 00:00:00 2001 -From: Thomas Crider -Date: Wed, 23 Feb 2022 01:40:23 -0700 -Subject: [PATCH] winegstreamer: remove WG_PARSER_EVENT_SEGMENT in audioconvert - due to removal in commit f51b2ca - ---- - dlls/winegstreamer/audioconvert.c | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/dlls/winegstreamer/audioconvert.c b/dlls/winegstreamer/audioconvert.c -index 58daf388a30..e8a4ad0a096 100644 ---- a/dlls/winegstreamer/audioconvert.c -+++ b/dlls/winegstreamer/audioconvert.c -@@ -756,9 +756,6 @@ static HRESULT WINAPI audio_converter_ProcessOutput(IMFTransform *iface, DWORD f - case WG_PARSER_EVENT_BUFFER: - break; - -- case WG_PARSER_EVENT_SEGMENT: -- continue; -- - default: - WARN("Unexpected event, %lu\n", event.type); - continue; --- -2.35.1 - diff --git a/patches/proton/32-proton-05_spellforce_registry.patch b/patches/proton/32-proton-05_spellforce_registry.patch deleted file mode 100644 index 0efa29f46..000000000 --- a/patches/proton/32-proton-05_spellforce_registry.patch +++ /dev/null @@ -1,21 +0,0 @@ -From ae37e82a735b0d3b44ba21fc56be0977372d8451 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 6 Nov 2020 11:54:47 -0600 -Subject: [PATCH] wine.inf: Limit resolution count for SpellForce to 16 - ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index e2efcce2a31..09f0aad8688 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4017,6 +4017,7 @@ HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin, - HKCU,Software\Wine\AppDefaults\DarkSoulsIII.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" - HKCU,Software\Wine\AppDefaults\sekiro.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" - HKCU,Software\Wine\AppDefaults\NieRAutomata.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"32" -+HKCU,Software\Wine\AppDefaults\SpellForce.exe\X11 Driver,"LimitNumberOfResolutions",0x2,"16" - HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\s2_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\h1_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" diff --git a/patches/proton/33-proton-06_shadow_of_war_registry.patch b/patches/proton/33-proton-06_shadow_of_war_registry.patch deleted file mode 100644 index b8f1f42aa..000000000 --- a/patches/proton/33-proton-06_shadow_of_war_registry.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 6ca9ae70bb9f09b6bc5d9f26e0a710a8691199e3 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Tue, 13 Oct 2020 18:20:39 +0300 -Subject: [PATCH] HACK: wine.inf: Enable atiadlxx and disable ags for Shadow of - War - -With the recent stubs game is able to use our atiadlxx without crashing. -This helps with getting the resolution list populated with AMD GPUs. - -AGS has to be force disabled - the dll ships with the game and uses a -bunch of more complex ADL2 calls that remain unimplemented. The game -works fine if the DLL is not found. ---- - loader/wine.inf.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 8c1742a95e7..e2efcce2a31 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4021,6 +4021,8 @@ HKCU,Software\Wine\AppDefaults\s2_sp64_ship.exe\DllOverrides,"atiadlxx",,"builti - HKCU,Software\Wine\AppDefaults\h1_sp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\iw7_ship.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"amd_ags_x64",,"" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" diff --git a/patches/proton/34-proton-winegstreamer_updates.patch b/patches/proton/34-proton-winegstreamer_updates.patch deleted file mode 100644 index a7bfcbc54..000000000 --- a/patches/proton/34-proton-winegstreamer_updates.patch +++ /dev/null @@ -1,214 +0,0 @@ -From c099ae745b3a63edee1677a2da01cab5aa5b8562 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Tue, 28 Jan 2020 14:30:43 -0600 -Subject: [PATCH] winegstreamer: HACK: Try harder to register winegstreamer - filters. - -The IDL declarations should actually be unnecessary with the quartz part, but there's a chance that an application will try to create filters before it creates the graph. ---- - dlls/quartz/filtergraph.c | 17 +++++++++++++++++ - dlls/winegstreamer/winegstreamer_classes.idl | 21 +++++++++++++++++++++ - 2 files changed, 38 insertions(+) - -diff --git a/dlls/quartz/filtergraph.c b/dlls/quartz/filtergraph.c -index 1ed41bdcec5..0af6e1ded5f 100644 ---- a/dlls/quartz/filtergraph.c -+++ b/dlls/quartz/filtergraph.c -@@ -5681,11 +5681,28 @@ static const IUnknownVtbl IInner_VTable = - FilterGraphInner_Release - }; - -+static BOOL CALLBACK register_winegstreamer_proc(INIT_ONCE *once, void *param, void **ctx) -+{ -+ HMODULE mod = LoadLibraryW(L"winegstreamer.dll"); -+ if (mod) -+ { -+ HRESULT (WINAPI *proc)(void) = (void *)GetProcAddress(mod, "DllRegisterServer"); -+ proc(); -+ FreeLibrary(mod); -+ } -+ return TRUE; -+} -+ - static HRESULT filter_graph_common_create(IUnknown *outer, IUnknown **out, BOOL threaded) - { -+ static INIT_ONCE once = INIT_ONCE_STATIC_INIT; - struct filter_graph *object; - HRESULT hr; - -+ /* HACK: our build system makes it difficult to load gstreamer on prefix -+ * creation, so it won't get registered. Do that here instead. */ -+ InitOnceExecuteOnce(&once, register_winegstreamer_proc, NULL, NULL); -+ - *out = NULL; - - fimpl = CoTaskMemAlloc(sizeof(*fimpl)); - -From eddbdd21c623bd041962fe4f91733c6696188d89 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Tue, 11 Aug 2020 14:03:20 -0500 -Subject: [PATCH] HACK: winegstreamer: Increase decodebin internal buffering - -This helps choppy audio due to OGG frame decoding seen in Worms -Revolution and BlazBlue Centralfiction. ---- - dlls/winegstreamer/wg_parser.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 2d4d4f46327..2629df78ed1 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1615,6 +1615,10 @@ static BOOL decodebin_parser_init_gst(struct wg_parser *parser) - g_signal_connect(element, "autoplug-select", G_CALLBACK(autoplug_select_cb), parser); - g_signal_connect(element, "no-more-pads", G_CALLBACK(no_more_pads_cb), parser); - -+ g_object_set(G_OBJECT(element), "max-size-buffers", G_MAXUINT, NULL); -+ g_object_set(G_OBJECT(element), "max-size-time", G_MAXUINT64, NULL); -+ g_object_set(G_OBJECT(element), "max-size-bytes", G_MAXUINT, NULL); -+ - parser->their_sink = gst_element_get_static_pad(element, "sink"); - - pthread_mutex_lock(&parser->mutex); -From afc22791db23d52c13b7f7cbb3eeacde21b381ed Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Wed, 21 Oct 2020 16:03:21 -0500 -Subject: [PATCH] winegstreamer: Allow videoconvert to parallelize. - -Not sure if this should be called a hack. It's not the *best* solution to the problem, but it's not a wrong one either. - -Signed-off-by: Zebediah Figura ---- - dlls/winegstreamer/wg_parser.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index 2629df78ed1..a625f000254 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1029,6 +1029,9 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - goto out; - } - -+ /* Let GStreamer choose a default number of threads. */ -+ gst_util_set_object_arg(G_OBJECT(vconv), "n-threads", "0"); -+ - /* GStreamer outputs RGB video top-down, but DirectShow expects bottom-up. */ - if (!(flip = gst_element_factory_make("videoflip", NULL))) - { -From aa52473db040db290296cd65191f87c831bf2878 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Tue, 20 Oct 2020 17:03:24 -0500 -Subject: [PATCH] HACK: winegstreamer: Use capssetter to ignore non-default YUV - color spaces. - ---- - dlls/winegstreamer/wg_parser.c | 53 ++++++++++++++++++++++++++++++++-- - 1 file changed, 51 insertions(+), 2 deletions(-) - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index a625f000254..be27b00cfd0 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -1293,7 +1293,17 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - - if (!strcmp(name, "video/x-raw")) - { -- GstElement *deinterlace, *vconv, *flip, *videobox, *vconv2; -+ GstElement *capssetter, *deinterlace, *vconv, *flip, *videobox, *vconv2; -+ /* Hack?: Flatten down the colorimetry to default values, without -+ * actually modifying the video at all.*/ -+ if (!(capssetter = gst_element_factory_make("capssetter", NULL))) -+ { -+ GST_ERROR("Failed to create capssetter, are %u-bit GStreamer \"good\" plugins installed?\n", -+ 8 * (int)sizeof(void *)); -+ goto out; -+ } -+ gst_util_set_object_arg(G_OBJECT(capssetter), "join", "true"); -+ gst_util_set_object_arg(G_OBJECT(capssetter), "caps", "video/x-raw,colorimetry=0:0:0:0"); - - /* DirectShow can express interlaced video, but downstream filters can't - * necessarily consume it. In particular, the video renderer can't. */ -@@ -1050,6 +1096,8 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - } - - /* The bin takes ownership of these elements. */ -+ gst_bin_add(GST_BIN(parser->container), capssetter); -+ gst_element_sync_state_with_parent(capssetter); - gst_bin_add(GST_BIN(parser->container), deinterlace); - gst_element_sync_state_with_parent(deinterlace); - gst_bin_add(GST_BIN(parser->container), vconv); -@@ -1373,6 +1383,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - gst_bin_add(GST_BIN(parser->container), vconv2); - gst_element_sync_state_with_parent(vconv2); - -+ gst_element_link(capssetter, deinterlace); - gst_element_link(deinterlace, vconv); - gst_element_link(vconv, flip); - if (videobox) -@@ -1385,7 +1396,7 @@ static void pad_added_cb(GstElement *element, GstPad *pad, gpointer user) - gst_element_link(flip, vconv2); - } - -- stream->post_sink = gst_element_get_static_pad(deinterlace, "sink"); -+ stream->post_sink = gst_element_get_static_pad(capssetter, "sink"); - stream->post_src = gst_element_get_static_pad(vconv2, "src"); - stream->flip = flip; - stream->box = videobox; - -From 03891654faf9271d81240faf9cd4f471ca5832f9 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 12 Nov 2021 16:35:52 +0100 -Subject: [PATCH] winegstreamer: Unblock initializing parser on disconnect. - -The decoder may be destroyed while the parsed is still initializing and -we need to notify it, before closing the helper and reader threads, so -that it terminates as well. - -This fixes Biomutant intro videos not playing. - -CW-Bug-ID: #18970 -CW-Bug-ID: #19608 ---- - dlls/winegstreamer/decode_transform.c | 5 ++--- - dlls/winegstreamer/wg_parser.c | 4 ++++ - 2 files changed, 6 insertions(+), 3 deletions(-) - -diff --git a/dlls/winegstreamer/decode_transform.c b/dlls/winegstreamer/decode_transform.c -index 64e1c84b2ba..b676249cf52 100644 ---- a/dlls/winegstreamer/decode_transform.c -+++ b/dlls/winegstreamer/decode_transform.c -@@ -157,11 +157,11 @@ static ULONG WINAPI mf_decoder_Release(IMFTransform *iface) - decoder->output_type = NULL; - } - -- if (decoder->wg_stream) -- unix_funcs->wg_parser_disconnect(decoder->wg_parser); -- - if (decoder->wg_parser) -+ { -+ unix_funcs->wg_parser_disconnect(decoder->wg_parser); - unix_funcs->wg_parser_destroy(decoder->wg_parser); -+ } - - DeleteCriticalSection(&decoder->cs); - DeleteCriticalSection(&decoder->help_cs); - -diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c -index c23500869ce..751282cb8d4 100644 ---- a/dlls/winegstreamer/wg_parser.c -+++ b/dlls/winegstreamer/wg_parser.c -@@ -2207,9 +2207,13 @@ static void CDECL wg_parser_disconnect(struct wg_parser *parser) - - /* Unblock all of our streams. */ - pthread_mutex_lock(&parser->mutex); -+ parser->flushing = true; -+ parser->no_more_pads = true; -+ pthread_cond_signal(&parser->init_cond); - for (i = 0; i < parser->stream_count; ++i) - { - parser->streams[i]->flushing = true; -+ pthread_cond_signal(&parser->streams[i]->event_cond); - pthread_cond_signal(&parser->streams[i]->event_empty_cond); - } - pthread_mutex_unlock(&parser->mutex); diff --git a/patches/proton/37-proton-OpenXR-patches.patch b/patches/proton/37-proton-OpenXR-patches.patch deleted file mode 100644 index 90f6ac8bf..000000000 --- a/patches/proton/37-proton-OpenXR-patches.patch +++ /dev/null @@ -1,684 +0,0 @@ -From 7c78c4bb595cc1ab37a7ecaf1d7be34d64f82cdf Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Sat, 11 Dec 2021 12:23:17 +0100 -Subject: [PATCH] winevulkan: Add struct unwrappers for vrclient. - ---- - dlls/winevulkan/loader.c | 25 +++++++++++++++++++++++++ - dlls/winevulkan/make_vulkan | 10 ++++++++++ - dlls/winevulkan/vulkan.c | 31 +++++++++++++++++++++++++++++++ - dlls/winevulkan/vulkan_loader.h | 6 ++++++ - dlls/winevulkan/vulkan_private.h | 6 ++++++ - 5 files changed, 78 insertions(+) - -diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c -index 3fa334d2a3e..4821b132cfe 100644 ---- a/dlls/winevulkan/loader.c -+++ b/dlls/winevulkan/loader.c -@@ -405,6 +405,31 @@ static BOOL WINAPI call_vulkan_debug_utils_callback( struct wine_vk_debug_utils_ - return params->user_callback(params->severity, params->message_types, ¶ms->data, params->user_data); - } - -+VkDevice WINAPI __wine_get_native_VkDevice(VkDevice device) -+{ -+ return unix_funcs->p_wine_get_native_VkDevice(device); -+} -+ -+VkInstance WINAPI __wine_get_native_VkInstance(VkInstance instance) -+{ -+ return unix_funcs->p_wine_get_native_VkInstance(instance); -+} -+ -+VkPhysicalDevice WINAPI __wine_get_native_VkPhysicalDevice(VkPhysicalDevice phys_dev) -+{ -+ return unix_funcs->p_wine_get_native_VkPhysicalDevice(phys_dev); -+} -+ -+VkQueue WINAPI __wine_get_native_VkQueue(VkQueue queue) -+{ -+ return unix_funcs->p_wine_get_native_VkQueue(queue); -+} -+ -+VkPhysicalDevice WINAPI __wine_get_wrapped_VkPhysicalDevice(VkInstance instance, VkPhysicalDevice native_phys_dev) -+{ -+ return unix_funcs->p_wine_get_wrapped_VkPhysicalDevice(instance, native_phys_dev); -+} -+ - BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved) - { - void **kernel_callback_table; -diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan -index e9b1b456584..7fc4412fdfd 100755 ---- a/dlls/winevulkan/make_vulkan -+++ b/dlls/winevulkan/make_vulkan -@@ -2847,6 +2847,11 @@ class VkGenerator(object): - f.write(" wine_vk_call,\n") - f.write(" wine_vk_is_available_instance_function,\n") - f.write(" wine_vk_is_available_device_function,\n") -+ f.write(" __wine_get_native_VkDevice,\n") -+ f.write(" __wine_get_native_VkInstance,\n") -+ f.write(" __wine_get_native_VkPhysicalDevice,\n") -+ f.write(" __wine_get_native_VkQueue,\n") -+ f.write(" __wine_get_wrapped_VkPhysicalDevice,\n") - f.write("};\n") - - def generate_thunks_h(self, f, prefix): -@@ -3229,6 +3234,11 @@ class VkGenerator(object): - f.write("@ stdcall -private vk_icdGetInstanceProcAddr(ptr str)\n") - f.write("@ stdcall -private vk_icdGetPhysicalDeviceProcAddr(ptr str)\n") - f.write("@ stdcall -private vk_icdNegotiateLoaderICDInterfaceVersion(ptr)\n") -+ f.write("@ stdcall __wine_get_native_VkDevice(ptr)\n") -+ f.write("@ stdcall __wine_get_native_VkInstance(ptr)\n") -+ f.write("@ stdcall __wine_get_native_VkPhysicalDevice(ptr)\n") -+ f.write("@ stdcall __wine_get_native_VkQueue(ptr)\n") -+ f.write("@ stdcall __wine_get_wrapped_VkPhysicalDevice(ptr ptr)\n") - - # Export symbols for all Vulkan Core functions. - for func in self.registry.funcs.values(): -diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c -index 638ca3a7a41..81c2feff36e 100644 ---- a/dlls/winevulkan/vulkan.c -+++ b/dlls/winevulkan/vulkan.c -@@ -1767,3 +1767,34 @@ BOOL WINAPI wine_vk_is_available_device_function(VkDevice device, const char *na - { - return !!vk_funcs->p_vkGetDeviceProcAddr(device->device, name); - } -+ -+VkDevice WINAPI __wine_get_native_VkDevice(VkDevice device) -+{ -+ return device->device; -+} -+ -+VkInstance WINAPI __wine_get_native_VkInstance(VkInstance instance) -+{ -+ return instance->instance; -+} -+ -+VkPhysicalDevice WINAPI __wine_get_native_VkPhysicalDevice(VkPhysicalDevice phys_dev) -+{ -+ return phys_dev->phys_dev; -+} -+ -+VkQueue WINAPI __wine_get_native_VkQueue(VkQueue queue) -+{ -+ return queue->queue; -+} -+ -+VkPhysicalDevice WINAPI __wine_get_wrapped_VkPhysicalDevice(VkInstance instance, VkPhysicalDevice native_phys_dev) -+{ -+ uint32_t i; -+ for(i = 0; i < instance->phys_dev_count; ++i){ -+ if(instance->phys_devs[i]->phys_dev == native_phys_dev) -+ return instance->phys_devs[i]; -+ } -+ WARN("Unknown native physical device: %p\n", native_phys_dev); -+ return NULL; -+} -diff --git a/dlls/winevulkan/vulkan_loader.h b/dlls/winevulkan/vulkan_loader.h -index 2efa56e0193..da3099fe042 100644 ---- a/dlls/winevulkan/vulkan_loader.h -+++ b/dlls/winevulkan/vulkan_loader.h -@@ -108,6 +108,12 @@ struct unix_funcs - NTSTATUS (WINAPI *p_vk_call)(enum unix_call, void *); - BOOL (WINAPI *p_is_available_instance_function)(VkInstance, const char *); - BOOL (WINAPI *p_is_available_device_function)(VkDevice, const char *); -+ -+ VkDevice (WINAPI *p_wine_get_native_VkDevice)(VkDevice); -+ VkInstance (WINAPI *p_wine_get_native_VkInstance)(VkInstance); -+ VkPhysicalDevice (WINAPI *p_wine_get_native_VkPhysicalDevice)(VkPhysicalDevice); -+ VkQueue (WINAPI *p_wine_get_native_VkQueue)(VkQueue); -+ VkPhysicalDevice (WINAPI *p_wine_get_wrapped_VkPhysicalDevice)(VkInstance, VkPhysicalDevice); - }; - - #endif /* __WINE_VULKAN_LOADER_H */ -diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h -index 83a26988e8b..971b2cb56bf 100644 ---- a/dlls/winevulkan/vulkan_private.h -+++ b/dlls/winevulkan/vulkan_private.h -@@ -217,4 +217,10 @@ extern const struct unix_funcs loader_funcs; - BOOL WINAPI wine_vk_is_available_instance_function(VkInstance instance, const char *name) DECLSPEC_HIDDEN; - BOOL WINAPI wine_vk_is_available_device_function(VkDevice device, const char *name) DECLSPEC_HIDDEN; - -+extern VkDevice WINAPI __wine_get_native_VkDevice(VkDevice device) DECLSPEC_HIDDEN; -+extern VkInstance WINAPI __wine_get_native_VkInstance(VkInstance instance) DECLSPEC_HIDDEN; -+extern VkPhysicalDevice WINAPI __wine_get_native_VkPhysicalDevice(VkPhysicalDevice phys_dev) DECLSPEC_HIDDEN; -+extern VkQueue WINAPI __wine_get_native_VkQueue(VkQueue queue) DECLSPEC_HIDDEN; -+extern VkPhysicalDevice WINAPI __wine_get_wrapped_VkPhysicalDevice(VkInstance instance, VkPhysicalDevice native_phys_dev) DECLSPEC_HIDDEN; -+ - #endif /* __WINE_VULKAN_PRIVATE_H */ -From 28b7ae8e2cf2fda0a41ad15d0ea0d6b85468c09e Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 18 Jun 2019 14:55:34 -0500 -Subject: [PATCH] Revert "winevulkan: Check if instance extensions are - supported." - -This reverts commit e84999bd7ab859746e893ed2d49b1d42b0323c3a. - -Vulkan VR games will try to load some extensions that winevulkan doesn't -support. ---- - dlls/winevulkan/vulkan.c | 8 +------- - 1 file changed, 1 insertion(+), 7 deletions(-) - -diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c -index 81c2feff36e..573e40aff89 100644 ---- a/dlls/winevulkan/vulkan.c -+++ b/dlls/winevulkan/vulkan.c -@@ -506,17 +506,11 @@ static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo - return VK_ERROR_LAYER_NOT_PRESENT; - } - -- TRACE("Enabled %u instance extensions.\n", dst->enabledExtensionCount); -+ TRACE("Enabled extensions: %u\n", dst->enabledExtensionCount); - for (i = 0; i < dst->enabledExtensionCount; i++) - { - const char *extension_name = dst->ppEnabledExtensionNames[i]; - TRACE("Extension %u: %s.\n", i, debugstr_a(extension_name)); -- if (!wine_vk_instance_extension_supported(extension_name)) -- { -- WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); -- free_VkInstanceCreateInfo_struct_chain(dst); -- return VK_ERROR_EXTENSION_NOT_PRESENT; -- } - if (!strcmp(extension_name, "VK_EXT_debug_utils") || !strcmp(extension_name, "VK_EXT_debug_report")) - { - object->enable_wrapper_list = VK_TRUE; -From e10162d664a82e6989a0e444807e9a1d84d86303 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 25 Sep 2018 14:53:05 -0500 -Subject: [PATCH] Revert "winevulkan: Check if device extensions are - supported." - -This reverts commit 4907ffdf2a15ab3a1e3749def37f4be67b758a35. - -Vulkan VR games will try to load some extensions that winevulkan doesn't -support. ---- - dlls/winevulkan/vulkan.c | 11 ++--------- - 1 file changed, 2 insertions(+), 9 deletions(-) - -diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c -index 573e40aff89..830fe7d9466 100644 ---- a/dlls/winevulkan/vulkan.c -+++ b/dlls/winevulkan/vulkan.c -@@ -386,17 +386,10 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src - dst->enabledLayerCount = 0; - dst->ppEnabledLayerNames = NULL; - -- TRACE("Enabled %u extensions.\n", dst->enabledExtensionCount); -+ TRACE("Enabled extensions: %u.\n", dst->enabledExtensionCount); - for (i = 0; i < dst->enabledExtensionCount; i++) - { -- const char *extension_name = dst->ppEnabledExtensionNames[i]; -- TRACE("Extension %u: %s.\n", i, debugstr_a(extension_name)); -- if (!wine_vk_device_extension_supported(extension_name)) -- { -- WARN("Extension %s is not supported.\n", debugstr_a(extension_name)); -- wine_vk_device_free_create_info(dst); -- return VK_ERROR_EXTENSION_NOT_PRESENT; -- } -+ TRACE("Extension %u: %s.\n", i, debugstr_a(dst->ppEnabledExtensionNames[i])); - } - - return VK_SUCCESS; -From 7e67d9e6792b2e4d97128ceb5d4ff2fdb581b37b Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Sun, 10 Oct 2021 21:52:26 +0200 -Subject: [PATCH] winevulkan: Retrieve XR extensions from the environment - ---- - dlls/winevulkan/vulkan.c | 124 +++++++++++++++++++++++++++++++++++++-- - 1 file changed, 120 insertions(+), 4 deletions(-) - -diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c -index 830fe7d9466..5ca62ff9350 100644 ---- a/dlls/winevulkan/vulkan.c -+++ b/dlls/winevulkan/vulkan.c -@@ -368,12 +368,70 @@ static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info) - free_VkDeviceCreateInfo_struct_chain(create_info); - } - -+static char **parse_xr_extensions(unsigned int *len) -+{ -+ char *xr_str, *iter, *start, **list; -+ unsigned int extension_count = 0, o = 0; -+ -+ xr_str = getenv("__WINE_OPENXR_VK_DEVICE_EXTENSIONS"); -+ if (!xr_str) -+ { -+ *len = 0; -+ return NULL; -+ } -+ xr_str = strdup(xr_str); -+ -+ TRACE("got var: %s\n", xr_str); -+ -+ iter = xr_str; -+ while(*iter){ -+ if(*iter++ == ' ') -+ extension_count++; -+ } -+ /* count the one ending in NUL */ -+ if(iter != xr_str) -+ extension_count++; -+ if(!extension_count){ -+ *len = 0; -+ return NULL; -+ } -+ -+ TRACE("counted %u extensions\n", extension_count); -+ -+ list = malloc(extension_count * sizeof(char *)); -+ -+ start = iter = xr_str; -+ do{ -+ if(*iter == ' '){ -+ *iter = 0; -+ list[o++] = strdup(start); -+ TRACE("added %s to list\n", list[o-1]); -+ iter++; -+ start = iter; -+ }else if(*iter == 0){ -+ list[o++] = strdup(start); -+ TRACE("added %s to list\n", list[o-1]); -+ break; -+ }else{ -+ iter++; -+ } -+ }while(1); -+ -+ free(xr_str); -+ -+ *len = extension_count; -+ -+ return list; -+} -+ - static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src, -- VkDeviceCreateInfo *dst) -+ VkDeviceCreateInfo *dst, BOOL *must_free_extensions) - { -- unsigned int i; -+ unsigned int i, append_xr = 0, wine_extension_count; - VkResult res; - -+ static const char *wine_xr_extension_name = "VK_WINE_openxr_device_extensions"; -+ - *dst = *src; - - if ((res = convert_VkDeviceCreateInfo_struct_chain(src->pNext, dst)) < 0) -@@ -386,8 +444,54 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src - dst->enabledLayerCount = 0; - dst->ppEnabledLayerNames = NULL; - -- TRACE("Enabled extensions: %u.\n", dst->enabledExtensionCount); - for (i = 0; i < dst->enabledExtensionCount; i++) -+ { -+ const char *extension_name = dst->ppEnabledExtensionNames[i]; -+ if (!strcmp(extension_name, wine_xr_extension_name)) -+ { -+ append_xr = 1; -+ break; -+ } -+ } -+ -+ if (append_xr) -+ { -+ unsigned int xr_extensions_len, o = 0; -+ char **xr_extensions_list = parse_xr_extensions(&xr_extensions_len); -+ -+ char **new_extensions_list = malloc(sizeof(char *) * (dst->enabledExtensionCount + xr_extensions_len)); -+ -+ if(!xr_extensions_list) -+ WARN("Requested to use XR extensions, but none are set!\n"); -+ -+ for (i = 0; i < dst->enabledExtensionCount; i++) -+ { -+ if (strcmp(dst->ppEnabledExtensionNames[i], wine_xr_extension_name) != 0) -+ { -+ new_extensions_list[o++] = strdup(dst->ppEnabledExtensionNames[i]); -+ } -+ } -+ -+ TRACE("appending XR extensions:\n"); -+ for (i = 0; i < xr_extensions_len; ++i) -+ { -+ TRACE("\t%s\n", xr_extensions_list[i]); -+ new_extensions_list[o++] = xr_extensions_list[i]; -+ } -+ dst->enabledExtensionCount = o; -+ dst->ppEnabledExtensionNames = (const char * const *)new_extensions_list; -+ -+ free(xr_extensions_list); -+ -+ *must_free_extensions = TRUE; -+ wine_extension_count = dst->enabledExtensionCount - xr_extensions_len; -+ }else{ -+ *must_free_extensions = FALSE; -+ wine_extension_count = dst->enabledExtensionCount; -+ } -+ -+ TRACE("Enabled %u extensions.\n", dst->enabledExtensionCount); -+ for (i = 0; i < wine_extension_count; i++) - { - TRACE("Extension %u: %s.\n", i, debugstr_a(dst->ppEnabledExtensionNames[i])); - } -@@ -395,6 +499,15 @@ static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src - return VK_SUCCESS; - } - -+static void wine_vk_device_free_create_info_extensions(VkDeviceCreateInfo *create_info) -+{ -+ unsigned int i; -+ for(i = 0; i < create_info->enabledExtensionCount; ++i) -+ free((void*)create_info->ppEnabledExtensionNames[i]); -+ free((void*)create_info->ppEnabledExtensionNames); -+} -+ -+ - /* Helper function used for freeing a device structure. This function supports full - * and partial object cleanups and can thus be used for vkCreateDevice failures. - */ -@@ -684,6 +797,7 @@ NTSTATUS wine_vkCreateDevice(void *args) - struct VkQueue_T *next_queue; - struct VkDevice_T *object; - unsigned int i; -+ BOOL create_info_free_extensions; - VkResult res; - - TRACE("%p, %p, %p, %p\n", phys_dev, create_info, allocator, device); -@@ -708,13 +822,15 @@ NTSTATUS wine_vkCreateDevice(void *args) - object->base.base.loader_magic = VULKAN_ICD_MAGIC_VALUE; - object->phys_dev = phys_dev; - -- res = wine_vk_device_convert_create_info(create_info, &create_info_host); -+ res = wine_vk_device_convert_create_info(create_info, &create_info_host, &create_info_free_extensions); - if (res != VK_SUCCESS) - goto fail; - - res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev, - &create_info_host, NULL /* allocator */, &object->device); - wine_vk_device_free_create_info(&create_info_host); -+ if(create_info_free_extensions) -+ wine_vk_device_free_create_info_extensions(&create_info_host); - WINE_VK_ADD_DISPATCHABLE_MAPPING(phys_dev->instance, object, object->device); - if (res != VK_SUCCESS) - { -From 116711bfb34fb080381f1111f9c8ecf1fc33334a Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Sat, 11 Dec 2021 12:27:42 +0100 -Subject: [PATCH] winevulkan: Add functions for creating VK instance and device - through OpenXR. - ---- - dlls/winevulkan/loader.c | 20 ++++++++++++++++ - dlls/winevulkan/make_vulkan | 10 ++++++++ - dlls/winevulkan/vulkan.c | 39 +++++++++++++++++++++++++++++--- - dlls/winevulkan/vulkan_loader.h | 10 ++++++++ - dlls/winevulkan/vulkan_private.h | 5 ++++ - dlls/winex11.drv/vulkan.c | 22 ++++++++++++++---- - 6 files changed, 99 insertions(+), 7 deletions(-) - -diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c -index 4821b132cfe..0b2c4241f75 100644 ---- a/dlls/winevulkan/loader.c -+++ b/dlls/winevulkan/loader.c -@@ -430,6 +430,26 @@ VkPhysicalDevice WINAPI __wine_get_wrapped_VkPhysicalDevice(VkInstance instance, - return unix_funcs->p_wine_get_wrapped_VkPhysicalDevice(instance, native_phys_dev); - } - -+VkResult WINAPI __wine_create_vk_instance_with_callback(const VkInstanceCreateInfo *create_info, -+ const VkAllocationCallbacks *allocator, VkInstance *instance, -+ VkResult (WINAPI *native_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, -+ VkInstance *, void * (*)(VkInstance, const char *), void *), void *native_vkCreateInstance_context) -+{ -+ return unix_funcs->p_wine_create_vk_instance_with_callback(create_info, allocator, instance, -+ native_vkCreateInstance, native_vkCreateInstance_context); -+} -+ -+VkResult WINAPI __wine_create_vk_device_with_callback(VkPhysicalDevice phys_dev, -+ const VkDeviceCreateInfo *create_info, -+ const VkAllocationCallbacks *allocator, VkDevice *device, -+ VkResult (WINAPI *native_vkCreateDevice)(VkPhysicalDevice, const VkDeviceCreateInfo *, const VkAllocationCallbacks *, -+ VkDevice *, void * (*)(VkInstance, const char *), void *), void *native_vkCreateDevice_context) -+{ -+ return unix_funcs->p_wine_create_vk_device_with_callback(phys_dev, create_info, allocator, device, -+ native_vkCreateDevice, native_vkCreateDevice_context); -+} -+ -+ - BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved) - { - void **kernel_callback_table; -diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan -index 7fc4412fdfd..e198256b31c 100755 ---- a/dlls/winevulkan/make_vulkan -+++ b/dlls/winevulkan/make_vulkan -@@ -2852,6 +2852,8 @@ class VkGenerator(object): - f.write(" __wine_get_native_VkPhysicalDevice,\n") - f.write(" __wine_get_native_VkQueue,\n") - f.write(" __wine_get_wrapped_VkPhysicalDevice,\n") -+ f.write(" __wine_create_vk_instance_with_callback,\n") -+ f.write(" __wine_create_vk_device_with_callback,\n") - f.write("};\n") - - def generate_thunks_h(self, f, prefix): -@@ -3208,6 +3208,12 @@ class VkGenerator(object): - f.write(" * will contain the area to blit the user image to in real coordinates.\n") - f.write(" * All parameters are optional. */\n") - f.write(" VkBool32 (*query_fs_hack)(VkSurfaceKHR surface, VkExtent2D *real_sz, VkExtent2D *user_sz, VkRect2D *dst_blit, VkFilter *filter);\n") -+ -+ f.write(" VkResult (*create_vk_instance_with_callback)(const VkInstanceCreateInfo *create_info,\n") -+ f.write(" const VkAllocationCallbacks *allocator, VkInstance *instance,\n") -+ f.write(" VkResult (WINAPI *native_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *,\n") -+ f.write(" VkInstance *, void * (*)(VkInstance, const char *), void *), void *native_vkCreateInstance_context);\n") -+ - f.write("};\n\n") - - f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(UINT version);\n\n") -@@ -3239,6 +3247,8 @@ class VkGenerator(object): - f.write("@ stdcall __wine_get_native_VkPhysicalDevice(ptr)\n") - f.write("@ stdcall __wine_get_native_VkQueue(ptr)\n") - f.write("@ stdcall __wine_get_wrapped_VkPhysicalDevice(ptr ptr)\n") -+ f.write("@ stdcall __wine_create_vk_instance_with_callback(ptr ptr ptr ptr ptr)\n") -+ f.write("@ stdcall __wine_create_vk_device_with_callback(ptr ptr ptr ptr ptr ptr)\n") - - # Export symbols for all Vulkan Core functions. - for func in self.registry.funcs.values(): -diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c -index 5ca62ff9350..9f12660a407 100644 ---- a/dlls/winevulkan/vulkan.c -+++ b/dlls/winevulkan/vulkan.c -@@ -793,6 +793,15 @@ NTSTATUS wine_vkCreateDevice(void *args) - const VkDeviceCreateInfo *create_info = params->pCreateInfo; - const VkAllocationCallbacks *allocator = params->pAllocator; - VkDevice *device = params->pDevice; -+ return __wine_create_vk_device_with_callback(phys_dev, create_info, allocator, device, NULL, NULL); -+} -+ -+VkResult WINAPI __wine_create_vk_device_with_callback(VkPhysicalDevice phys_dev, -+ const VkDeviceCreateInfo *create_info, -+ const VkAllocationCallbacks *allocator, VkDevice *device, -+ VkResult (WINAPI *native_vkCreateDevice)(VkPhysicalDevice, const VkDeviceCreateInfo *, const VkAllocationCallbacks *, -+ VkDevice *, void * (*)(VkInstance, const char *), void *), void *native_vkCreateDevice_context) -+{ - VkDeviceCreateInfo create_info_host; - struct VkQueue_T *next_queue; - struct VkDevice_T *object; -@@ -826,8 +835,14 @@ NTSTATUS wine_vkCreateDevice(void *args) - if (res != VK_SUCCESS) - goto fail; - -- res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev, -- &create_info_host, NULL /* allocator */, &object->device); -+ if (native_vkCreateDevice) -+ res = native_vkCreateDevice(phys_dev->phys_dev, -+ &create_info_host, NULL /* allocator */, &object->device, -+ vk_funcs->p_vkGetInstanceProcAddr, native_vkCreateDevice_context); -+ else -+ res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev, -+ &create_info_host, NULL /* allocator */, &object->device); -+ - wine_vk_device_free_create_info(&create_info_host); - if(create_info_free_extensions) - wine_vk_device_free_create_info_extensions(&create_info_host); -@@ -909,12 +909,23 @@ NTSTATUS wine_vkCreateInstance(void *args) - const VkInstanceCreateInfo *create_info = params->pCreateInfo; - const VkAllocationCallbacks *allocator = params->pAllocator; - VkInstance *instance = params->pInstance; -+ return __wine_create_vk_instance_with_callback(create_info, allocator, instance, NULL, NULL); -+} -+ -+VkResult WINAPI __wine_create_vk_instance_with_callback(const VkInstanceCreateInfo *create_info, -+ const VkAllocationCallbacks *allocator, VkInstance *instance, -+ VkResult (WINAPI *native_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, -+ VkInstance *, void * (*)(VkInstance, const char *), void *), void *native_vkCreateInstance_context) -+{ - VkInstanceCreateInfo create_info_host; - const VkApplicationInfo *app_info; - uint32_t new_mxcsr, old_mxcsr; - struct VkInstance_T *object; - VkResult res; - -+ TRACE("create_info %p, allocator %p, instance %p, native_vkCreateInstance %p, context %p.\n", -+ create_info, allocator, instance, native_vkCreateInstance, native_vkCreateInstance_context); -+ - if (allocator) - FIXME("Support for allocation callbacks not implemented yet\n"); - -@@ -917,7 +943,14 @@ NTSTATUS wine_vkCreateInstance(void *args) - return res; - } - -- res = vk_funcs->p_vkCreateInstance(&create_info_host, NULL /* allocator */, &object->instance); -+ if (native_vkCreateInstance && !vk_funcs->create_vk_instance_with_callback) -+ ERR("Driver create_vk_instance_with_callback is not available.\n"); -+ -+ if (native_vkCreateInstance && vk_funcs->create_vk_instance_with_callback) -+ res = vk_funcs->create_vk_instance_with_callback(&create_info_host, NULL /* allocator */, &object->instance, -+ native_vkCreateInstance, native_vkCreateInstance_context); -+ else -+ res = vk_funcs->p_vkCreateInstance(&create_info_host, NULL /* allocator */, &object->instance); - free_VkInstanceCreateInfo_struct_chain(&create_info_host); - if (res != VK_SUCCESS) - { -diff --git a/dlls/winevulkan/vulkan_loader.h b/dlls/winevulkan/vulkan_loader.h -index da3099fe042..05913756fbc 100644 ---- a/dlls/winevulkan/vulkan_loader.h -+++ b/dlls/winevulkan/vulkan_loader.h -@@ -103,6 +103,11 @@ static inline NTSTATUS vk_unix_call(enum unix_call code, void *params) - return __wine_unix_call(unix_handle, code, params); - } - -+typedef VkResult (WINAPI *PFN_native_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *, -+ void * (*)(VkInstance, const char *), void *); -+typedef VkResult (WINAPI *PFN_native_vkCreateDevice)(VkPhysicalDevice, const VkDeviceCreateInfo *, const VkAllocationCallbacks *, VkDevice *, -+ void * (*)(VkInstance, const char *), void *); -+ - struct unix_funcs - { - NTSTATUS (WINAPI *p_vk_call)(enum unix_call, void *); -@@ -114,6 +119,11 @@ struct unix_funcs - VkPhysicalDevice (WINAPI *p_wine_get_native_VkPhysicalDevice)(VkPhysicalDevice); - VkQueue (WINAPI *p_wine_get_native_VkQueue)(VkQueue); - VkPhysicalDevice (WINAPI *p_wine_get_wrapped_VkPhysicalDevice)(VkInstance, VkPhysicalDevice); -+ -+ VkResult (WINAPI *p_wine_create_vk_instance_with_callback)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *, -+ PFN_native_vkCreateInstance, void *); -+ VkResult (WINAPI *p_wine_create_vk_device_with_callback)(VkPhysicalDevice, const VkDeviceCreateInfo *, const VkAllocationCallbacks *, VkDevice *, -+ PFN_native_vkCreateDevice, void *); - }; - - #endif /* __WINE_VULKAN_LOADER_H */ -diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h -index 971b2cb56bf..666ef95e1b1 100644 ---- a/dlls/winevulkan/vulkan_private.h -+++ b/dlls/winevulkan/vulkan_private.h -@@ -223,4 +223,9 @@ extern VkPhysicalDevice WINAPI __wine_get_native_VkPhysicalDevice(VkPhysicalDevi - extern VkQueue WINAPI __wine_get_native_VkQueue(VkQueue queue) DECLSPEC_HIDDEN; - extern VkPhysicalDevice WINAPI __wine_get_wrapped_VkPhysicalDevice(VkInstance instance, VkPhysicalDevice native_phys_dev) DECLSPEC_HIDDEN; - -+extern VkResult WINAPI __wine_create_vk_instance_with_callback(const VkInstanceCreateInfo *create_info, const VkAllocationCallbacks *allocator, -+ VkInstance *instance, PFN_native_vkCreateInstance callback, void *context) DECLSPEC_HIDDEN; -+extern VkResult WINAPI __wine_create_vk_device_with_callback(VkPhysicalDevice phys_dev, const VkDeviceCreateInfo *create_info, -+ const VkAllocationCallbacks *allocator, VkDevice *device, PFN_native_vkCreateDevice callback, void *context) DECLSPEC_HIDDEN; -+ - #endif /* __WINE_VULKAN_PRIVATE_H */ -diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c -index 619b0ecec1e..d805b3c8be4 100644 ---- a/dlls/winex11.drv/vulkan.c -+++ b/dlls/winex11.drv/vulkan.c -@@ -257,12 +257,15 @@ void vulkan_thread_detach(void) - LeaveCriticalSection(&context_section); - } - --static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, -- const VkAllocationCallbacks *allocator, VkInstance *instance) -+static VkResult X11DRV_create_vk_instance_with_callback(const VkInstanceCreateInfo *create_info, -+ const VkAllocationCallbacks *allocator, VkInstance *instance, -+ VkResult (WINAPI *native_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, -+ VkInstance *, void * (*)(VkInstance, const char *), void *), void *native_vkCreateInstance_context) - { - VkInstanceCreateInfo create_info_host; - VkResult res; -- TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance); -+ TRACE("create_info %p, allocator %p, instance %p, native_vkCreateInstance %p, context %p.\n", -+ create_info, allocator, instance, native_vkCreateInstance, native_vkCreateInstance_context); - - if (allocator) - FIXME("Support for allocation callbacks not implemented yet\n"); -@@ -278,12 +281,22 @@ static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, - return res; - } - -- res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance); -+ if (native_vkCreateInstance) -+ res = native_vkCreateInstance(&create_info_host, NULL /* allocator */, instance, -+ pvkGetInstanceProcAddr, native_vkCreateInstance_context); -+ else -+ res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance); - - heap_free((void *)create_info_host.ppEnabledExtensionNames); - return res; - } - -+static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, -+ const VkAllocationCallbacks *allocator, VkInstance *instance) -+{ -+ return X11DRV_create_vk_instance_with_callback(create_info, allocator, instance, NULL, NULL); -+} -+ - static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, - const VkSwapchainCreateInfoKHR *create_info, - const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain) -@@ -964,6 +964,7 @@ static const struct vulkan_funcs vulkan_funcs = - - X11DRV_wine_get_native_surface, - X11DRV_query_fs_hack, -+ X11DRV_create_vk_instance_with_callback, - }; - - static void *X11DRV_get_vk_device_proc_addr(const char *name) -From d6b1bc3622340688a99837e413368f2f0ce6bc58 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 4 Jan 2021 14:25:06 -0600 -Subject: [PATCH] wine.inf: Add OpenXR registry entries - ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 1a6af65a834..c0d600a00e3 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -6140,6 +6140,9 @@ HKCU,Software\Wine\DllOverrides,"nvcuda",0x2,"disabled" - [NVIDIANGX] - HKLM,Software\NVIDIA Corporation\Global\NGXCore,"FullPath",,"C:\Windows\System32" - -+[ProtonOverrides] -+HKLM,Software\Khronos\OpenXR\1,"ActiveRuntime",,"C:\openxr\wineopenxr64.json" -+ - [NlsFiles] - c_037.nls - c_10000.nls diff --git a/patches/proton/38-proton-keyboard-input-and-mouse-focus-fixes.patch b/patches/proton/38-proton-keyboard-input-and-mouse-focus-fixes.patch deleted file mode 100644 index 2de519c76..000000000 --- a/patches/proton/38-proton-keyboard-input-and-mouse-focus-fixes.patch +++ /dev/null @@ -1,1190 +0,0 @@ -From 82270d26980c8f83894994ec9c51cd2dcb8decde Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 18 Oct 2019 11:39:19 +0200 -Subject: [PATCH] winex11.drv: Pass XEvent instead of XClientMessageEvent to - handlers. - -This is to avoid a dubious cast from XClientMessageEvent to XEvent in -next patch. ---- - dlls/winex11.drv/event.c | 20 +++++++++++++------- - dlls/winex11.drv/x11drv.h | 8 ++++---- - dlls/winex11.drv/xdnd.c | 11 +++++++---- - 3 files changed, 24 insertions(+), 15 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 4656247b51c..2cb60b7937c 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -639,8 +639,10 @@ static void set_focus( Display *display, HWND hwnd, Time time ) - /********************************************************************** - * handle_manager_message - */ --static void handle_manager_message( HWND hwnd, XClientMessageEvent *event ) -+static void handle_manager_message( HWND hwnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; -+ - if (hwnd != GetDesktopWindow()) return; - if (systray_atom && event->data.l[1] == systray_atom) - change_systray_owner( event->display, event->data.l[2] ); -@@ -650,8 +652,9 @@ static void handle_manager_message( HWND hwnd, XClientMessageEvent *event ) - /********************************************************************** - * handle_wm_protocols - */ --static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event ) -+static void handle_wm_protocols( HWND hwnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - Atom protocol = (Atom)event->data.l[0]; - Time event_time = (Time)event->data.l[1]; - -@@ -1699,8 +1702,10 @@ static void EVENT_DropURLs( HWND hWnd, XClientMessageEvent *event ) - /********************************************************************** - * handle_xembed_protocol - */ --static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) -+static void handle_xembed_protocol( HWND hwnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; -+ - switch (event->data.l[1]) - { - case XEMBED_EMBEDDED_NOTIFY: -@@ -1755,8 +1760,9 @@ static void handle_xembed_protocol( HWND hwnd, XClientMessageEvent *event ) - /********************************************************************** - * handle_dnd_protocol - */ --static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) -+static void handle_dnd_protocol( HWND hwnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - Window root, child; - int root_x, root_y, child_x, child_y; - unsigned int u; -@@ -1775,8 +1781,8 @@ static void handle_dnd_protocol( HWND hwnd, XClientMessageEvent *event ) - - struct client_message_handler - { -- int atom; /* protocol atom */ -- void (*handler)(HWND, XClientMessageEvent *); /* corresponding handler function */ -+ int atom; /* protocol atom */ -+ void (*handler)(HWND, XEvent *); /* corresponding handler function */ - }; - - static const struct client_message_handler client_messages[] = -@@ -1812,7 +1818,7 @@ static BOOL X11DRV_ClientMessage( HWND hwnd, XEvent *xev ) - { - if (event->message_type == X11DRV_Atoms[client_messages[i].atom - FIRST_XATOM]) - { -- client_messages[i].handler( hwnd, event ); -+ client_messages[i].handler( hwnd, xev ); - return TRUE; - } - } -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 97311254b91..4054e86f4ee 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -294,10 +294,10 @@ extern BOOL IME_SetCompositionString(DWORD dwIndex, LPCVOID lpComp, - DWORD dwReadLen) DECLSPEC_HIDDEN; - extern void IME_SetResultString(LPWSTR lpResult, DWORD dwResultlen) DECLSPEC_HIDDEN; - --extern void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; --extern void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; --extern void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; --extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) DECLSPEC_HIDDEN; -+extern void X11DRV_XDND_EnterEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; -+extern void X11DRV_XDND_PositionEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; -+extern void X11DRV_XDND_DropEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; -+extern void X11DRV_XDND_LeaveEvent( HWND hWnd, XEvent *xev ) DECLSPEC_HIDDEN; - extern void X11DRV_CLIPBOARD_ImportSelection( Display *display, Window win, Atom selection, - Atom *targets, UINT count, - void (*callback)( Atom, UINT, HANDLE )) DECLSPEC_HIDDEN; -diff --git a/dlls/winex11.drv/xdnd.c b/dlls/winex11.drv/xdnd.c -index eb685613b7b..2ab5b9157dc 100644 ---- a/dlls/winex11.drv/xdnd.c -+++ b/dlls/winex11.drv/xdnd.c -@@ -188,8 +188,9 @@ static long X11DRV_XDND_DROPEFFECTToXdndAction(DWORD effect) - * - * Handle an XdndEnter event. - */ --void X11DRV_XDND_EnterEvent( HWND hWnd, XClientMessageEvent *event ) -+void X11DRV_XDND_EnterEvent( HWND hWnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - int version; - Atom *xdndtypes; - unsigned long count = 0; -@@ -287,8 +288,9 @@ static HWND window_accepting_files(HWND hwnd) - * - * Handle an XdndPosition event. - */ --void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) -+void X11DRV_XDND_PositionEvent( HWND hWnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - XClientMessageEvent e; - int accept = 0; /* Assume we're not accepting */ - IDropTarget *dropTarget = NULL; -@@ -401,8 +403,9 @@ void X11DRV_XDND_PositionEvent( HWND hWnd, XClientMessageEvent *event ) - * - * Handle an XdndDrop event. - */ --void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) -+void X11DRV_XDND_DropEvent( HWND hWnd, XEvent *xev ) - { -+ XClientMessageEvent *event = &xev->xclient; - XClientMessageEvent e; - IDropTarget *dropTarget; - DWORD effect = XDNDDropEffect; -@@ -493,7 +496,7 @@ void X11DRV_XDND_DropEvent( HWND hWnd, XClientMessageEvent *event ) - * - * Handle an XdndLeave event. - */ --void X11DRV_XDND_LeaveEvent( HWND hWnd, XClientMessageEvent *event ) -+void X11DRV_XDND_LeaveEvent( HWND hWnd, XEvent *xev ) - { - IDropTarget *dropTarget; - -From 5a06b183da6427149d3ca5677613d10c0429eb8b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 23 Dec 2019 14:38:44 +0100 -Subject: [PATCH] winex11.drv: Pass XEvent instead of Display to set_focus. - ---- - dlls/winex11.drv/event.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 1ef76d506ed..2e9ff2173cf 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -603,7 +603,7 @@ static void set_input_focus( struct x11drv_win_data *data ) - /********************************************************************** - * set_focus - */ --static void set_focus( Display *display, HWND hwnd, Time time ) -+static void set_focus( XEvent *xev, HWND hwnd, Time time ) - { - HWND focus; - Window win; -@@ -622,7 +622,7 @@ static void set_focus( Display *display, HWND hwnd, Time time ) - if (win) - { - TRACE( "setting focus to %p (%lx) time=%ld\n", focus, win, time ); -- XSetInputFocus( display, win, RevertToParent, time ); -+ XSetInputFocus( xev->xany.display, win, RevertToParent, time ); - } - } - -@@ -721,7 +721,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) - MAKELONG( HTMENU, WM_LBUTTONDOWN ) ); - if (ma != MA_NOACTIVATEANDEAT && ma != MA_NOACTIVATE) - { -- set_focus( event->display, hwnd, event_time ); -+ set_focus( xev, hwnd, event_time ); - return; - } - } -@@ -730,7 +730,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) - hwnd = GetForegroundWindow(); - if (!hwnd) hwnd = last_focus; - if (!hwnd) hwnd = GetDesktopWindow(); -- set_focus( event->display, hwnd, event_time ); -+ set_focus( xev, hwnd, event_time ); - return; - } - /* try to find some other window to give the focus to */ -@@ -738,7 +738,7 @@ static void handle_wm_protocols( HWND hwnd, XEvent *xev ) - if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT ); - if (!hwnd) hwnd = GetActiveWindow(); - if (!hwnd) hwnd = last_focus; -- if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, event_time ); -+ if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, event_time ); - } - else if (protocol == x11drv_atom(_NET_WM_PING)) - { -@@ -818,7 +818,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - if (hwnd) hwnd = GetAncestor( hwnd, GA_ROOT ); - if (!hwnd) hwnd = GetActiveWindow(); - if (!hwnd) hwnd = x11drv_thread_data()->last_focus; -- if (hwnd && can_activate_window(hwnd)) set_focus( event->display, hwnd, CurrentTime ); -+ if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); - } - else SetForegroundWindow( hwnd ); - return TRUE; -From b9dcf02b582ef877ebb85396c64aa7faf2565377 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 7 Oct 2019 12:58:23 +0200 -Subject: [PATCH] winex11.drv: Merge FocusIn/FocusOut NotifyGrab/NotifyUngrab - cases. - -The return value was different as well, this makes it consistent. The -switch is also going to go away. ---- - dlls/winex11.drv/event.c | 15 ++++++++++----- - 1 file changed, 10 insertions(+), 5 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index f23cf7e710b..a6e025152ef 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -801,7 +801,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - case NotifyGrab: - /* these are received when moving undecorated managed windows on mutter */ - keyboard_grabbed = TRUE; -- return FALSE; -+ break; - case NotifyWhileGrabbed: - keyboard_grabbed = TRUE; - break; -@@ -811,9 +811,12 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - case NotifyUngrab: - keyboard_grabbed = FALSE; - retry_grab_clipping_window(); -- return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ -+ break; - } - -+ /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ -+ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; -+ - if ((xic = X11DRV_get_ic( hwnd ))) XSetICFocus( xic ); - if (use_take_focus) - { -@@ -903,7 +906,7 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) - case NotifyUngrab: - /* these are received when moving undecorated managed windows on mutter */ - keyboard_grabbed = FALSE; -- return FALSE; -+ break; - case NotifyNormal: - keyboard_grabbed = FALSE; - break; -@@ -918,10 +921,12 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) - * FocusIn with NotifyUngrab mode. - */ - retry_grab_clipping_window(); -- -- return TRUE; /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ -+ break; - } - -+ /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ -+ if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; -+ - focus_out( event->display, hwnd ); - return TRUE; - } -From f2ed642f0944e77921494d00bb582a9eede637c1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 19 Sep 2019 15:42:09 +0200 -Subject: [PATCH] winex11.drv: Wait for pointer grab on FocusIn/WM_TAKE_FOCUS - events. - -The FocusIn/WM_TAKE_FOCUS events are received as soon as a window is -clicked, but when some modifier key is pressed or when the click is on -the window frame, the WM may still be controlling the window size or -position. It usually grabs the cursor while doing so - and if not then -there's apparently nothing we can do. - -When using undecorated mode we handle this case "correctly" by going -through the corresponding Windows non-client message loop until mouse -buttons are released, but when using decorated windows the window -decoration is empty from the Wine perspective and any window event is -considered as happening in the client area. - -This leads to some issues when the window is moved or resized, with -applications applying clipping rectangles immediately and not updating -it on subsequent window move/resize messages. Delaying the WM_ACTIVATE -until the WM releases its grab and the window move is complete helps -solving this situation. - -This delay is implemented here by resending the FocusIn/WM_TAKE_FOCUS -events to the window until the cursor can be grabbed and then processing -them normally. ---- - dlls/winex11.drv/event.c | 39 ++++++++++++++++++++++++++++++++++++--- - 1 file changed, 36 insertions(+), 3 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index a6e025152ef..a13cd15bc04 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -323,6 +323,24 @@ static enum event_merge_action merge_raw_motion_events( XIRawEvent *prev, XIRawE - } - #endif - -+static int try_grab_pointer( Display *display ) -+{ -+ if (!grab_pointer) -+ return 1; -+ -+ /* if we are already clipping the cursor in the current thread, we should not -+ * call XGrabPointer here or it would change the confine-to window. */ -+ if (clipping_cursor && x11drv_thread_data()->clip_hwnd) -+ return 1; -+ -+ if (XGrabPointer( display, root_window, False, 0, GrabModeAsync, GrabModeAsync, -+ None, None, CurrentTime ) != GrabSuccess) -+ return 0; -+ -+ XUngrabPointer( display, CurrentTime ); -+ return 1; -+} -+ - /*********************************************************************** - * merge_events - * -@@ -618,8 +636,16 @@ static void set_focus( XEvent *xev, HWND hwnd, Time time ) - Window win; - GUITHREADINFO threadinfo; - -- TRACE( "setting foreground window to %p\n", hwnd ); -- SetForegroundWindow( hwnd ); -+ if (!try_grab_pointer( xev->xany.display )) -+ { -+ XSendEvent( xev->xany.display, xev->xany.window, False, 0, xev ); -+ return; -+ } -+ else -+ { -+ TRACE( "setting foreground window to %p\n", hwnd ); -+ SetForegroundWindow( hwnd ); -+ } - - threadinfo.cbSize = sizeof(threadinfo); - GetGUIThreadInfo(0, &threadinfo); -@@ -822,8 +848,15 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - if (!hwnd) hwnd = GetActiveWindow(); - if (!hwnd) hwnd = x11drv_thread_data()->last_focus; - if (hwnd && can_activate_window(hwnd)) set_focus( xev, hwnd, CurrentTime ); -+ return TRUE; - } -- else SetForegroundWindow( hwnd ); -+ else if (!try_grab_pointer( event->display )) -+ { -+ XSendEvent( event->display, event->window, False, 0, xev ); -+ return FALSE; -+ } -+ -+ SetForegroundWindow( hwnd ); - return TRUE; - } - -From cbaa1a01df27ebd5b21fdb57ae7c1df8ddf75b23 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 9 Dec 2021 11:53:02 +0100 -Subject: [PATCH] winex11.drv: Release pointer grab on focus change. - -When using WM_TAKE_FOCUS, the foreground window will only receive the -FocusOut message after we have called XSetInputFocus. As we are waiting -for the cursor to be released, we have to tell it to release its grab -so we can try to grab it ourselves. ---- - dlls/winex11.drv/event.c | 2 ++ - dlls/winex11.drv/window.c | 2 ++ - dlls/winex11.drv/x11drv.h | 3 ++- - 3 files changed, 6 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index a13cd15bc04..67ef62ba3cc 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -638,6 +638,8 @@ static void set_focus( XEvent *xev, HWND hwnd, Time time ) - - if (!try_grab_pointer( xev->xany.display )) - { -+ /* ask the foreground window to release its grab before trying to get ours */ -+ SendMessageW( GetForegroundWindow(), WM_X11DRV_RELEASE_CURSOR, 0, 0 ); - XSendEvent( xev->xany.display, xev->xany.window, False, 0, xev ); - return; - } -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 1bac11b373a..f76e020323a 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -2898,6 +2898,8 @@ LRESULT CDECL X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) - return 0; - case WM_X11DRV_ADD_TAB: - taskbar_add_tab( hwnd ); -+ case WM_X11DRV_RELEASE_CURSOR: -+ ungrab_clipping_window(); - return 0; - default: - FIXME( "got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, wp, lp ); -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 4054e86f4ee..1bdb26bff40 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -580,7 +580,8 @@ enum x11drv_window_messages - WM_X11DRV_CLIP_CURSOR_NOTIFY, - WM_X11DRV_CLIP_CURSOR_REQUEST, - WM_X11DRV_DELETE_TAB, -- WM_X11DRV_ADD_TAB -+ WM_X11DRV_ADD_TAB, -+ WM_X11DRV_RELEASE_CURSOR, - }; - - /* _NET_WM_STATE properties that we keep track of */ -From 181f064c19948961bec9878a0600e35dee3409f1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 1 Oct 2019 11:21:24 +0200 -Subject: [PATCH] winex11.drv: Restore pointer grab on FocusIn events. - -This reverts commit 92177b0b161e91f1d609615d89d8e3199feea33f. - -We introduced unnecessary complexity by adding the last_clip_* state, -we can instead use the ClipCursor state. - -This restores the ClipCursor on FocusIn events by sending a -WM_X11DRV_CLIP_CURSOR message to the foreground window, which will query -the current clipping rect from the server and apply it. ---- - dlls/winex11.drv/event.c | 10 +++------- - dlls/winex11.drv/mouse.c | 24 ------------------------ - dlls/winex11.drv/x11drv.h | 1 - - 3 files changed, 3 insertions(+), 32 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 4c6b2e542fd..cf0305b2a4d 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -838,10 +838,12 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - break; - case NotifyUngrab: - keyboard_grabbed = FALSE; -- retry_grab_clipping_window(); - break; - } - -+ /* ask the foreground window to re-apply the current ClipCursor rect */ -+ SendMessageW( GetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0 ); -+ - /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ - if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; - -@@ -950,12 +952,6 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) - break; - case NotifyGrab: - keyboard_grabbed = TRUE; -- -- /* This will do nothing due to keyboard_grabbed == TRUE, but it -- * will save the current clipping rect so we can restore it on -- * FocusIn with NotifyUngrab mode. -- */ -- retry_grab_clipping_window(); - break; - } - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 59f37681811..73c7527144e 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -128,9 +128,6 @@ XContext cursor_context = 0; - static HWND cursor_window; - static HCURSOR last_cursor; - static DWORD last_cursor_change; --static RECT last_clip_rect; --static HWND last_clip_foreground_window; --static BOOL last_clip_refused; - static RECT clip_rect; - static Cursor create_cursor( HANDLE handle ); - -@@ -450,15 +447,8 @@ static BOOL grab_clipping_window( const RECT *clip ) - if (keyboard_grabbed) - { - WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); -- last_clip_refused = TRUE; -- last_clip_foreground_window = GetForegroundWindow(); -- last_clip_rect = *clip; - return FALSE; - } -- else -- { -- last_clip_refused = FALSE; -- } - - /* enable XInput2 unless we are already clipping */ - if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); -@@ -529,20 +519,6 @@ void reset_clipping_window(void) - ClipCursor( NULL ); /* make sure the clip rectangle is reset too */ - } - --/*********************************************************************** -- * retry_grab_clipping_window -- * -- * Restore the current clip rectangle or retry the last one if it has -- * been refused because of an active keyboard grab. -- */ --void retry_grab_clipping_window(void) --{ -- if (clipping_cursor) -- ClipCursor( &clip_rect ); -- else if (last_clip_refused && GetForegroundWindow() == last_clip_foreground_window) -- ClipCursor( &last_clip_rect ); --} -- - /*********************************************************************** - * clip_cursor_notify - * -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 1bdb26bff40..145fe5313d4 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -679,7 +679,6 @@ extern LRESULT clip_cursor_notify( HWND hwnd, HWND prev_clip_hwnd, HWND new_clip - extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) DECLSPEC_HIDDEN; - extern void ungrab_clipping_window(void) DECLSPEC_HIDDEN; - extern void reset_clipping_window(void) DECLSPEC_HIDDEN; --extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; - extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; - extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; - extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; -From 601f89d0f682dba5bebdf8964d9c388cdf3d2235 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 4 Oct 2019 13:57:33 +0200 -Subject: [PATCH] Revert "winex11.drv: Only grab or warp the cursor when - keyboard isn't grabbed." - -This reverts commit 54f8077c41f715cfcf9c2bc016d964b720911326. - -We are now delaying FocusIn events until cursor grab is released, -eventually restoring the last ClipCursor, and we also release our grab -on FocusOut events. This keyboard grab tracking isn't needed anymore. ---- - dlls/winex11.drv/event.c | 37 ------------------------------------- - dlls/winex11.drv/mouse.c | 12 ------------ - dlls/winex11.drv/x11drv.h | 1 - - 3 files changed, 50 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index cf0305b2a4d..b7f5614f222 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -148,9 +148,6 @@ static const char * event_names[MAX_EVENT_HANDLERS] = - "SelectionNotify", "ColormapNotify", "ClientMessage", "MappingNotify", "GenericEvent" - }; - --/* is someone else grabbing the keyboard, for example the WM, when manipulating the window */ --BOOL keyboard_grabbed = FALSE; -- - int xinput2_opcode = 0; - - /* return the name of an X event */ -@@ -824,23 +821,6 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - if (event->detail == NotifyPointer) return FALSE; - if (hwnd == GetDesktopWindow()) return FALSE; - -- switch (event->mode) -- { -- case NotifyGrab: -- /* these are received when moving undecorated managed windows on mutter */ -- keyboard_grabbed = TRUE; -- break; -- case NotifyWhileGrabbed: -- keyboard_grabbed = TRUE; -- break; -- case NotifyNormal: -- keyboard_grabbed = FALSE; -- break; -- case NotifyUngrab: -- keyboard_grabbed = FALSE; -- break; -- } -- - /* ask the foreground window to re-apply the current ClipCursor rect */ - SendMessageW( GetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0 ); - -@@ -902,23 +909,6 @@ static BOOL X11DRV_FocusOut( HWND hwnd, XEvent *xev ) - } - if (!hwnd) return FALSE; - -- switch (event->mode) -- { -- case NotifyUngrab: -- /* these are received when moving undecorated managed windows on mutter */ -- keyboard_grabbed = FALSE; -- break; -- case NotifyNormal: -- keyboard_grabbed = FALSE; -- break; -- case NotifyWhileGrabbed: -- keyboard_grabbed = TRUE; -- break; -- case NotifyGrab: -- keyboard_grabbed = TRUE; -- break; -- } -- - /* ignore wm specific NotifyUngrab / NotifyGrab events w.r.t focus */ - if (event->mode == NotifyGrab || event->mode == NotifyUngrab) return FALSE; - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 73c7527144e..1d6f9d1c5b9 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -444,12 +444,6 @@ static BOOL grab_clipping_window( const RECT *clip ) - GetModuleHandleW(0), NULL ))) - return TRUE; - -- if (keyboard_grabbed) -- { -- WARN( "refusing to clip to %s\n", wine_dbgstr_rect(clip) ); -- return FALSE; -- } -- - /* enable XInput2 unless we are already clipping */ - if (!data->clip_hwnd) X11DRV_XInput2_Enable( data->display, None, PointerMotionMask ); - -@@ -1514,12 +1508,6 @@ BOOL CDECL X11DRV_SetCursorPos( INT x, INT y ) - struct x11drv_thread_data *data = x11drv_init_thread_data(); - POINT pos = virtual_screen_to_root( x, y ); - -- if (keyboard_grabbed) -- { -- WARN( "refusing to warp to %u, %u\n", pos.x, pos.y ); -- return FALSE; -- } -- - if (!clipping_cursor && - XGrabPointer( data->display, root_window, False, - PointerMotionMask | ButtonPressMask | ButtonReleaseMask, -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 145fe5313d4..4e6dcceb441 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -421,7 +421,6 @@ extern Colormap default_colormap DECLSPEC_HIDDEN; - extern XPixmapFormatValues **pixmap_formats DECLSPEC_HIDDEN; - extern Window root_window DECLSPEC_HIDDEN; - extern BOOL clipping_cursor DECLSPEC_HIDDEN; --extern BOOL keyboard_grabbed DECLSPEC_HIDDEN; - extern unsigned int screen_bpp DECLSPEC_HIDDEN; - extern BOOL use_xkb DECLSPEC_HIDDEN; - extern BOOL usexrandr DECLSPEC_HIDDEN; -From eb12dcf3498a14e8d26c2e4b9a53498e61b43ebc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 17 Dec 2019 16:58:07 +0100 -Subject: [PATCH] Revert "winex11.drv: Only call XWarpPointer if we can get - exclusive pointer grab." - -This reverts commit 74efb3e872aebf57a42d62b52e149ae26f320c9a. - -We are now only activating windows only once the window manager has -released its grab, it should be safer to let them move the pointer -around and this should not be needed anymore. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47771 ---- - dlls/winex11.drv/mouse.c | 13 ------------- - 1 file changed, 13 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 1d6f9d1c5b9..157ba0be84e 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -1508,21 +1508,8 @@ BOOL CDECL X11DRV_SetCursorPos( INT x, INT y ) - struct x11drv_thread_data *data = x11drv_init_thread_data(); - POINT pos = virtual_screen_to_root( x, y ); - -- if (!clipping_cursor && -- XGrabPointer( data->display, root_window, False, -- PointerMotionMask | ButtonPressMask | ButtonReleaseMask, -- GrabModeAsync, GrabModeAsync, None, None, CurrentTime ) != GrabSuccess) -- { -- WARN( "refusing to warp pointer to %u, %u without exclusive grab\n", pos.x, pos.y ); -- return FALSE; -- } -- - XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0, pos.x, pos.y ); - data->warp_serial = NextRequest( data->display ); -- -- if (!clipping_cursor) -- XUngrabPointer( data->display, CurrentTime ); -- - XNoOp( data->display ); - XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */ - TRACE( "warped to %d,%d serial %lu\n", x, y, data->warp_serial ); -From 308c42c712eee011da4b1e53c3172c1ca226eed3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 21 May 2021 14:57:46 +0200 -Subject: [PATCH] user32: Implement rudimentary EnableMouseInPointer support. - -CW-Bug-Id: 18943 ---- - dlls/user32/input.c | 9 +++++---- - dlls/user32/message.c | 32 ++++++++++++++++++++++++++++++++ - dlls/user32/user_private.h | 1 + - include/winuser.h | 26 ++++++++++++++++++++++++++ - 4 files changed, 64 insertions(+), 4 deletions(-) - -diff --git a/dlls/user32/input.c b/dlls/user32/input.c -index a3b5916a01f..bbc3d8cba63 100644 ---- a/dlls/user32/input.c -+++ b/dlls/user32/input.c -@@ -1144,15 +1144,16 @@ TrackMouseEvent (TRACKMOUSEEVENT *ptme) - return TRUE; - } - -+BOOL enable_mouse_in_pointer = FALSE; -+ - /*********************************************************************** - * EnableMouseInPointer (USER32.@) - */ - BOOL WINAPI EnableMouseInPointer(BOOL enable) - { -- FIXME("(%#x) stub\n", enable); -- -- SetLastError(ERROR_CALL_NOT_IMPLEMENTED); -- return FALSE; -+ FIXME("(%#x) semi-stub\n", enable); -+ enable_mouse_in_pointer = TRUE; -+ return TRUE; - } - - static DWORD CALLBACK devnotify_window_callback(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header) -diff --git a/dlls/user32/message.c b/dlls/user32/message.c -index 77902dd0c87..bd22a33b1f3 100644 ---- a/dlls/user32/message.c -+++ b/dlls/user32/message.c -@@ -2597,6 +2597,38 @@ static BOOL process_mouse_message( MSG *msg, UINT hw_id, ULONG_PTR extra_info, H - in the WM_SETCURSOR message even if it's non-client mouse message */ - SendMessageW( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message )); - -+ if (enable_mouse_in_pointer) switch (msg->message) -+ { -+ case WM_MOUSEMOVE: -+ case WM_LBUTTONDOWN: -+ case WM_LBUTTONUP: -+ case WM_RBUTTONDOWN: -+ case WM_RBUTTONUP: -+ case WM_MBUTTONDOWN: -+ case WM_MBUTTONUP: -+ case WM_XBUTTONDOWN: -+ case WM_XBUTTONUP: -+ { -+ WORD flags = POINTER_MESSAGE_FLAG_INRANGE|POINTER_MESSAGE_FLAG_INCONTACT|POINTER_MESSAGE_FLAG_PRIMARY; -+ if (msg->message == WM_LBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; -+ if (msg->message == WM_RBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; -+ if (msg->message == WM_MBUTTONDOWN) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_LBUTTON) flags |= POINTER_MESSAGE_FLAG_FIRSTBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_RBUTTON) flags |= POINTER_MESSAGE_FLAG_SECONDBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_MBUTTON) flags |= POINTER_MESSAGE_FLAG_THIRDBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON1) flags |= POINTER_MESSAGE_FLAG_FOURTHBUTTON; -+ if (msg->message == WM_XBUTTONDOWN && LOWORD( msg->wParam ) == MK_XBUTTON2) flags |= POINTER_MESSAGE_FLAG_FIFTHBUTTON; -+ SendMessageW( msg->hwnd, WM_POINTERUPDATE, MAKELONG( 1, flags ), MAKELONG( msg->pt.x, msg->pt.y ) ); -+ break; -+ } -+ case WM_MOUSEWHEEL: -+ SendMessageW( msg->hwnd, WM_POINTERWHEEL, MAKELONG( 1, HIWORD( msg->wParam ) ), MAKELONG( msg->pt.x, msg->pt.y ) ); -+ break; -+ case WM_MOUSEHWHEEL: -+ SendMessageW( msg->hwnd, WM_POINTERHWHEEL, MAKELONG( 1, HIWORD( msg->wParam ) ), MAKELONG( msg->pt.x, msg->pt.y ) ); -+ break; -+ } -+ - msg->message = message; - return !eatMsg; - } -diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h -index 6923ddb2906..63e14c20a3d 100644 ---- a/dlls/user32/user_private.h -+++ b/dlls/user32/user_private.h -@@ -152,6 +152,7 @@ static inline BOOL is_broadcast( HWND hwnd ) - } - - extern HMODULE user32_module DECLSPEC_HIDDEN; -+extern BOOL enable_mouse_in_pointer DECLSPEC_HIDDEN; - - struct dce; - struct tagWND; -diff --git a/include/winuser.h b/include/winuser.h -index 1d37bd44344..198c3ded77f 100644 ---- a/include/winuser.h -+++ b/include/winuser.h -@@ -3475,6 +3475,32 @@ typedef struct tagMENUGETOBJECTINFO - void *pvObj; - } MENUGETOBJECTINFO, *PMENUGETOBJECTINFO; - -+#define POINTER_MESSAGE_FLAG_NEW 0x00000001 -+#define POINTER_MESSAGE_FLAG_INRANGE 0x00000002 -+#define POINTER_MESSAGE_FLAG_INCONTACT 0x00000004 -+#define POINTER_MESSAGE_FLAG_FIRSTBUTTON 0x00000010 -+#define POINTER_MESSAGE_FLAG_SECONDBUTTON 0x00000020 -+#define POINTER_MESSAGE_FLAG_THIRDBUTTON 0x00000040 -+#define POINTER_MESSAGE_FLAG_FOURTHBUTTON 0x00000080 -+#define POINTER_MESSAGE_FLAG_FIFTHBUTTON 0x00000100 -+#define POINTER_MESSAGE_FLAG_PRIMARY 0x00002000 -+#define POINTER_MESSAGE_FLAG_CONFIDENCE 0x00004000 -+#define POINTER_MESSAGE_FLAG_CANCELED 0x00008000 -+ -+#define GET_POINTERID_WPARAM(wparam) (LOWORD(wparam)) -+#define IS_POINTER_FLAG_SET_WPARAM(wparam, flags) ((HIWORD(wparam) & (flags)) == (flags)) -+#define IS_POINTER_NEW_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_NEW) -+#define IS_POINTER_INRANGE_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_INRANGE) -+#define IS_POINTER_INCONTACT_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_INCONTACT) -+#define IS_POINTER_FIRSTBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_FIRSTBUTTON) -+#define IS_POINTER_SECONDBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_SECONDBUTTON) -+#define IS_POINTER_THIRDBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_THIRDBUTTON) -+#define IS_POINTER_FOURTHBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_FOURTHBUTTON) -+#define IS_POINTER_FIFTHBUTTON_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_FIFTHBUTTON) -+#define IS_POINTER_PRIMARY_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_PRIMARY) -+#define HAS_POINTER_CONFIDENCE_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_CONFIDENCE) -+#define IS_POINTER_CANCELED_WPARAM(wparam) IS_POINTER_FLAG_SET_WPARAM(wparam, POINTER_MESSAGE_FLAG_CANCELED) -+ - #if defined(_WINGDI_) && !defined(NOGDI) - WINUSERAPI LONG WINAPI ChangeDisplaySettingsA(LPDEVMODEA,DWORD); - WINUSERAPI LONG WINAPI ChangeDisplaySettingsW(LPDEVMODEW,DWORD); -From 626129a6ea5b7b948d192d53c94137cf0b80e938 Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Mon, 15 Mar 2021 12:01:25 -0500 -Subject: [PATCH] winex11.drv: Flush X connection after ungrabbing the pointer. - -CW-Bug-Id: #18169 ---- - dlls/winex11.drv/mouse.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 157ba0be84e..d02163cbaa8 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -497,7 +497,11 @@ void ungrab_clipping_window(void) - - TRACE( "no longer clipping\n" ); - XUnmapWindow( display, clip_window ); -- if (clipping_cursor) XUngrabPointer( display, CurrentTime ); -+ if (clipping_cursor) -+ { -+ XUngrabPointer( display, CurrentTime ); -+ XFlush( display ); -+ } - clipping_cursor = FALSE; - SendNotifyMessageW( GetDesktopWindow(), WM_X11DRV_CLIP_CURSOR_NOTIFY, 0, 0 ); - } -From 42ffa67ffd96b6f43e01acf844c12728b0824619 Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Mon, 7 Dec 2020 09:31:52 +0100 -Subject: [PATCH] winex11.drv: Recognize the keyboard in a locale-independent - way. - -Try to recognize the keyboard comparing keysyms instead of converting -them to multibyte strings, which makes the process locale-dependent and -therefore more fragile. - -Unfortunately this means that the layout tables might need to be -updated. However, this change is known to fix the recognitions of a few -keys in the French layout. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30984 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45605 -CW-Bug-Id: #16793 ---- - dlls/winex11.drv/keyboard.c | 64 ++++++++++++++++++------------------- - 1 file changed, 31 insertions(+), 33 deletions(-) - -diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c -index 567f3d845b6..450211a17f5 100644 ---- a/dlls/winex11.drv/keyboard.c -+++ b/dlls/winex11.drv/keyboard.c -@@ -1417,6 +1417,35 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev ) - return TRUE; - } - -+/* From the point of view of this function there are two types of -+ * keys: those for which the mapping to vkey and scancode depends on -+ * the keyboard layout (i.e., letters, numbers, punctuation) and those -+ * for which it doesn't (control keys); since this function is used to -+ * recognize the keyboard layout and map keysyms to vkeys and -+ * scancodes, we are only concerned about the first type, and map -+ * everything in the second type to zero. -+ */ -+static char keysym_to_char( KeySym keysym ) -+{ -+ /* Dead keys */ -+ if (0xfe50 <= keysym && keysym < 0xfed0) -+ return KEYBOARD_MapDeadKeysym( keysym ); -+ -+ /* Control keys (there is nothing allocated below 0xfc00, but I -+ take some margin in case something is added in the future) */ -+ if (0xf000 <= keysym && keysym < 0x10000) -+ return 0; -+ -+ /* XFree86 vendor keys */ -+ if (0x10000000 <= keysym) -+ return 0; -+ -+ /* "Normal" keys: return last octet, because our tables don't have -+ more than that; it would be better to extend the tables and -+ compare the whole keysym, but it's a lot of work... */ -+ return keysym & 0xff; -+} -+ - /********************************************************************** - * X11DRV_KEYBOARD_DetectLayout - * -@@ -1447,24 +1476,7 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) - /* get data for keycode from X server */ - for (i = 0; i < syms; i++) { - if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; -- /* Allow both one-byte and two-byte national keysyms */ -- if ((keysym < 0x8000) && (keysym != ' ')) -- { --#ifdef HAVE_XKB -- if (!use_xkb || !XkbTranslateKeySym(display, &keysym, 0, &ckey[keyc][i], 1, NULL)) --#endif -- { -- TRACE("XKB could not translate keysym %04lx\n", keysym); -- /* FIXME: query what keysym is used as Mode_switch, fill XKeyEvent -- * with appropriate ShiftMask and Mode_switch, use XLookupString -- * to get character in the local encoding. -- */ -- ckey[keyc][i] = keysym & 0xFF; -- } -- } -- else { -- ckey[keyc][i] = KEYBOARD_MapDeadKeysym(keysym); -- } -+ ckey[keyc][i] = keysym_to_char(keysym); - } - } - -@@ -1674,21 +1686,7 @@ void X11DRV_InitKeyboard( Display *display ) - int maxlen=0,maxval=-1,ok; - for (i=0; i -Date: Mon, 7 Dec 2020 09:49:53 +0100 -Subject: [PATCH] winex11.drv: Dump keysyms and translations for all keys. - -Dump all we can see about the user keyboard, so that their +keyboard -logs can be used to fix layout tables. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=30984 -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45605 -CW-Bug-Id: #16793 ---- - dlls/winex11.drv/keyboard.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c -index 450211a17f5..d04d1db9102 100644 ---- a/dlls/winex11.drv/keyboard.c -+++ b/dlls/winex11.drv/keyboard.c -@@ -1477,6 +1477,19 @@ X11DRV_KEYBOARD_DetectLayout( Display *display ) - for (i = 0; i < syms; i++) { - if (!(keysym = keycode_to_keysym (display, keyc, i))) continue; - ckey[keyc][i] = keysym_to_char(keysym); -+ if (TRACE_ON(keyboard)) -+ { -+ char buf[32]; -+ WCHAR bufW[32]; -+ int len, lenW; -+ KeySym orig_keysym = keysym; -+ len = XkbTranslateKeySym(display, &keysym, 0, buf, sizeof(buf), NULL); -+ lenW = MultiByteToWideChar(CP_UNIXCP, 0, buf, len, bufW, ARRAY_SIZE(bufW)); -+ if (lenW < ARRAY_SIZE(bufW)) -+ bufW[lenW] = 0; -+ TRACE("keycode %u, index %d, orig_keysym 0x%04lx, keysym 0x%04lx, buf %s, bufW %s\n", -+ keyc, i, orig_keysym, keysym, debugstr_a(buf), debugstr_w(bufW)); -+ } - } - } - -From 1eb3f357442e867566cfef2e423a0542e8c53e29 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 15 Mar 2021 11:31:37 -0500 -Subject: [PATCH] HACK: winex11.drv: Add WINE_ALLOW_XIM option. - ---- - dlls/winex11.drv/x11drv_main.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 64f12cd96d2..e5a1ccf775a 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -642,6 +642,13 @@ static BOOL process_attach(void) - dlopen( SONAME_LIBXEXT, RTLD_NOW|RTLD_GLOBAL ); - #endif - -+ { -+ const char *e = getenv("WINE_ALLOW_XIM"); -+ if(e){ -+ use_xim = IS_OPTION_TRUE(*e); -+ } -+ } -+ - setup_options(); - - if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE; -From f0b709b13fbb5f269f929cfe67b62b8704d1e800 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Wed, 20 Jun 2018 15:07:28 -0500 -Subject: [PATCH] HACK: user32: Remove hooks that time out. - -In accordance with Win7+ behaviour. ---- - dlls/user32/hook.c | 17 +++++++++++------ - 1 file changed, 11 insertions(+), 6 deletions(-) - -diff --git a/dlls/user32/hook.c b/dlls/user32/hook.c -index 159797020f2..e8a31100646 100644 ---- a/dlls/user32/hook.c -+++ b/dlls/user32/hook.c -@@ -387,6 +387,7 @@ void *get_hook_proc( void *proc, const WCHAR *module, HMODULE *free_module ) - static LRESULT call_hook( struct hook_info *info, INT code, WPARAM wparam, LPARAM lparam ) - { - DWORD_PTR ret = 0; -+ LRESULT lres = 0; - - if (info->tid) - { -@@ -400,20 +401,24 @@ static LRESULT call_hook( struct hook_info *info, INT code, WPARAM wparam, LPARA - switch(info->id) - { - case WH_KEYBOARD_LL: -- MSG_SendInternalMessageTimeout( info->pid, info->tid, WM_WINE_KEYBOARD_LL_HOOK, -- wparam, (LPARAM)&h_extra, SMTO_ABORTIFHUNG, -- get_ll_hook_timeout(), &ret ); -+ lres = MSG_SendInternalMessageTimeout( info->pid, info->tid, WM_WINE_KEYBOARD_LL_HOOK, -+ wparam, (LPARAM)&h_extra, SMTO_ABORTIFHUNG, get_ll_hook_timeout(), &ret ); - break; - case WH_MOUSE_LL: -- MSG_SendInternalMessageTimeout( info->pid, info->tid, WM_WINE_MOUSE_LL_HOOK, -- wparam, (LPARAM)&h_extra, SMTO_ABORTIFHUNG, -- get_ll_hook_timeout(), &ret ); -+ lres = MSG_SendInternalMessageTimeout( info->pid, info->tid, WM_WINE_MOUSE_LL_HOOK, -+ wparam, (LPARAM)&h_extra, SMTO_ABORTIFHUNG, get_ll_hook_timeout(), &ret ); - break; - default: - ERR("Unknown hook id %d\n", info->id); - assert(0); - break; - } -+ -+ if (!lres && GetLastError() == ERROR_TIMEOUT) -+ { -+ TRACE("Hook %p timed out; removing it.\n", info->handle); -+ NtUserUnhookWindowsHookEx( info->handle ); -+ } - } - else if (info->proc) - { -From 67274cfa92b7ace6693b14f4911dcf9b4084fae3 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Wed, 20 Jun 2018 15:10:08 -0500 -Subject: [PATCH] HACK: server: Don't check for a hung queue when sending - low-level hooks. - -Since user32 does this. - -This logic is independent of the SMTO_ABORTIFHUNG logic on Windows. In fact, IsHungAppWindow() uses yet another algorithm. ---- - server/queue.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/server/queue.c b/server/queue.c -index 77ee67066e0..dea4b835ab2 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -1661,7 +1661,6 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa - - if (!(hook_thread = get_first_global_hook( id ))) return 0; - if (!(queue = hook_thread->queue)) return 0; -- if (is_queue_hung( queue )) return 0; - - if (!(msg = mem_alloc( sizeof(*msg) ))) return 0; - -From d0ce33cfce4a46244ac6cef9d3a6d043e64e837a Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 12 Feb 2018 09:15:07 -0600 -Subject: [PATCH] winex11.drv: Log more information about X11 errors. - ---- - dlls/winex11.drv/x11drv_main.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index e5a1ccf775a..8c2688f2a58 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -316,6 +316,9 @@ static int error_handler( Display *display, XErrorEvent *error_evt ) - error_evt->serial, error_evt->request_code ); - DebugBreak(); /* force an entry in the debugger */ - } -+ TRACE("passing on error %d req %d:%d res 0x%lx\n", -+ error_evt->error_code, error_evt->request_code, -+ error_evt->minor_code, error_evt->resourceid); - old_error_handler( display, error_evt ); - return 0; - } -From 19b86fe3d35e00c8985e0c616cd7bc2eeb5e2df7 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Wed, 27 Jun 2018 10:06:48 -0500 -Subject: [PATCH] HACK: winex11.drv: Let the WM focus our windows by default. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This should fix game windows not being in focus when first started -and when exiting, which can cause surprising keyboard behavior (e.g. -accidentally Alt-F4ing Steam itself, which is in the background). - -This may break modal dialogs in some WMs (fvwm2?) which do not respect -our responses to WM_TAKE_FOCUS. For games that show that issue, we can -re-enable UseTakeFocus. - -From Zeb: - -""" -The basic problem, if I understand it correctly, is that Wine uses the -"globally active" focus model by default. This means that the window -manager won't focus our windows unless we respond in the affirmative to -a WM_TAKE_FOCUS event. Since the GUI thread isn't processing messages, -this doesn't happen. - -Luckily, there is a very easy workaround: create the registry key -HKCU\Software\Wine\X11 Driver and set the somewhat inaptly named value -"UseTakeFocus" to "N" (i.e. No). This causes Wine to use the "locally -active" model instead, which means that the window manager will focus -our windows when it sees fit—i.e. when the user clicks on them, or when -they are created. -""" ---- - dlls/winex11.drv/x11drv_main.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 8c2688f2a58..6bf4a0a4211 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -68,7 +68,7 @@ BOOL usexrandr = TRUE; - BOOL usexcomposite = TRUE; - BOOL use_xfixes = FALSE; - BOOL use_xkb = TRUE; --BOOL use_take_focus = TRUE; -+BOOL use_take_focus = FALSE; - BOOL use_primary_selection = FALSE; - BOOL use_system_cursors = TRUE; - BOOL show_systray = TRUE; diff --git a/patches/proton/39-proton-cpu-topology-overrides.patch b/patches/proton/39-proton-cpu-topology-overrides.patch deleted file mode 100644 index 05de7bd79..000000000 --- a/patches/proton/39-proton-cpu-topology-overrides.patch +++ /dev/null @@ -1,596 +0,0 @@ -From e6c96f88d8f78a9890a5b96a8e85406ad9695f3c Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 2 Nov 2020 23:03:20 +0300 -Subject: [PATCH] ntdll: (HACK) Add variable to report all logical CPUs as - physical cores. - ---- - dlls/ntdll/unix/system.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c -index 0b83761ed46..bf3d6c34f14 100644 ---- a/dlls/ntdll/unix/system.c -+++ b/dlls/ntdll/unix/system.c -@@ -830,7 +830,8 @@ static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION * - static const char core_info[] = "/sys/devices/system/cpu/cpu%u/topology/%s"; - static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s"; - static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap"; -- -+ const char *env_fake_logical_cores = getenv("WINE_LOGICAL_CPUS_AS_CORES"); -+ BOOL fake_logical_cpus_as_cores = env_fake_logical_cores && atoi(env_fake_logical_cores); - FILE *fcpu_list, *fnuma_list, *f; - DWORD len = 0, beg, end, i, j, r, num_cpus = 0, max_cpus = 0; - char op, name[MAX_PATH]; -@@ -902,7 +903,7 @@ static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION * - { - /* Mask of logical threads sharing same physical core in kernel core numbering. */ - sprintf(name, core_info, i, "thread_siblings"); -- if(!sysfs_parse_bitmap(name, &thread_mask)) thread_mask = 1< -Date: Fri, 20 Nov 2020 18:01:11 +0300 -Subject: [PATCH] ntdll: Implement CPU topology override. - ---- - dlls/ntdll/unix/server.c | 3 + - dlls/ntdll/unix/system.c | 167 ++++++++++++++++++++++++++++++--- - dlls/ntdll/unix/thread.c | 15 ++- - dlls/ntdll/unix/unix_private.h | 1 + - include/wine/server_protocol.h | 9 +- - server/process.c | 7 ++ - server/process.h | 1 + - server/protocol.def | 7 ++ - server/thread.c | 20 +++- - server/trace.c | 19 ++++ - 10 files changed, 228 insertions(+), 21 deletions(-) - -diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c -index b1d3e863240..7b0c7c32f58 100644 ---- a/dlls/ntdll/unix/server.c -+++ b/dlls/ntdll/unix/server.c -@@ -1467,6 +1467,7 @@ void CDECL server_init_process_done( void *relay ) - PEB *peb = NtCurrentTeb()->Peb; - IMAGE_NT_HEADERS *nt = get_exe_nt_header(); - void *entry, *teb; -+ struct cpu_topology_override *cpu_override = get_cpu_topology_override(); - NTSTATUS status; - int suspend; - -@@ -1488,6 +1489,8 @@ void CDECL server_init_process_done( void *relay ) - /* Signal the parent process to continue */ - SERVER_START_REQ( init_process_done ) - { -+ if (cpu_override) -+ wine_server_add_data( req, cpu_override, sizeof(*cpu_override) ); - req->teb = wine_server_client_ptr( teb ); - req->peb = NtCurrentTeb64() ? NtCurrentTeb64()->Peb : wine_server_client_ptr( peb ); - #ifdef __i386__ -diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c -index bf3d6c34f14..fc8165f2828 100644 ---- a/dlls/ntdll/unix/system.c -+++ b/dlls/ntdll/unix/system.c -@@ -29,6 +29,7 @@ - #include - #include - #include -+#include - #include - #include - #ifdef HAVE_SYS_PARAM_H -@@ -165,6 +166,12 @@ struct smbios_boot_info - #define RSMB 0x52534D42 - - SYSTEM_CPU_INFORMATION cpu_info = { 0 }; -+static struct -+{ -+ struct cpu_topology_override mapping; -+ BOOL smt; -+} -+cpu_override; - - /******************************************************************************* - * Architecture specific feature detection for CPUs -@@ -475,6 +482,88 @@ static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info ) - - #endif /* End architecture specific feature detection for CPUs */ - -+static void fill_cpu_override(unsigned int host_cpu_count) -+{ -+ const char *env_override = getenv("WINE_CPU_TOPOLOGY"); -+ unsigned int i; -+ char *s; -+ -+ if (!env_override) -+ return; -+ -+ cpu_override.mapping.cpu_count = strtol(env_override, &s, 10); -+ if (s == env_override) -+ goto error; -+ -+ if (!cpu_override.mapping.cpu_count || cpu_override.mapping.cpu_count > MAXIMUM_PROCESSORS) -+ { -+ ERR("Invalid logical CPU count %u, limit %u.\n", cpu_override.mapping.cpu_count, MAXIMUM_PROCESSORS); -+ goto error; -+ } -+ -+ if (tolower(*s) == 's') -+ { -+ cpu_override.mapping.cpu_count *= 2; -+ if (cpu_override.mapping.cpu_count > MAXIMUM_PROCESSORS) -+ { -+ ERR("Logical CPU count exceeds limit %u.\n", MAXIMUM_PROCESSORS); -+ goto error; -+ } -+ cpu_override.smt = TRUE; -+ ++s; -+ } -+ if (*s != ':') -+ goto error; -+ ++s; -+ for (i = 0; i < cpu_override.mapping.cpu_count; ++i) -+ { -+ char *next; -+ -+ if (i) -+ { -+ if (*s != ',') -+ { -+ if (!*s) -+ ERR("Incomplete host CPU mapping string, %u CPUs mapping required.\n", -+ cpu_override.mapping.cpu_count); -+ goto error; -+ } -+ ++s; -+ } -+ -+ cpu_override.mapping.host_cpu_id[i] = strtol(s, &next, 10); -+ if (next == s) -+ goto error; -+ if (cpu_override.mapping.host_cpu_id[i] >= host_cpu_count) -+ { -+ ERR("Invalid host CPU index %u (host_cpu_count %u).\n", -+ cpu_override.mapping.host_cpu_id[i], host_cpu_count); -+ goto error; -+ } -+ s = next; -+ } -+ if (*s) -+ goto error; -+ -+ ERR("Overriding CPU configuration, %u logical CPUs, host CPUs ", cpu_override.mapping.cpu_count); -+ for (i = 0; i < cpu_override.mapping.cpu_count; ++i) -+ { -+ if (i) -+ ERR(","); -+ ERR("%u", cpu_override.mapping.host_cpu_id[i]); -+ } -+ ERR("\n"); -+ return; -+error: -+ cpu_override.mapping.cpu_count = 0; -+ ERR("Invalid WINE_CPU_TOPOLOGY string %s (%s).\n", debugstr_a(env_override), debugstr_a(s)); -+} -+ -+struct cpu_topology_override *get_cpu_topology_override(void) -+{ -+ return cpu_override.mapping.cpu_count ? &cpu_override.mapping : NULL; -+} -+ - /****************************************************************** - * init_cpu_info - * -@@ -508,7 +597,11 @@ void init_cpu_info(void) - num = 1; - FIXME("Detecting the number of processors is not supported.\n"); - #endif -- peb->NumberOfProcessors = num; -+ -+ fill_cpu_override(num); -+ -+ peb->NumberOfProcessors = cpu_override.mapping.cpu_count -+ ? cpu_override.mapping.cpu_count : num; - get_cpuinfo( &cpu_info ); - TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n", - cpu_info.Architecture, cpu_info.Level, cpu_info.Revision, cpu_info.FeatureSet ); -@@ -860,6 +953,12 @@ static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION * - if (op == '-') fscanf(fcpu_list, "%u%c ", &end, &op); - else end = beg; - -+ if (cpu_override.mapping.cpu_count) -+ { -+ beg = 0; -+ end = cpu_override.mapping.cpu_count - 1; -+ } -+ - for(i = beg; i <= end; i++) - { - DWORD phys_core = 0; -@@ -873,7 +972,9 @@ static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION * - - if (relation == RelationAll || relation == RelationProcessorPackage) - { -- sprintf(name, core_info, i, "physical_package_id"); -+ sprintf(name, core_info, cpu_override.mapping.cpu_count ? cpu_override.mapping.host_cpu_id[i] : i, -+ "physical_package_id"); -+ - f = fopen(name, "r"); - if (f) - { -@@ -881,6 +982,7 @@ static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION * - fclose(f); - } - else r = 0; -+ - if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, r, (ULONG_PTR)1 << i)) - { - fclose(fcpu_list); -@@ -903,21 +1005,36 @@ static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION * - { - /* Mask of logical threads sharing same physical core in kernel core numbering. */ - sprintf(name, core_info, i, "thread_siblings"); -- if(fake_logical_cpus_as_cores || !sysfs_parse_bitmap(name, &thread_mask)) thread_mask = (ULONG_PTR)1<cpu_count; ++i) -+ if (override->host_cpu_id[i] == processor) -+ return i; -+ -+ WARN("Thread is running on processor which is not in the defined override.\n"); -+ } - #endif - - if (peb->NumberOfProcessors > 1) -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index 39ab7912490..b29de19ec8e 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -279,6 +279,7 @@ extern NTSTATUS open_unix_file( HANDLE *handle, const char *unix_name, ACCESS_MA - ULONG options, void *ea_buffer, ULONG ea_length ) DECLSPEC_HIDDEN; - extern void init_files(void) DECLSPEC_HIDDEN; - extern void init_cpu_info(void) DECLSPEC_HIDDEN; -+extern struct cpu_topology_override *get_cpu_topology_override(void) DECLSPEC_HIDDEN; - extern void add_completion( HANDLE handle, ULONG_PTR value, NTSTATUS status, ULONG info, BOOL async ) DECLSPEC_HIDDEN; - - extern void dbg_init(void) DECLSPEC_HIDDEN; - -diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h -index f4f45d958be..aed7090572b 100644 ---- a/include/wine/server_protocol.h -+++ b/include/wine/server_protocol.h -@@ -794,6 +794,12 @@ typedef struct - lparam_t info; - } cursor_pos_t; - -+struct cpu_topology_override -+{ -+ unsigned int cpu_count; -+ unsigned char host_cpu_id[64]; -+}; -+ - - - -@@ -895,6 +901,7 @@ struct init_process_done_request - mod_handle_t module; - client_ptr_t ldt_copy; - client_ptr_t entry; -+ /* VARARG(cpu_override,cpu_topology_override); */ - }; - struct init_process_done_reply - { -diff --git a/server/process.c b/server/process.c -index 97e074a5261..d1f9ab764f7 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -73,6 +73,7 @@ static void process_destroy( struct object *obj ); - static int process_get_esync_fd( struct object *obj, enum esync_type *type ); - static unsigned int process_get_fsync_idx( struct object *obj, enum fsync_type *type ); - static void terminate_process( struct process *process, struct thread *skip, int exit_code ); -+static void set_process_affinity( struct process *process, affinity_t affinity ); - - static const struct object_ops process_ops = - { -@@ -550,6 +551,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all, - process->rawinput_kbd = NULL; - process->esync_fd = -1; - process->fsync_idx = 0; -+ process->cpu_override.cpu_count = 0; - list_init( &process->kernel_object ); - list_init( &process->thread_list ); - list_init( &process->locks ); -@@ -1368,6 +1370,8 @@ DECL_HANDLER(init_process_done) - { - struct process_dll *dll; - struct process *process = current->process; -+ const struct cpu_topology_override *cpu_override = get_req_data(); -+ unsigned int have_cpu_override = get_req_data_size() / sizeof(*cpu_override); - struct memory_view *view; - client_ptr_t base; - const pe_image_info_t *image_info; -@@ -1397,6 +1401,9 @@ DECL_HANDLER(init_process_done) - if (req->gui) process->idle_event = create_event( NULL, NULL, 0, 1, 0, NULL ); - if (process->debugger) set_process_debug_flag( process, 1 ); - reply->suspend = (current->suspend || process->suspend); -+ -+ if (have_cpu_override) -+ process->cpu_override = *cpu_override; - } - - /* open a handle to a process */ -diff --git a/server/process.h b/server/process.h -index 430fd365508..d1b8b3fc222 100644 ---- a/server/process.h -+++ b/server/process.h -@@ -100,6 +100,7 @@ struct process - struct list kernel_object; /* list of kernel object pointers */ - int esync_fd; /* esync file descriptor (signaled on exit) */ - unsigned int fsync_idx; -+ struct cpu_topology_override cpu_override; /* Overridden CPUs to host CPUs mapping. */ - }; - - #define CPU_FLAG(cpu) (1 << (cpu)) -diff --git a/server/protocol.def b/server/protocol.def -index 48f9f4fae90..0f2fe077b80 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -810,6 +810,12 @@ typedef struct - lparam_t info; - } cursor_pos_t; - -+struct cpu_topology_override -+{ -+ unsigned int cpu_count; -+ unsigned char host_cpu_id[64]; -+}; -+ - /****************************************************************/ - /* Request declarations */ - -@@ -877,6 +883,7 @@ typedef struct - - /* Signal the end of the process initialization */ - @REQ(init_process_done) -+ VARARG(cpu_override,cpu_topology_override); /* Overridden CPUs to host CPUs mapping. */ - client_ptr_t teb; /* TEB of new thread (in process address space) */ - client_ptr_t peb; /* PEB of new process (in process address space) */ - client_ptr_t ldt_copy; /* address of LDT copy (in process address space) */ -diff --git a/server/thread.c b/server/thread.c -index 0fb3aa0e727..31043c3df33 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -605,8 +605,19 @@ int set_thread_affinity( struct thread *thread, affinity_t affinity ) - - CPU_ZERO( &set ); - for (i = 0, mask = 1; mask; i++, mask <<= 1) -- if (affinity & mask) CPU_SET( i, &set ); -- -+ if (affinity & mask) -+ { -+ if (thread->process->cpu_override.cpu_count) -+ { -+ if (i >= thread->process->cpu_override.cpu_count) -+ break; -+ CPU_SET( thread->process->cpu_override.host_cpu_id[i], &set ); -+ } -+ else -+ { -+ CPU_SET( i, &set ); -+ } -+ } - ret = sched_setaffinity( thread->unix_tid, sizeof(set), &set ); - } - #endif -@@ -1500,7 +1511,7 @@ DECL_HANDLER(init_thread) - - if (!process->parent_id) - process->affinity = current->affinity = get_thread_affinity( current ); -- else -+ else if (!process->cpu_override.cpu_count) - set_thread_affinity( current, current->affinity ); - - debug_level = max( debug_level, req->debug_level ); -@@ -1514,10 +1525,12 @@ DECL_HANDLER(init_thread) - current->unix_tid = req->unix_tid; - current->teb = req->teb; - current->entry_point = req->entry; -+ struct process *process = current->process; - - init_thread_context( current ); - generate_debug_event( current, DbgCreateThreadStateChange, &req->entry ); -- set_thread_affinity( current, current->affinity ); -+ if (!process->cpu_override.cpu_count) -+ set_thread_affinity( current, current->affinity ); - - reply->pid = get_process_id( current->process ); - reply->tid = get_thread_id( current ); -diff --git a/server/trace.c b/server/trace.c -index e3a29beb6da..7df5681357b 100644 ---- a/server/trace.c -+++ b/server/trace.c -@@ -1293,6 +1293,24 @@ static void dump_varargs_handle_infos( const char *prefix, data_size_t size ) - fputc( '}', stderr ); - } - -+static void dump_varargs_cpu_topology_override( const char *prefix, data_size_t size ) -+{ -+ const struct cpu_topology_override *cpu_topology = cur_data; -+ unsigned int i; -+ -+ if (size < sizeof(*cpu_topology)) -+ return; -+ -+ fprintf( stderr,"%s{", prefix ); -+ for (i = 0; i < cpu_topology->cpu_count; ++i) -+ { -+ if (i) fputc( ',', stderr ); -+ fprintf( stderr, "%u", cpu_topology->host_cpu_id[i] ); -+ } -+ fputc( '}', stderr ); -+ remove_data( size ); -+} -+ - typedef void (*dump_func)( const void *req ); - - /* Everything below this line is generated automatically by tools/make_requests */ -@@ -1369,6 +1387,7 @@ static void dump_init_process_done_request( const struct init_process_done_reque - dump_uint64( ", module=", &req->module ); - dump_uint64( ", ldt_copy=", &req->ldt_copy ); - dump_uint64( ", entry=", &req->entry ); -+ dump_varargs_cpu_topology_override( ", cpu_override=", cur_size ); - } - - static void dump_init_process_done_reply( const struct init_process_done_reply *req ) - diff --git a/patches/proton/41-proton-07_nfs_registry.patch b/patches/proton/41-proton-07_nfs_registry.patch deleted file mode 100644 index 7a31dace4..000000000 --- a/patches/proton/41-proton-07_nfs_registry.patch +++ /dev/null @@ -1,21 +0,0 @@ -From a90109abaa6114c785786b0b41dcaaa103ab59dc Mon Sep 17 00:00:00 2001 -From: Anna Lasky -Date: Fri, 5 Feb 2021 08:31:07 -0600 -Subject: [PATCH] wine.inf: Use built-in atiadlxx for Need For Speed - ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 928c6883372..fd529938508 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4030,6 +4030,7 @@ HKCU,Software\Wine\AppDefaults\h1_sp64_ship.exe\DllOverrides,"atiadlxx",,"builti - HKCU,Software\Wine\AppDefaults\h1_mp64_ship.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\iw7_ship.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\NFS16.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"amd_ags_x64",,"" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. diff --git a/patches/proton/45-proton-08_FH4_registry.patch b/patches/proton/45-proton-08_FH4_registry.patch deleted file mode 100644 index 390b5d1ff..000000000 --- a/patches/proton/45-proton-08_FH4_registry.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 7c5d821826cdd2c4251cc65ecc7119537f8025d6 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 21 Apr 2021 18:40:25 +0300 -Subject: [PATCH] wine.inf: Set amd_ags_x64 to built-in for Forza Horizon 4. - -For FH4. ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 1506a73573b..a2b45b3c28f 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4234,6 +4234,7 @@ HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steam - HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steamclient64.dll" - HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" - HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" -+HKCU,Software\Wine\AppDefaults\ForzaHorizon4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. diff --git a/patches/proton/46-proton-09_nvapi_registry.patch b/patches/proton/46-proton-09_nvapi_registry.patch deleted file mode 100644 index 834c387df..000000000 --- a/patches/proton/46-proton-09_nvapi_registry.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0bff1b4fc6929694b706bd7e659ed0b58ff51f2d Mon Sep 17 00:00:00 2001 -From: Liam Middlebrook -Date: Tue, 11 May 2021 20:23:18 -0700 -Subject: [PATCH] loader: Set default regkey for NVIDIA NGX FullPath - -Sets the default location for the NVIDIA NGX SDK search-path to be -C:\Windows\System32\ - -This is required for supporting NVIDIA DLSS within Proton. - -Reviewed-by: Adam Moss ---- - loader/wine.inf.in | 12 +++++++++--- - 1 file changed, 9 insertions(+), 3 deletions(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 851a31b7d05..735a3899b3e 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -75,7 +75,8 @@ AddReg=\ - Timezones,\ - VersionInfo,\ - LicenseInformation, \ -- SteamClient -+ SteamClient, \ -+ NVIDIANGX - - [DefaultInstall.ntamd64] - RegisterDlls=RegisterDllsSection -@@ -104,7 +105,8 @@ AddReg=\ - Timezones,\ - VersionInfo.ntamd64,\ - LicenseInformation, \ -- SteamClient.ntamd64 -+ SteamClient.ntamd64, \ -+ NVIDIANGX - - [DefaultInstall.ntarm64] - RegisterDlls=RegisterDllsSection -@@ -149,7 +151,8 @@ AddReg=\ - Tapi,\ - VersionInfo.ntamd64,\ - LicenseInformation, \ -- SteamClient.ntamd64 -+ SteamClient.ntamd64, \ -+ NVIDIANGX - - [Wow64Install.ntarm64] - WineFakeDlls=FakeDllsWin32 -@@ -4431,6 +4431,9 @@ HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"atiadlxx",,"disabled" - -+[NVIDIANGX] -+HKLM,Software\NVIDIA Corporation\Global\NGXCore,"FullPath",,"C:\Windows\System32" -+ - [NlsFiles] - c_037.nls - c_10000.nls -From e3d19be8982e063183ff6ffafb96045c8d7a38fb Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 10 Sep 2021 23:16:57 +0300 -Subject: [PATCH] wine.inf: Disable nvcuda.dll by default. - -The nvcuda.dll stub presence may cause regressions when the games -successfully load and try to use it (like Divinity The Original Sin 2). -The library is enabled in proton script together with nvapi.dll. - -Link: https://github.com/ValveSoftware/wine/pull/119 ---- - loader/wine.inf.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index dd2be6a2a45..644a2fcce1d 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4208,6 +4208,7 @@ HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"atiadlxx",,"disabled" -+HKCU,Software\Wine\DllOverrides,"nvcuda",0x2,"disabled" - - [SteamClient.ntamd64] - HKCU,Software\Valve\Steam,"SteamPath",,"%16422%\Steam" -@@ -4263,6 +4264,7 @@ HKCU,Software\Wine\DllOverrides,"ucrtbase",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcomp140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"vcruntime140",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"atiadlxx",,"disabled" -+HKCU,Software\Wine\DllOverrides,"nvcuda",0x2,"disabled" - - [NVIDIANGX] - HKLM,Software\NVIDIA Corporation\Global\NGXCore,"FullPath",,"C:\Windows\System32" diff --git a/patches/proton/47-proton-10_dirt_5_registry.patch b/patches/proton/47-proton-10_dirt_5_registry.patch deleted file mode 100644 index cad42662c..000000000 --- a/patches/proton/47-proton-10_dirt_5_registry.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 78f9970a3636a125719773d5c442f5a66f95fbc7 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 15 Mar 2021 13:24:34 -0500 -Subject: [PATCH] wine.inf: Use built-in atiadlxx for DIRT5 - ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index fabfc86ac0c..4df88d1f386 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4232,6 +4232,7 @@ HKCU,Software\Wine\AppDefaults\BlackOps3.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\NFS16.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"amd_ags_x64",,"" -+HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" - diff --git a/patches/proton/49-proton_QPC-update-replace.patch b/patches/proton/49-proton_QPC-update-replace.patch deleted file mode 100644 index 75ee7e3ca..000000000 --- a/patches/proton/49-proton_QPC-update-replace.patch +++ /dev/null @@ -1,285 +0,0 @@ -From 5a7154ee6436e38b1fdc5ac4901d1bbd6bbf2c71 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 4 Jun 2021 10:24:10 +0200 -Subject: [PATCH] wineboot: Compute and write the TSC frequency to registry - ~Mhz. - -In HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor - -Squashed with patches from: - -* Arkadiusz Hiler - -Check if the kernel trusts TSC before using it for Qpc. - -Even if the bits are claiming that TSC meets our requirements the -hardware implementation may still be broken. - -The Linux kernel does a lot of quality testing before deciding to use as -the clock source. If it (or the user, through an override) does not trust -the TSC we should not trust it either. - -* Joshua Ashton - -Some games such as Horizon Zero Dawn use this registry value to -correlate values from rtdsc to real time. - -Testing across a few devices, is seems like Windows always returns the -TSC frequency in this entry, not the current/maximum frequency of the -processor. - -Returning the nominal/maximum cpu frequency here causes the game to run -in slow motion as it may not match the tsc frequency of the processor. - -Ideally we'd not have to measure this and the kernel would return -tsc_khz to userspace, but this is a good enough stop-gap until -https://lkml.org/lkml/2020/12/31/72 or something similar is merged. - -CW-Bug-Id: #18918 -CW-Bug-Id: #18958 ---- - programs/wineboot/wineboot.c | 175 ++++++++++++++++++++++++++++++++++- - 1 file changed, 170 insertions(+), 5 deletions(-) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index db7baff269f..f869b8a4e89 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -82,6 +82,8 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(wineboot); - -+#define TICKSPERSEC 10000000 -+ - extern BOOL shutdown_close_windows( BOOL force ); - extern BOOL shutdown_all_desktops( BOOL force ); - extern void kill_processes( BOOL kill_desktop ); -@@ -241,15 +243,173 @@ static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) - TRACE("XSAVE feature 2 %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]); - } - -+static UINT64 read_tsc_frequency( BOOL has_rdtscp ) -+{ -+ UINT64 freq = 0; -+ -+/* FIXME: Intel provides TSC freq in some CPUID but it's been slightly broken, -+ fix it properly and test it on real Intel hardware */ -+ -+#if 0 -+ int regs[4], cpuid_level, tmp; -+ UINT64 denom, numer; -+ -+ __cpuid( regs, 0 ); -+ tmp = regs[2]; -+ regs[2] = regs[3]; -+ regs[3] = tmp; -+ -+ /* only available on some intel CPUs */ -+ if (memcmp( regs + 1, "GenuineIntel", 12 )) freq = 0; -+ else if ((cpuid_level = regs[0]) < 0x15) freq = 0; -+ else -+ { -+ __cpuid( regs, 0x15 ); -+ if (!(denom = regs[0]) || !(numer = regs[1])) freq = 0; -+ else -+ { -+ if ((freq = regs[2])) freq = freq * numer / denom; -+ else if (cpuid_level >= 0x16) -+ { -+ __cpuid( regs, 0x16 ); /* eax is base freq in MHz */ -+ freq = regs[0] * (UINT64)1000000; -+ } -+ else freq = 0; -+ } -+ -+ if (!freq) WARN( "Failed to read TSC frequency from CPUID, falling back to calibration.\n" ); -+ else TRACE( "TSC frequency read from CPUID, found %I64u Hz\n", freq ); -+ } -+#endif -+ -+ if (freq == 0) -+ { -+ LONGLONG time0, time1, tsc0, tsc1, tsc2, tsc3, freq0, freq1, error; -+ unsigned int aux; -+ UINT retries = 50; -+ int regs[4]; -+ -+ do -+ { -+ if (has_rdtscp) -+ { -+ tsc0 = __rdtscp( &aux ); -+ time0 = RtlGetSystemTimePrecise(); -+ tsc1 = __rdtscp( &aux ); -+ Sleep( 1 ); -+ tsc2 = __rdtscp( &aux ); -+ time1 = RtlGetSystemTimePrecise(); -+ tsc3 = __rdtscp( &aux ); -+ } -+ else -+ { -+ tsc0 = __rdtsc(); __cpuid( regs, 0 ); -+ time0 = RtlGetSystemTimePrecise(); -+ tsc1 = __rdtsc(); __cpuid( regs, 0 ); -+ Sleep(1); -+ tsc2 = __rdtsc(); __cpuid( regs, 0 ); -+ time1 = RtlGetSystemTimePrecise(); -+ tsc3 = __rdtsc(); __cpuid( regs, 0 ); -+ } -+ -+ freq0 = (tsc2 - tsc0) * 10000000 / (time1 - time0); -+ freq1 = (tsc3 - tsc1) * 10000000 / (time1 - time0); -+ error = llabs( (freq1 - freq0) * 1000000 / min( freq1, freq0 ) ); -+ } -+ while (error > 100 && retries--); -+ -+ if (!retries) WARN( "TSC frequency calibration failed, unstable TSC?\n" ); -+ else -+ { -+ freq = (freq0 + freq1) / 2; -+ TRACE( "TSC frequency calibration complete, found %I64u Hz\n", freq ); -+ } -+ } -+ -+ return freq; -+} -+ -+static BOOL is_tsc_trusted_by_the_kernel(void) -+{ -+ char buf[4] = {}; -+ DWORD num_read; -+ HANDLE handle; -+ BOOL ret = TRUE; -+ -+ handle = CreateFileA( "\\??\\unix\\sys\\bus\\clocksource\\devices\\clocksource0\\current_clocksource", -+ GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); -+ if (handle == INVALID_HANDLE_VALUE) return TRUE; -+ -+ if (ReadFile( handle, buf, sizeof(buf) - 1, &num_read, NULL ) && strcmp( "tsc", buf )) -+ ret = FALSE; -+ -+ CloseHandle( handle ); -+ return ret; -+} -+ -+static void initialize_qpc_features( struct _KUSER_SHARED_DATA *data, UINT64 *tsc_frequency ) -+{ -+ BOOL has_rdtscp = FALSE; -+ int regs[4]; -+ -+ data->QpcBypassEnabled = 0; -+ data->QpcFrequency = TICKSPERSEC; -+ data->QpcShift = 0; -+ data->QpcBias = 0; -+ *tsc_frequency = 0; -+ -+ if (!is_tsc_trusted_by_the_kernel()) -+ { -+ WARN( "Failed to compute TSC frequency, not trusted by the kernel.\n" ); -+ return; -+ } -+ -+ if (!data->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE]) -+ { -+ WARN( "Failed to compute TSC frequency, RDTSC instruction not supported.\n" ); -+ return; -+ } -+ -+ __cpuid( regs, 0x80000000 ); -+ if (regs[0] < 0x80000007) -+ { -+ WARN( "Failed to compute TSC frequency, unable to check invariant TSC.\n" ); -+ return; -+ } -+ -+ /* check for invariant tsc bit */ -+ __cpuid( regs, 0x80000007 ); -+ if (!(regs[3] & (1 << 8))) -+ { -+ WARN( "Failed to compute TSC frequency, no invariant TSC.\n" ); -+ return; -+ } -+ -+ /* check for rdtscp support bit */ -+ __cpuid( regs, 0x80000001 ); -+ if ((regs[3] & (1 << 27))) has_rdtscp = TRUE; -+ -+ *tsc_frequency = read_tsc_frequency( has_rdtscp ); -+} -+ - #else - - static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) - { - } - -+static void initialize_qpc_features( struct _KUSER_SHARED_DATA *data, UINT64 *tsc_frequency ) -+{ -+ data->QpcBypassEnabled = 0; -+ data->QpcFrequency = TICKSPERSEC; -+ data->QpcShift = 0; -+ data->QpcBias = 0; -+ *tsc_frequency = 0; -+} -+ - #endif - --static void create_user_shared_data(void) -+static void create_user_shared_data( UINT64 *tsc_frequency ) - { - struct _KUSER_SHARED_DATA *data; - RTL_OSVERSIONINFOEXW version; -@@ -336,6 +496,7 @@ static void create_user_shared_data(void) - data->ActiveGroupCount = 1; - - initialize_xstate_features( data ); -+ initialize_qpc_features( data, tsc_frequency ); - - UnmapViewOfFile( data ); - } -@@ -647,7 +808,7 @@ static void create_bios_key( HKEY system_key ) - } - - /* create the volatile hardware registry keys */ --static void create_hardware_registry_keys(void) -+static void create_hardware_registry_keys( UINT64 tsc_frequency ) - { - unsigned int i; - HKEY hkey, system_key, cpu_key, fpu_key; -@@ -884,12 +884,15 @@ static void create_hardware_registry_keys( UINT64 tsc_frequency ) - if (!RegCreateKeyExW( cpu_key, numW, 0, NULL, REG_OPTION_VOLATILE, - KEY_ALL_ACCESS, NULL, &hkey, NULL )) - { -+ DWORD tsc_freq_mhz = (DWORD)(tsc_frequency / 1000000ull); /* Hz -> Mhz */ -+ if (!tsc_freq_mhz) tsc_freq_mhz = power_info[i].MaxMhz; -+ - RegSetValueExW( hkey, L"FeatureSet", 0, REG_DWORD, (BYTE *)&sci.ProcessorFeatureBits, sizeof(DWORD) ); - set_reg_value( hkey, L"Identifier", id ); - /* TODO: report ARM properly */ - set_reg_value( hkey, L"ProcessorNameString", namestr ); - set_reg_value( hkey, L"VendorIdentifier", vendorid ); -- RegSetValueExW( hkey, L"~MHz", 0, REG_DWORD, (BYTE *)&power_info[i].MaxMhz, sizeof(DWORD) ); -+ RegSetValueExW( hkey, L"~MHz", 0, REG_DWORD, (BYTE *)&tsc_freq_mhz, sizeof(DWORD) ); - RegCloseKey( hkey ); - } - if (sci.ProcessorArchitecture != PROCESSOR_ARCHITECTURE_ARM && -@@ -1680,6 +1844,7 @@ int __cdecl main( int argc, char *argv[] ) - BOOL end_session, force, init, kill, restart, shutdown, update; - HANDLE event; - OBJECT_ATTRIBUTES attr; -+ UINT64 tsc_frequency = 0; - UNICODE_STRING nameW; - BOOL is_wow64; - -@@ -1765,8 +1930,8 @@ int __cdecl main( int argc, char *argv[] ) - - ResetEvent( event ); /* in case this is a restart */ - -- create_user_shared_data(); -- create_hardware_registry_keys(); -+ create_user_shared_data( &tsc_frequency ); -+ create_hardware_registry_keys( tsc_frequency ); - create_dynamic_registry_keys(); - create_environment_registry_keys(); - create_computer_name_keys(); - diff --git a/patches/proton/49-proton_QPC.patch b/patches/proton/49-proton_QPC.patch deleted file mode 100644 index f668e8562..000000000 --- a/patches/proton/49-proton_QPC.patch +++ /dev/null @@ -1,1331 +0,0 @@ -From 0882d8ece671b524dce3ecdc89c933bbc115707b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 4 Mar 2021 11:59:33 +0100 -Subject: [PATCH] wineboot: Initialize user shared data Qpc flags and - frequency. - ---- - programs/wineboot/wineboot.c | 19 +++++++++++++++++++ - 1 file changed, 19 insertions(+) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index f295ff0b8b4..c28c68332d5 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -82,6 +82,8 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(wineboot); - -+#define TICKSPERSEC 10000000 -+ - extern BOOL shutdown_close_windows( BOOL force ); - extern BOOL shutdown_all_desktops( BOOL force ); - extern void kill_processes( BOOL kill_desktop ); -@@ -241,12 +243,28 @@ static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) - TRACE("XSAVE feature 2 %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]); - } - -+static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) -+{ -+ data->QpcBypassEnabled = 0; -+ data->QpcFrequency = TICKSPERSEC; -+ data->QpcShift = 0; -+ data->QpcBias = 0; -+} -+ - #else - - static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) - { - } - -+static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) -+{ -+ data->QpcBypassEnabled = 0; -+ data->QpcFrequency = TICKSPERSEC; -+ data->QpcShift = 0; -+ data->QpcBias = 0; -+} -+ - #endif - - static void create_user_shared_data(void) -@@ -336,6 +354,7 @@ static void create_user_shared_data(void) - data->ActiveGroupCount = 1; - - initialize_xstate_features( data ); -+ initialize_qpc_features( data ); - - UnmapViewOfFile( data ); - } -From 5af21c994fd138b05f3357870b19f69b7f15612f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 4 Mar 2021 10:25:28 +0100 -Subject: [PATCH] ntdll: Read Qpc frequency from user shared data. - ---- - dlls/ntdll/time.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c -index f92443500d8..c0eb1f7f923 100644 ---- a/dlls/ntdll/time.c -+++ b/dlls/ntdll/time.c -@@ -389,7 +389,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RtlQueryPerformanceCounter( LARGE_INTEGER *counter - */ - BOOL WINAPI DECLSPEC_HOTPATCH RtlQueryPerformanceFrequency( LARGE_INTEGER *frequency ) - { -- frequency->QuadPart = TICKSPERSEC; -+ frequency->QuadPart = user_shared_data->QpcFrequency; - return TRUE; - } - -From 2a14e52a188d62973ded3a980cd83faafe86784d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 4 Mar 2021 10:46:06 +0100 -Subject: [PATCH] ntdll: Use rdtsc(p) for RtlQueryPerformanceCounter when - enabled. - ---- - dlls/ntdll/time.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c -index c0eb1f7f923..404a07a4402 100644 ---- a/dlls/ntdll/time.c -+++ b/dlls/ntdll/time.c -@@ -39,6 +39,7 @@ - #include "wine/exception.h" - #include "wine/debug.h" - #include "ntdll_misc.h" -+#include "intrin.h" - - WINE_DEFAULT_DEBUG_CHANNEL(ntdll); - -@@ -380,6 +381,26 @@ LONGLONG WINAPI RtlGetSystemTimePrecise( void ) - */ - BOOL WINAPI DECLSPEC_HOTPATCH RtlQueryPerformanceCounter( LARGE_INTEGER *counter ) - { -+ if (user_shared_data->u3.QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED) -+ { -+ unsigned __int64 tsc; -+ unsigned int aux; -+ -+ if (user_shared_data->u3.QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_RDTSCP) -+ tsc = __rdtscp(&aux); -+ else -+ { -+ if (user_shared_data->u3.QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_MFENCE) -+ __asm__ __volatile__ ( "mfence" : : : "memory" ); -+ if (user_shared_data->u3.QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_LFENCE) -+ __asm__ __volatile__ ( "lfence" : : : "memory" ); -+ tsc = __rdtsc(); -+ } -+ -+ counter->QuadPart = (tsc + user_shared_data->QpcBias) >> user_shared_data->u3.QpcShift; -+ return TRUE; -+ } -+ - NtQueryPerformanceCounter( counter, NULL ); - return TRUE; - } -From 285439de54ff8dbe078aaf06527aa19828bc5a01 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 22 Mar 2021 10:16:43 +0100 -Subject: [PATCH] wineboot: Initialize and calibrate user shared data Qpc - frequency. - ---- - programs/wineboot/wineboot.c | 88 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 88 insertions(+) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index c28c68332d5..6a16e609772 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -245,10 +245,98 @@ static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) - - static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) - { -+ int regs[4], cpuid_level, denom, numer, freq, tmp; -+ -+ if (data->QpcBypassEnabled) return; -+ - data->QpcBypassEnabled = 0; - data->QpcFrequency = TICKSPERSEC; - data->QpcShift = 0; - data->QpcBias = 0; -+ -+ if (!data->ProcessorFeatures[PF_RDTSC_INSTRUCTION_AVAILABLE]) -+ { -+ WARN("No RDTSC support, disabling QpcBypass\n"); -+ return; -+ } -+ -+ __cpuid(regs, 0x80000000); -+ if (regs[0] < 0x80000007) -+ { -+ WARN("Unable to check invariant TSC, disabling QpcBypass\n"); -+ return; -+ } -+ -+ /* check for invariant tsc bit */ -+ __cpuid(regs, 0x80000007); -+ if (!(regs[3] & (1 << 8))) -+ { -+ WARN("No invariant TSC, disabling QpcBypass\n"); -+ return; -+ } -+ data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED; -+ -+ /* check for rdtscp support bit */ -+ __cpuid(regs, 0x80000001); -+ if ((regs[3] & (1 << 27))) -+ data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_RDTSCP; -+ else if (data->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE]) -+ data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_LFENCE; -+ else -+ data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_MFENCE; -+ -+ __cpuid(regs, 0); -+ tmp = regs[2]; -+ regs[2] = regs[3]; -+ regs[3] = tmp; -+ -+ data->QpcFrequency = 0; -+ -+ if (!data->QpcFrequency) -+ { -+ LONGLONG time0, time1, tsc0, tsc1, tsc2, tsc3, freq0, freq1, error; -+ unsigned int aux; -+ UINT retries = 50; -+ -+ data->QpcShift = 0; -+ data->QpcBias = 0; -+ -+ do -+ { -+ tsc0 = __rdtscp(&aux); -+ time0 = RtlGetSystemTimePrecise(); -+ tsc1 = __rdtscp(&aux); -+ Sleep(1); -+ tsc2 = __rdtscp(&aux); -+ time1 = RtlGetSystemTimePrecise(); -+ tsc3 = __rdtscp(&aux); -+ -+ freq0 = (tsc2 - tsc0) * 10000000 / (time1 - time0); -+ freq1 = (tsc3 - tsc1) * 10000000 / (time1 - time0); -+ error = llabs((freq1 - freq0) * 1000000 / min(freq1, freq0)); -+ } -+ while (error > 100 && retries--); -+ -+ if (!retries) WARN("TSC frequency calibration failed, unstable TSC?\n"); -+ else -+ { -+ data->QpcFrequency = (freq0 + freq1 + (1 << 10) - 1) >> 11; -+ data->QpcShift = 10; -+ data->QpcBias = 0; -+ -+ TRACE("TSC frequency calibration complete, freq %I64d, shift %d, bias %I64d\n", -+ data->QpcFrequency, data->QpcShift, data->QpcBias); -+ } -+ } -+ -+ if (!data->QpcFrequency) -+ { -+ WARN("Unable to calibrate TSC frequency, disabling QpcBypass.\n"); -+ data->QpcBypassEnabled = 0; -+ data->QpcFrequency = TICKSPERSEC; -+ data->QpcShift = 0; -+ data->QpcBias = 0; -+ } - } - - #else -From e7e1b259412189a56ef6a6962f42807a26e1aab8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 4 Mar 2021 10:50:48 +0100 -Subject: [PATCH] ntdll: Prefer RtlQueryPerformanceCounter over - NtQueryPerformanceCounter. - ---- - dlls/ntdll/threadpool.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index 1b51a191979..9d4e4d7ffd9 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -591,8 +591,10 @@ static DWORD WINAPI timer_callback_wrapper(LPVOID p) - - static inline ULONGLONG queue_current_time(void) - { -- LARGE_INTEGER now, freq; -- NtQueryPerformanceCounter(&now, &freq); -+ static LARGE_INTEGER freq; -+ LARGE_INTEGER now; -+ if (!freq.QuadPart) RtlQueryPerformanceFrequency(&freq); -+ RtlQueryPerformanceCounter(&now); - return now.QuadPart * 1000 / freq.QuadPart; - } - -From 6977fdc4cd9776ea80fa0957f87486cead4fb889 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 4 Mar 2021 10:51:05 +0100 -Subject: [PATCH] hal: Prefer RtlQueryPerformanceCounter over - NtQueryPerformanceCounter. - ---- - dlls/hal/hal.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/hal/hal.c b/dlls/hal/hal.c -index 21ce6e12c99..e54d9df2362 100644 ---- a/dlls/hal/hal.c -+++ b/dlls/hal/hal.c -@@ -193,6 +193,7 @@ ULONGLONG WINAPI KeQueryPerformanceCounter(LARGE_INTEGER *frequency) - - TRACE("(%p)\n", frequency); - -- NtQueryPerformanceCounter(&counter, frequency); -+ RtlQueryPerformanceFrequency(frequency); -+ RtlQueryPerformanceCounter(&counter); - return counter.QuadPart; - } -From 8646f9ee9452b2adaedda179c8704dbc5544441e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 4 Mar 2021 10:51:17 +0100 -Subject: [PATCH] kernelbase: Prefer RtlQueryPerformanceCounter over - NtQueryPerformanceCounter. - ---- - dlls/kernelbase/registry.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernelbase/registry.c b/dlls/kernelbase/registry.c -index 2ed5e268119..aa26ad2acce 100644 ---- a/dlls/kernelbase/registry.c -+++ b/dlls/kernelbase/registry.c -@@ -1331,7 +1331,8 @@ static DWORD query_perf_data(const WCHAR *query, DWORD *type, void *data, DWORD - pdb->HeaderLength = sizeof(*pdb); - pdb->NumObjectTypes = 0; - pdb->DefaultObject = 0; -- NtQueryPerformanceCounter( &pdb->PerfTime, &pdb->PerfFreq ); -+ RtlQueryPerformanceFrequency( &pdb->PerfFreq ); -+ RtlQueryPerformanceCounter( &pdb->PerfTime ); - - data = pdb + 1; - pdb->SystemNameOffset = sizeof(*pdb); -From 0b23c1488f302577e17dd8d1821f524959e6bcb3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 4 Mar 2021 12:39:58 +0100 -Subject: [PATCH] winmm: Only call QueryPerformanceFrequency once. - ---- - dlls/winmm/time.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/dlls/winmm/time.c b/dlls/winmm/time.c -index 634b5df7923..bbf6613e849 100644 ---- a/dlls/winmm/time.c -+++ b/dlls/winmm/time.c -@@ -254,10 +254,11 @@ MMRESULT WINAPI timeGetSystemTime(LPMMTIME lpTime, UINT wSize) - */ - DWORD WINAPI timeGetTime(void) - { -- LARGE_INTEGER now, freq; -+ static LARGE_INTEGER freq; -+ LARGE_INTEGER now; - -+ if (!freq.QuadPart) QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&now); -- QueryPerformanceFrequency(&freq); - - return (now.QuadPart * 1000) / freq.QuadPart; - } -From b1a2ec3485868e0837a187772cbfacab96bfc418 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 28 Apr 2021 09:44:42 +0200 -Subject: [PATCH] server: Update QpcBias when updating the clock time. - ---- - server/fd.c | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - -diff --git a/server/fd.c b/server/fd.c -index ff88ae16d8d..2750e229109 100644 ---- a/server/fd.c -+++ b/server/fd.c -@@ -94,6 +94,9 @@ - #ifdef HAVE_SYS_SYSCALL_H - #include - #endif -+#if defined(__i386__) || defined(__x86_64__) -+#include -+#endif - - #include "ntstatus.h" - #define WIN32_NO_STATUS -@@ -406,6 +409,26 @@ static const int user_shared_data_timeout = 16; - timeout_t timezone_bias; - struct tm *tm; - time_t now; -+ unsigned __int64 tsc, qpc_bias, qpc_freq = user_shared_data->QpcFrequency; -+ unsigned int aux, qpc_shift = user_shared_data->QpcShift; -+ unsigned int qpc_bypass = user_shared_data->QpcBypassEnabled; -+ -+ if (!(qpc_bypass & SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED)) -+ tsc = 0; -+#if defined(__i386__) || defined(__x86_64__) -+ else if (qpc_bypass & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_RDTSCP) -+ tsc = __rdtscp(&aux); -+ else -+ { -+ if (qpc_bypass & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_MFENCE) -+ __asm__ __volatile__ ( "mfence" : : : "memory" ); -+ if (qpc_bypass & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_LFENCE) -+ __asm__ __volatile__ ( "lfence" : : : "memory" ); -+ tsc = __rdtsc(); -+ } -+#endif -+ -+ qpc_bias = ((monotonic_time * qpc_freq / 10000000) << qpc_shift) - tsc; - - if (monotonic_time - last_timezone_update > TICKS_PER_SEC) - { -@@ -424,6 +447,7 @@ static void set_user_shared_data_time(void) - atomic_store_ulong(&user_shared_data->TickCount.LowPart, tick_count); - atomic_store_long(&user_shared_data->TickCount.High1Time, tick_count >> 32); - atomic_store_ulong(&user_shared_data->TickCountLowDeprecated, tick_count); -+ user_shared_data->QpcBias = qpc_bias; - } - - void set_current_time(void) -From 0f850e60fb84ce75c6d2666bd1ddca67a956a658 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 28 Apr 2021 11:50:36 +0200 -Subject: [PATCH] ntdll: Create and use hypervisor shared data page for Qpc. - ---- - dlls/ntdll/ntdll_misc.h | 8 ++ - dlls/ntdll/thread.c | 1 + - dlls/ntdll/time.c | 11 ++ - dlls/ntdll/unix/loader.c | 1 + - dlls/ntdll/unix/system.c | 12 +++ - dlls/ntdll/unix/unix_private.h | 2 + - dlls/ntdll/unix/virtual.c | 38 +++++++ - programs/wineboot/wineboot.c | 192 ++++++++++++++++++++++++++------- - server/directory.c | 3 + - server/fd.c | 27 ++++- - server/file.h | 10 ++ - server/mapping.c | 14 +++ - 12 files changed, 275 insertions(+), 44 deletions(-) - -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index 99031a0668e..79b40cd7af3 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -86,6 +86,14 @@ extern const WCHAR syswow64_dir[] DECLSPEC_HIDDEN; - extern void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) DECLSPEC_HIDDEN; - extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN; - -+struct hypervisor_shared_data -+{ -+ UINT64 unknown; -+ UINT64 QpcMultiplier; -+ UINT64 QpcBias; -+}; -+ -+extern struct hypervisor_shared_data *hypervisor_shared_data DECLSPEC_HIDDEN; - extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN; - - /* locale */ -diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c -index d3c3db7fd68..b68a23ff58f 100644 ---- a/dlls/ntdll/thread.c -+++ b/dlls/ntdll/thread.c -@@ -35,6 +35,7 @@ - WINE_DECLARE_DEBUG_CHANNEL(relay); - WINE_DECLARE_DEBUG_CHANNEL(thread); - -+struct hypervisor_shared_data *hypervisor_shared_data = (void *)0x7ffd0000; - struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; - - -diff --git a/dlls/ntdll/time.c b/dlls/ntdll/time.c -index 404a07a4402..1c00010bffb 100644 ---- a/dlls/ntdll/time.c -+++ b/dlls/ntdll/time.c -@@ -376,6 +376,14 @@ LONGLONG WINAPI RtlGetSystemTimePrecise( void ) - return unix_funcs->RtlGetSystemTimePrecise(); - } - -+/* 128-bit multiply a by b and return the high 64 bits, same as __umulh */ -+static UINT64 multiply_tsc(UINT64 a, UINT64 b) -+{ -+ UINT64 ah = a >> 32, al = (UINT32)a, bh = b >> 32, bl = (UINT32)b, m; -+ m = (ah * bl) + (bh * al) + ((al * bl) >> 32); -+ return (ah * bh) + (m >> 32); -+} -+ - /****************************************************************************** - * RtlQueryPerformanceCounter [NTDLL.@] - */ -@@ -397,6 +405,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH RtlQueryPerformanceCounter( LARGE_INTEGER *counter - tsc = __rdtsc(); - } - -+ if (user_shared_data->u3.QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE) -+ tsc = multiply_tsc(tsc, hypervisor_shared_data->QpcMultiplier) + hypervisor_shared_data->QpcBias; -+ - counter->QuadPart = (tsc + user_shared_data->QpcBias) >> user_shared_data->u3.QpcShift; - return TRUE; - } -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 4abc5ce6656..016fc8112bf 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -1865,6 +1865,7 @@ static void start_main_thread(void) - fsync_init(); - esync_init(); - virtual_map_user_shared_data(); -+ virtual_map_hypervisor_shared_data(); - init_cpu_info(); - syscall_dispatcher = signal_init_syscalls(); - init_files(); -diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c -index 8b77c577d01..7aa4a64fbef 100644 ---- a/dlls/ntdll/unix/system.c -+++ b/dlls/ntdll/unix/system.c -@@ -2942,6 +2942,18 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class, - ret = STATUS_SUCCESS; - break; - -+ case SystemHypervisorSharedPageInformation: -+ { -+ len = sizeof(void *); -+ if (size >= len) -+ { -+ if (!info) ret = STATUS_ACCESS_VIOLATION; -+ else *(void **)info = hypervisor_shared_data; -+ } -+ else ret = STATUS_INFO_LENGTH_MISMATCH; -+ break; -+ } -+ - default: - FIXME( "(0x%08x,%p,0x%08x,%p) stub\n", class, info, size, ret_size ); - -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index 453460c4960..a2f683d9ff1 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -131,6 +131,7 @@ extern BOOL process_exiting DECLSPEC_HIDDEN; - extern HANDLE keyed_event DECLSPEC_HIDDEN; - extern timeout_t server_start_time DECLSPEC_HIDDEN; - extern sigset_t server_block_set DECLSPEC_HIDDEN; -+extern void *hypervisor_shared_data DECLSPEC_HIDDEN; - extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN; - extern SYSTEM_CPU_INFORMATION cpu_info DECLSPEC_HIDDEN; - #ifdef __i386__ -@@ -195,6 +196,7 @@ extern NTSTATUS virtual_clear_tls_index( ULONG index ) DECLSPEC_HIDDEN; - extern NTSTATUS virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, - SIZE_T *pthread_size ) DECLSPEC_HIDDEN; - extern void virtual_map_user_shared_data(void) DECLSPEC_HIDDEN; -+extern void virtual_map_hypervisor_shared_data(void) DECLSPEC_HIDDEN; - extern NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack ) DECLSPEC_HIDDEN; - extern unsigned int virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN; - extern ssize_t virtual_locked_read( int fd, void *addr, size_t size ) DECLSPEC_HIDDEN; -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index 181a19edc9e..123b5ad211a 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -159,6 +159,7 @@ static void *user_space_limit = (void *)0x7fff0000; - static void *working_set_limit = (void *)0x7fff0000; - #endif - -+void *hypervisor_shared_data = (void *)0x7ffd0000; - struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; - - /* TEB allocation blocks */ -@@ -2717,6 +2718,14 @@ TEB *virtual_alloc_first_teb(void) - exit(1); - } - -+ status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&hypervisor_shared_data, 0, &data_size, -+ MEM_RESERVE | MEM_COMMIT, PAGE_READONLY ); -+ if (status) -+ { -+ ERR( "wine: failed to map the shared user data: %08x\n", status ); -+ exit(1); -+ } -+ - NtAllocateVirtualMemory( NtCurrentProcess(), &teb_block, is_win64 ? 0x7fffffff : 0, &total, - MEM_RESERVE | MEM_TOP_DOWN, PAGE_READWRITE ); - teb_block_pos = 30; -@@ -2948,6 +2957,35 @@ void virtual_map_user_shared_data(void) - } - - -+/*********************************************************************** -+ * virtual_map_hypervisor_shared_data -+ */ -+void virtual_map_hypervisor_shared_data(void) -+{ -+ static const WCHAR nameW[] = {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s', -+ '\\','_','_','w','i','n','e','_','h','y','p','e','r','v','i','s','o','r','_','s','h','a','r','e','d','_','d','a','t','a',0}; -+ UNICODE_STRING name_str = { sizeof(nameW) - sizeof(WCHAR), sizeof(nameW), (WCHAR *)nameW }; -+ OBJECT_ATTRIBUTES attr = { sizeof(attr), 0, &name_str }; -+ NTSTATUS status; -+ HANDLE section; -+ int res, fd, needs_close; -+ -+ if ((status = NtOpenSection( §ion, SECTION_ALL_ACCESS, &attr ))) -+ { -+ ERR( "failed to open the hypervisor shared data section: %08x\n", status ); -+ exit(1); -+ } -+ if ((res = server_get_unix_fd( section, 0, &fd, &needs_close, NULL, NULL )) || -+ (hypervisor_shared_data != mmap( hypervisor_shared_data, page_size, PROT_READ, MAP_SHARED|MAP_FIXED, fd, 0 ))) -+ { -+ ERR( "failed to remap the process hypervisor shared data: %d\n", res ); -+ exit(1); -+ } -+ if (needs_close) close( fd ); -+ NtClose( section ); -+} -+ -+ - /*********************************************************************** - * grow_thread_stack - */ -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 6a16e609772..9bebededa4f 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -243,9 +243,81 @@ static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) - TRACE("XSAVE feature 2 %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]); - } - -+static UINT64 read_tsc_frequency(void) -+{ -+ UINT64 freq = 0; -+ -+/* FIXME: Intel provides TSC freq in some CPUID but it's been slightly broken, -+ fix it properly and test it on real Intel hardware */ -+ -+#if 0 -+ int regs[4], cpuid_level, tmp; -+ UINT64 denom, numer; -+ -+ __cpuid(regs, 0); -+ tmp = regs[2]; -+ regs[2] = regs[3]; -+ regs[3] = tmp; -+ -+ /* only available on some intel CPUs */ -+ if (memcmp(regs + 1, "GenuineIntel", 12)) freq = 0; -+ else if ((cpuid_level = regs[0]) < 0x15) freq = 0; -+ else -+ { -+ __cpuid(regs, 0x15); -+ if (!(denom = regs[0]) || !(numer = regs[1])) freq = 0; -+ else -+ { -+ if ((freq = regs[2])) freq = freq * numer / denom; -+ else if (cpuid_level >= 0x16) -+ { -+ __cpuid(regs, 0x16); /* eax is base freq in MHz */ -+ freq = regs[0] * (UINT64)1000000; -+ } -+ else freq = 0; -+ } -+ -+ if (!freq) WARN("Failed to read TSC frequency from CPUID, falling back to calibration.\n"); -+ else TRACE("TSC frequency read from CPUID, found %I64u Hz\n", freq); -+ } -+#endif -+ -+ if (freq == 0) -+ { -+ LONGLONG time0, time1, tsc0, tsc1, tsc2, tsc3, freq0, freq1, error; -+ unsigned int aux; -+ UINT retries = 50; -+ -+ do -+ { -+ tsc0 = __rdtscp(&aux); -+ time0 = RtlGetSystemTimePrecise(); -+ tsc1 = __rdtscp(&aux); -+ Sleep(1); -+ tsc2 = __rdtscp(&aux); -+ time1 = RtlGetSystemTimePrecise(); -+ tsc3 = __rdtscp(&aux); -+ -+ freq0 = (tsc2 - tsc0) * 10000000 / (time1 - time0); -+ freq1 = (tsc3 - tsc1) * 10000000 / (time1 - time0); -+ error = llabs((freq1 - freq0) * 1000000 / min(freq1, freq0)); -+ } -+ while (error > 100 && retries--); -+ -+ if (!retries) WARN("TSC frequency calibration failed, unstable TSC?\n"); -+ else -+ { -+ freq = (freq0 + freq1) / 2; -+ TRACE("TSC frequency calibration complete, found %I64u Hz\n", freq); -+ } -+ } -+ -+ return freq; -+} -+ - static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) - { -- int regs[4], cpuid_level, denom, numer, freq, tmp; -+ int regs[4]; - - if (data->QpcBypassEnabled) return; - -@@ -285,48 +357,10 @@ static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) - else - data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_MFENCE; - -- __cpuid(regs, 0); -- tmp = regs[2]; -- regs[2] = regs[3]; -- regs[3] = tmp; -- -- data->QpcFrequency = 0; -- -- if (!data->QpcFrequency) -+ if ((data->QpcFrequency = (read_tsc_frequency() >> 10))) - { -- LONGLONG time0, time1, tsc0, tsc1, tsc2, tsc3, freq0, freq1, error; -- unsigned int aux; -- UINT retries = 50; -- -- data->QpcShift = 0; -+ data->QpcShift = 10; - data->QpcBias = 0; -- -- do -- { -- tsc0 = __rdtscp(&aux); -- time0 = RtlGetSystemTimePrecise(); -- tsc1 = __rdtscp(&aux); -- Sleep(1); -- tsc2 = __rdtscp(&aux); -- time1 = RtlGetSystemTimePrecise(); -- tsc3 = __rdtscp(&aux); -- -- freq0 = (tsc2 - tsc0) * 10000000 / (time1 - time0); -- freq1 = (tsc3 - tsc1) * 10000000 / (time1 - time0); -- error = llabs((freq1 - freq0) * 1000000 / min(freq1, freq0)); -- } -- while (error > 100 && retries--); -- -- if (!retries) WARN("TSC frequency calibration failed, unstable TSC?\n"); -- else -- { -- data->QpcFrequency = (freq0 + freq1 + (1 << 10) - 1) >> 11; -- data->QpcShift = 10; -- data->QpcBias = 0; -- -- TRACE("TSC frequency calibration complete, freq %I64d, shift %d, bias %I64d\n", -- data->QpcFrequency, data->QpcShift, data->QpcBias); -- } - } - - if (!data->QpcFrequency) -@@ -355,6 +389,81 @@ static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) - - #endif - -+struct hypervisor_shared_data -+{ -+ UINT64 unknown; -+ UINT64 QpcMultiplier; -+ UINT64 QpcBias; -+}; -+ -+static UINT64 muldiv_tsc(UINT64 a, UINT64 b, UINT64 c) -+{ -+ UINT64 ka = a / c, ra = a % c, kb = b / c, rb = b % c; -+ return ka * kb * c + kb * ra + ka * rb + (ra * rb + c / 2) / c; -+} -+ -+static void create_hypervisor_shared_data(void) -+{ -+ struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; -+ struct hypervisor_shared_data *hypervisor_shared_data; -+ OBJECT_ATTRIBUTES attr = {sizeof(attr)}; -+ UNICODE_STRING name; -+ NTSTATUS status; -+ HANDLE handle; -+ -+ RtlInitUnicodeString( &name, L"\\KernelObjects\\__wine_hypervisor_shared_data" ); -+ InitializeObjectAttributes( &attr, &name, OBJ_OPENIF, NULL, NULL ); -+ if ((status = NtOpenSection( &handle, SECTION_ALL_ACCESS, &attr ))) -+ { -+ ERR( "cannot open __wine_hypervisor_shared_data: %x\n", status ); -+ return; -+ } -+ hypervisor_shared_data = MapViewOfFile( handle, FILE_MAP_WRITE, 0, 0, sizeof(*hypervisor_shared_data) ); -+ CloseHandle( handle ); -+ if (!hypervisor_shared_data) -+ { -+ ERR( "cannot map __wine_hypervisor_shared_data\n" ); -+ return; -+ } -+ -+ RtlInitUnicodeString( &name, L"\\KernelObjects\\__wine_user_shared_data" ); -+ InitializeObjectAttributes( &attr, &name, OBJ_OPENIF, NULL, NULL ); -+ if ((status = NtOpenSection( &handle, SECTION_ALL_ACCESS, &attr ))) -+ { -+ ERR( "cannot open __wine_user_shared_data: %x\n", status ); -+ UnmapViewOfFile( hypervisor_shared_data ); -+ return; -+ } -+ user_shared_data = MapViewOfFile( handle, FILE_MAP_WRITE, 0, 0, sizeof(*user_shared_data) ); -+ CloseHandle( handle ); -+ if (!user_shared_data) -+ { -+ ERR( "cannot map __wine_user_shared_data\n" ); -+ UnmapViewOfFile( hypervisor_shared_data ); -+ return; -+ } -+ -+ hypervisor_shared_data->unknown = 0; -+ hypervisor_shared_data->QpcMultiplier = 0; -+ hypervisor_shared_data->QpcBias = 0; -+ -+ if (user_shared_data->QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED) -+ { -+ hypervisor_shared_data->QpcMultiplier = muldiv_tsc((UINT64)5000 << 32, (UINT64)2000 << 32, read_tsc_frequency()); -+ user_shared_data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE; -+ user_shared_data->QpcInterruptTimeIncrement = (ULONGLONG)1 << 63; -+ user_shared_data->QpcInterruptTimeIncrementShift = 1; -+ user_shared_data->QpcSystemTimeIncrement = (ULONGLONG)1 << 63; -+ user_shared_data->QpcSystemTimeIncrementShift = 1; -+ user_shared_data->QpcFrequency = 10000000; -+ user_shared_data->QpcShift = 0; -+ user_shared_data->QpcBias = 0; -+ } -+ -+ UnmapViewOfFile( user_shared_data ); -+ UnmapViewOfFile( hypervisor_shared_data ); -+} -+ - static void create_user_shared_data(void) - { - struct _KUSER_SHARED_DATA *data; -@@ -1839,6 +1948,7 @@ int __cdecl main( int argc, char *argv[] ) - ResetEvent( event ); /* in case this is a restart */ - - create_user_shared_data(); -+ create_hypervisor_shared_data(); - create_hardware_registry_keys(); - create_dynamic_registry_keys(); - create_environment_registry_keys(); -diff --git a/server/directory.c b/server/directory.c -index 304b79e9a18..6ee4803aaa2 100644 ---- a/server/directory.c -+++ b/server/directory.c -@@ -474,8 +474,10 @@ void init_directories( struct fd *intl_fd ) - /* mappings */ - static const WCHAR intlW[] = {'N','l','s','S','e','c','t','i','o','n','L','A','N','G','_','I','N','T','L'}; - static const WCHAR user_dataW[] = {'_','_','w','i','n','e','_','u','s','e','r','_','s','h','a','r','e','d','_','d','a','t','a'}; -+ static const WCHAR hypervisor_dataW[] = {'_','_','w','i','n','e','_','h','y','p','e','r','v','i','s','o','r','_','s','h','a','r','e','d','_','d','a','t','a'}; - static const struct unicode_str intl_str = {intlW, sizeof(intlW)}; - static const struct unicode_str user_data_str = {user_dataW, sizeof(user_dataW)}; -+ static const struct unicode_str hypervisor_data_str = {hypervisor_dataW, sizeof(hypervisor_dataW)}; - - struct directory *dir_driver, *dir_device, *dir_global, *dir_kernel, *dir_nls; - struct object *named_pipe_device, *mailslot_device, *null_device; -@@ -523,6 +525,7 @@ void init_directories( struct fd *intl_fd ) - /* mappings */ - release_object( create_fd_mapping( &dir_nls->obj, &intl_str, intl_fd, OBJ_PERMANENT, NULL )); - release_object( create_user_data_mapping( &dir_kernel->obj, &user_data_str, OBJ_PERMANENT, NULL )); -+ release_object( create_hypervisor_data_mapping( &dir_kernel->obj, &hypervisor_data_str, OBJ_PERMANENT, NULL )); - release_object( intl_fd ); - - release_object( named_pipe_device ); -diff --git a/server/fd.c b/server/fd.c -index 2750e229109..7a1cd4bcddc 100644 ---- a/server/fd.c -+++ b/server/fd.c -@@ -403,9 +403,18 @@ static struct list rel_timeout_list = LIST_INIT(rel_timeout_list); /* sorted rel - timeout_t current_time; - timeout_t monotonic_time; - -+struct hypervisor_shared_data *hypervisor_shared_data = NULL; - struct _KUSER_SHARED_DATA *user_shared_data = NULL; - static const int user_shared_data_timeout = 16; - -+/* 128-bit multiply a by b and return the high 64 bits, same as __umulh */ -+static UINT64 multiply_tsc(UINT64 a, UINT64 b) -+{ -+ UINT64 ah = a >> 32, al = (UINT32)a, bh = b >> 32, bl = (UINT32)b, m; -+ m = (ah * bl) + (bh * al) + ((al * bl) >> 32); -+ return (ah * bh) + (m >> 32); -+} -+ - static void atomic_store_ulong(volatile ULONG *ptr, ULONG value) - { - /* on x86 there should be total store order guarantees, so volatile is -@@ -428,7 +437,13 @@ static void set_user_shared_data_time(void) - } - #endif - -- qpc_bias = ((monotonic_time * qpc_freq / 10000000) << qpc_shift) - tsc; -+ if (!(qpc_bypass & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE)) -+ qpc_bias = ((monotonic_time * qpc_freq / 10000000) << qpc_shift) - tsc; -+ else -+ { -+ tsc = multiply_tsc(tsc, hypervisor_shared_data->QpcMultiplier); -+ qpc_bias = monotonic_time - tsc; -+ } - - /* on X86 there should be total store order guarantees, so volatile is enough - * to ensure the stores aren't reordered by the compiler, and then they will -@@ -447,7 +462,10 @@ static void set_user_shared_data_time(void) - atomic_store_ulong(&user_shared_data->TickCount.LowPart, tick_count); - atomic_store_long(&user_shared_data->TickCount.High1Time, tick_count >> 32); - atomic_store_ulong(&user_shared_data->TickCountLowDeprecated, tick_count); -- user_shared_data->QpcBias = qpc_bias; -+ if (qpc_bypass & SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE) -+ hypervisor_shared_data->QpcBias = qpc_bias; -+ else -+ user_shared_data->QpcBias = qpc_bias; - } - - void set_current_time(void) -diff --git a/server/file.h b/server/file.h -index 3f0c3a559b3..719af8c01b3 100644 ---- a/server/file.h -+++ b/server/file.h -@@ -134,6 +134,14 @@ static inline struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get - struct timeout_user; - extern timeout_t current_time; - extern timeout_t monotonic_time; -+ -+struct hypervisor_shared_data -+{ -+ UINT64 unknown; -+ UINT64 QpcMultiplier; -+ UINT64 QpcBias; -+}; -+extern struct hypervisor_shared_data *hypervisor_shared_data; - extern struct _KUSER_SHARED_DATA *user_shared_data; - - #define TICKS_PER_SEC 10000000 -@@ -188,6 +196,8 @@ extern struct mapping *create_fd_mapping( struct object *root, const struct unic - unsigned int attr, const struct security_descriptor *sd ); - extern struct object *create_user_data_mapping( struct object *root, const struct unicode_str *name, - unsigned int attr, const struct security_descriptor *sd ); -+extern struct object *create_hypervisor_data_mapping( struct object *root, const struct unicode_str *name, -+ unsigned int attr, const struct security_descriptor *sd ); - - /* device functions */ - -diff --git a/server/mapping.c b/server/mapping.c -index 2253591f6fa..07fb6decb62 100644 ---- a/server/mapping.c -+++ b/server/mapping.c -@@ -1107,10 +1107,24 @@ struct object *create_user_data_mapping( struct object *root, const struct unico - user_shared_data->SystemCall = 1; - } - return &mapping->obj; - } - -+struct object *create_hypervisor_data_mapping( struct object *root, const struct unicode_str *name, -+ unsigned int attr, const struct security_descriptor *sd ) -+{ -+ void *ptr; -+ struct mapping *mapping; -+ -+ if (!(mapping = create_mapping( root, name, attr, sizeof(struct hypervisor_shared_data), -+ SEC_COMMIT, 0, FILE_READ_DATA | FILE_WRITE_DATA, sd ))) return NULL; -+ ptr = mmap( NULL, mapping->size, PROT_WRITE, MAP_SHARED, get_unix_fd( mapping->fd ), 0 ); -+ if (ptr != MAP_FAILED) -+ hypervisor_shared_data = ptr; -+ return &mapping->obj; -+} -+ - /* create a file mapping */ - DECL_HANDLER(create_mapping) - { - struct object *root; - struct mapping *mapping; -From 3b066b60d21e0fa03ee713a5c11ecfc5252de53c Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Thu, 3 Jun 2021 22:56:08 +0300 -Subject: [PATCH] wineboot: Check if the kernel trusts TSC before using it for - Qpc. - -Even if the bits are claiming that TSC meets our requirements the -hardware implementation may still be broken. - -The Linux kernel does a lot of quality testing before deciding to use as -the clock source. If it (or the user, through an override) does not trust -the TSC we should not trust it either. - -CW-Bug-Id: #18918 -CW-Bug-Id: #18958 ---- - programs/wineboot/wineboot.c | 31 +++++++++++++++++++++++++++++++ - 1 file changed, 31 insertions(+) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 9bebededa4f..79a4bda4d67 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -315,6 +315,30 @@ static UINT64 read_tsc_frequency(void) - return freq; - } - -+static BOOL is_tsc_trusted_by_the_kernel(void) -+{ -+ char buf[4] = {}; -+ DWORD num_read; -+ HANDLE handle; -+ BOOL ret = TRUE; -+ -+ handle = CreateFileA( "\\??\\unix\\sys\\bus\\clocksource\\devices\\clocksource0\\current_clocksource", -+ GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); -+ -+ if (handle == INVALID_HANDLE_VALUE) -+ return TRUE; -+ -+ if (ReadFile( handle, buf, sizeof(buf)-1, &num_read, NULL )) -+ { -+ if (!!strcmp( "tsc", buf )) -+ ret = FALSE; -+ } -+ -+ CloseHandle( handle ); -+ -+ return ret; -+} -+ - static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) - { - int regs[4]; -@@ -346,6 +370,13 @@ static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) - WARN("No invariant TSC, disabling QpcBypass\n"); - return; - } -+ -+ if (!is_tsc_trusted_by_the_kernel()) -+ { -+ WARN("TSC is not trusted by the kernel, disabling QpcBypass.\n"); -+ return; -+ } -+ - data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED; - - /* check for rdtscp support bit */ -From 69f2470f937f46ae362d0ba5c144f170f5850a8e Mon Sep 17 00:00:00 2001 -From: Joshua Ashton -Date: Thu, 3 Jun 2021 20:27:49 +0100 -Subject: [PATCH] wineboot: Return TSC frequency in ~Mhz - -Some games such as Horizon Zero Dawn use this registry value to correlate values from rtdsc -> real time. - -In my testing across a few devices, Windows always returns the tsc frequency in this entry, not the current/maximum frequency of the processor. - -Returning the nominal/maximum cpu frequency here causes the game to run in slow motion as it may not match the tsc frequency of the processor. - -Ideally we'd not have to measure this and the kernel would return tsc_khz to userspace, but this is a good enough stop-gap until https://lkml.org/lkml/2020/12/31/72 or something similar is merged. - -Fixes: #4125 (Slow motion bug) - -Signed-off-by: Joshua Ashton ---- - programs/wineboot/wineboot.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 79a4bda4d67..0662feac9ce 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -969,12 +969,15 @@ static void create_hardware_registry_keys(void) - if (!RegCreateKeyExW( cpu_key, numW, 0, NULL, REG_OPTION_VOLATILE, - KEY_ALL_ACCESS, NULL, &hkey, NULL )) - { -+ UINT64 tsc_freq = read_tsc_frequency(); /* Hz */ -+ DWORD tsc_freq_mhz = (DWORD)(tsc_freq / 1000000ull); -+ - RegSetValueExW( hkey, L"FeatureSet", 0, REG_DWORD, (BYTE *)&sci.ProcessorFeatureBits, sizeof(DWORD) ); - set_reg_value( hkey, L"Identifier", id ); - /* TODO: report ARM properly */ - set_reg_value( hkey, L"ProcessorNameString", namestr ); - set_reg_value( hkey, L"VendorIdentifier", vendorid ); -- RegSetValueExW( hkey, L"~MHz", 0, REG_DWORD, (BYTE *)&power_info[i].MaxMhz, sizeof(DWORD) ); -+ RegSetValueExW( hkey, L"~MHz", 0, REG_DWORD, (BYTE *)&tsc_freq_mhz, sizeof(DWORD) ); - RegCloseKey( hkey ); - } - if (sci.ProcessorArchitecture != PROCESSOR_ARCHITECTURE_ARM && -From 2bde7d53b3874dfc6f3066819e00da142443a48f Mon Sep 17 00:00:00 2001 -From: Joshua Ashton -Date: Fri, 4 Jun 2021 10:20:51 +0200 -Subject: [PATCH] wineboot: Calculate TSC frequency once at the start - -This calculates the TSC frequency once at the very start of wineboot. - -This avoids needing to calculate this multiple times which can lead to stalls. - -Signed-off-by: Joshua Ashton ---- - programs/wineboot/wineboot.c | 26 ++++++++++++++------------ - 1 file changed, 14 insertions(+), 12 deletions(-) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 0662feac9ce..dc0e645dd09 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -339,7 +339,7 @@ static BOOL is_tsc_trusted_by_the_kernel(void) - return ret; - } - --static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) -+static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data, UINT64 tsc_frequency) - { - int regs[4]; - -@@ -388,7 +388,7 @@ static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) - else - data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_MFENCE; - -- if ((data->QpcFrequency = (read_tsc_frequency() >> 10))) -+ if ((data->QpcFrequency = (tsc_frequency >> 10))) - { - data->QpcShift = 10; - data->QpcBias = 0; -@@ -433,7 +433,7 @@ static UINT64 muldiv_tsc(UINT64 a, UINT64 b, UINT64 c) - return ka * kb * c + kb * ra + ka * rb + (ra * rb + c / 2) / c; - } - --static void create_hypervisor_shared_data(void) -+static void create_hypervisor_shared_data(UINT64 tsc_frequency) - { - struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; - struct hypervisor_shared_data *hypervisor_shared_data; -@@ -480,7 +480,7 @@ static void create_hypervisor_shared_data(void) - - if (user_shared_data->QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED) - { -- hypervisor_shared_data->QpcMultiplier = muldiv_tsc((UINT64)5000 << 32, (UINT64)2000 << 32, read_tsc_frequency()); -+ hypervisor_shared_data->QpcMultiplier = muldiv_tsc((UINT64)5000 << 32, (UINT64)2000 << 32, tsc_frequency); - user_shared_data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE; - user_shared_data->QpcInterruptTimeIncrement = (ULONGLONG)1 << 63; - user_shared_data->QpcInterruptTimeIncrementShift = 1; -@@ -495,7 +495,7 @@ static void create_hypervisor_shared_data(void) - UnmapViewOfFile( hypervisor_shared_data ); - } - --static void create_user_shared_data(void) -+static void create_user_shared_data(UINT64 tsc_frequency) - { - struct _KUSER_SHARED_DATA *data; - RTL_OSVERSIONINFOEXW version; -@@ -582,7 +582,7 @@ static void create_user_shared_data(void) - data->ActiveGroupCount = 1; - - initialize_xstate_features( data ); -- initialize_qpc_features( data ); -+ initialize_qpc_features( data, tsc_frequency ); - - UnmapViewOfFile( data ); - } -@@ -894,7 +894,7 @@ static void create_bios_key( HKEY system_key ) - } - - /* create the volatile hardware registry keys */ --static void create_hardware_registry_keys(void) -+static void create_hardware_registry_keys(UINT64 tsc_frequency) - { - unsigned int i; - HKEY hkey, system_key, cpu_key, fpu_key; -@@ -969,8 +969,7 @@ static void create_hardware_registry_keys(void) - if (!RegCreateKeyExW( cpu_key, numW, 0, NULL, REG_OPTION_VOLATILE, - KEY_ALL_ACCESS, NULL, &hkey, NULL )) - { -- UINT64 tsc_freq = read_tsc_frequency(); /* Hz */ -- DWORD tsc_freq_mhz = (DWORD)(tsc_freq / 1000000ull); -+ DWORD tsc_freq_mhz = (DWORD)(tsc_frequency / 1000000ull); /* Hz -> Mhz */ - - RegSetValueExW( hkey, L"FeatureSet", 0, REG_DWORD, (BYTE *)&sci.FeatureSet, sizeof(DWORD) ); - set_reg_value( hkey, L"Identifier", id ); -@@ -1896,9 +1895,12 @@ int __cdecl main( int argc, char *argv[] ) - BOOL end_session, force, init, kill, restart, shutdown, update; - HANDLE event; - OBJECT_ATTRIBUTES attr; -+ UINT64 tsc_frequency; - UNICODE_STRING nameW; - BOOL is_wow64; - -+ tsc_frequency = read_tsc_frequency(); -+ - end_session = force = init = kill = restart = shutdown = update = FALSE; - GetWindowsDirectoryW( windowsdir, MAX_PATH ); - if( !SetCurrentDirectoryW( windowsdir ) ) -@@ -1981,9 +1983,9 @@ int __cdecl main( int argc, char *argv[] ) - - ResetEvent( event ); /* in case this is a restart */ - -- create_user_shared_data(); -- create_hypervisor_shared_data(); -- create_hardware_registry_keys(); -+ create_user_shared_data(tsc_frequency); -+ create_hypervisor_shared_data(tsc_frequency); -+ create_hardware_registry_keys(tsc_frequency); - create_dynamic_registry_keys(); - create_environment_registry_keys(); - create_computer_name_keys(); -From 9490a634610c111aba940c527200f3fdba113e96 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 7 Oct 2021 17:50:51 +0200 -Subject: [PATCH] wineboot: Calibrate TSC frequency after reading CPU - capabilities. - -To support old CPUs without rdtscp / rdtsc instructions. ---- - programs/wineboot/wineboot.c | 50 ++++++++++++++++++++++++------------ - 1 file changed, 33 insertions(+), 17 deletions(-) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index f82e2cfc26a..1baedd084a3 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -243,7 +243,7 @@ static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) - TRACE("XSAVE feature 2 %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]); - } - --static UINT64 read_tsc_frequency(void) -+static UINT64 read_tsc_frequency(BOOL use_rdtscp) - { - UINT64 freq = 0; - -@@ -287,16 +287,30 @@ static UINT64 read_tsc_frequency(void) - LONGLONG time0, time1, tsc0, tsc1, tsc2, tsc3, freq0, freq1, error; - unsigned int aux; - UINT retries = 50; -+ int regs[4]; - - do - { -- tsc0 = __rdtscp(&aux); -- time0 = RtlGetSystemTimePrecise(); -- tsc1 = __rdtscp(&aux); -- Sleep(1); -- tsc2 = __rdtscp(&aux); -- time1 = RtlGetSystemTimePrecise(); -- tsc3 = __rdtscp(&aux); -+ if (use_rdtscp) -+ { -+ tsc0 = __rdtscp(&aux); -+ time0 = RtlGetSystemTimePrecise(); -+ tsc1 = __rdtscp(&aux); -+ Sleep(1); -+ tsc2 = __rdtscp(&aux); -+ time1 = RtlGetSystemTimePrecise(); -+ tsc3 = __rdtscp(&aux); -+ } -+ else -+ { -+ tsc0 = __rdtsc(); __cpuid(regs, 0); -+ time0 = RtlGetSystemTimePrecise(); -+ tsc1 = __rdtsc(); __cpuid(regs, 0); -+ Sleep(1); -+ tsc2 = __rdtsc(); __cpuid(regs, 0); -+ time1 = RtlGetSystemTimePrecise(); -+ tsc3 = __rdtsc(); __cpuid(regs, 0); -+ } - - freq0 = (tsc2 - tsc0) * 10000000 / (time1 - time0); - freq1 = (tsc3 - tsc1) * 10000000 / (time1 - time0); -@@ -339,7 +353,7 @@ static BOOL is_tsc_trusted_by_the_kernel(void) - return ret; - } - --static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data, UINT64 tsc_frequency) -+static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data, UINT64 *tsc_frequency) - { - int regs[4]; - -@@ -388,7 +402,9 @@ static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data, UINT64 tsc_ - else - data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_MFENCE; - -- if ((data->QpcFrequency = (tsc_frequency >> 10))) -+ *tsc_frequency = read_tsc_frequency((regs[3] & (1 << 27)) != 0); -+ -+ if ((data->QpcFrequency = (*tsc_frequency >> 10))) - { - data->QpcShift = 10; - data->QpcBias = 0; -@@ -410,12 +426,13 @@ static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) - { - } - --static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data) -+static void initialize_qpc_features(struct _KUSER_SHARED_DATA *data, UINT64 *tsc_frequency) - { - data->QpcBypassEnabled = 0; - data->QpcFrequency = TICKSPERSEC; - data->QpcShift = 0; - data->QpcBias = 0; -+ *tsc_frequency = 0; - } - - #endif -@@ -478,7 +495,7 @@ static void create_hypervisor_shared_data(UINT64 tsc_frequency) - hypervisor_shared_data->QpcMultiplier = 0; - hypervisor_shared_data->QpcBias = 0; - -- if (user_shared_data->QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED) -+ if ((user_shared_data->QpcBypassEnabled & SHARED_GLOBAL_FLAGS_QPC_BYPASS_ENABLED) && tsc_frequency) - { - hypervisor_shared_data->QpcMultiplier = muldiv_tsc((UINT64)5000 << 32, (UINT64)2000 << 32, tsc_frequency); - user_shared_data->QpcBypassEnabled |= SHARED_GLOBAL_FLAGS_QPC_BYPASS_USE_HV_PAGE; -@@ -495,7 +512,7 @@ static void create_hypervisor_shared_data(UINT64 tsc_frequency) - UnmapViewOfFile( hypervisor_shared_data ); - } - --static void create_user_shared_data(UINT64 tsc_frequency) -+static void create_user_shared_data(UINT64 *tsc_frequency) - { - struct _KUSER_SHARED_DATA *data; - RTL_OSVERSIONINFOEXW version; -@@ -970,6 +987,7 @@ static void create_hardware_registry_keys(UINT64 tsc_frequency) - KEY_ALL_ACCESS, NULL, &hkey, NULL )) - { - DWORD tsc_freq_mhz = (DWORD)(tsc_frequency / 1000000ull); /* Hz -> Mhz */ -+ if (!tsc_freq_mhz) tsc_freq_mhz = power_info[i].MaxMhz; - - RegSetValueExW( hkey, L"FeatureSet", 0, REG_DWORD, (BYTE *)&sci.FeatureSet, sizeof(DWORD) ); - set_reg_value( hkey, L"Identifier", id ); -@@ -1929,12 +1947,10 @@ int __cdecl main( int argc, char *argv[] ) - BOOL end_session, force, init, kill, restart, shutdown, update; - HANDLE event; - OBJECT_ATTRIBUTES attr; -- UINT64 tsc_frequency; -+ UINT64 tsc_frequency = 0; - UNICODE_STRING nameW; - BOOL is_wow64; - -- tsc_frequency = read_tsc_frequency(); -- - end_session = force = init = kill = restart = shutdown = update = FALSE; - GetWindowsDirectoryW( windowsdir, MAX_PATH ); - if( !SetCurrentDirectoryW( windowsdir ) ) -@@ -2017,7 +2033,7 @@ int __cdecl main( int argc, char *argv[] ) - - ResetEvent( event ); /* in case this is a restart */ - -- create_user_shared_data(tsc_frequency); -+ create_user_shared_data(&tsc_frequency); - create_hypervisor_shared_data(tsc_frequency); - create_hardware_registry_keys(tsc_frequency); - create_dynamic_registry_keys(); diff --git a/patches/proton/50-proton_LFH.patch b/patches/proton/50-proton_LFH.patch deleted file mode 100644 index 3631b8966..000000000 --- a/patches/proton/50-proton_LFH.patch +++ /dev/null @@ -1,3044 +0,0 @@ -From 41b214de987308a747193805de27358f7c89c662 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Sat, 25 Apr 2020 12:26:57 +0200 -Subject: [PATCH 01/18] kernel32: Catch page faults in GlobalSize. - -In the same way GlobalFree does already. ---- - dlls/kernel32/heap.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/dlls/kernel32/heap.c b/dlls/kernel32/heap.c -index 02f4587d43b..e68135e499d 100644 ---- a/dlls/kernel32/heap.c -+++ b/dlls/kernel32/heap.c -@@ -326,6 +326,8 @@ SIZE_T WINAPI GlobalSize(HGLOBAL hmem) - return 0; - } - -+ __TRY -+ { - if(ISPOINTER(hmem)) - { - retval=HeapSize(GetProcessHeap(), 0, hmem); -@@ -359,6 +361,14 @@ SIZE_T WINAPI GlobalSize(HGLOBAL hmem) - } - RtlUnlockHeap(GetProcessHeap()); - } -+ } -+ __EXCEPT_PAGE_FAULT -+ { -+ SetLastError( ERROR_INVALID_HANDLE ); -+ retval = 0; -+ } -+ __ENDTRY -+ - if (retval == ~(SIZE_T)0) retval = 0; - return retval; - } - -From 6d07b74fd0737b154b4a98eb60cb3d89d794e1cd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 5 May 2020 13:44:57 +0200 -Subject: [PATCH 02/18] kernel32/tests: Add HeapSetInformation and LFH tests. - ---- - dlls/kernel32/tests/heap.c | 68 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 68 insertions(+) - -diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c -index 8558bd7f1b3..db96fb010b4 100644 ---- a/dlls/kernel32/tests/heap.c -+++ b/dlls/kernel32/tests/heap.c -@@ -42,6 +42,7 @@ - static LPVOID (WINAPI *pHeapAlloc)(HANDLE,DWORD,SIZE_T); - static LPVOID (WINAPI *pHeapReAlloc)(HANDLE,DWORD,LPVOID,SIZE_T); - static BOOL (WINAPI *pHeapQueryInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); -+static BOOL (WINAPI *pHeapSetInformation)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T); - static BOOL (WINAPI *pGetPhysicallyInstalledSystemMemory)(ULONGLONG *); - static ULONG (WINAPI *pRtlGetNtGlobalFlags)(void); - -@@ -528,6 +529,8 @@ static void test_HeapCreate(void) - UINT i; - BOOL error; - DWORD dwSize; -+ ULONG hci; -+ SIZE_T size; - - /* Retrieve the page size for this system */ - GetSystemInfo(&sysInfo); -@@ -624,6 +627,71 @@ static void test_HeapCreate(void) - - /* Check that HeapDestroy works */ - ok(HeapDestroy(heap),"HeapDestroy failed\n"); -+ -+ -+ if (!(pHeapQueryInformation = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "HeapQueryInformation")) || -+ !(pHeapSetInformation = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "HeapSetInformation"))) -+ win_skip("HeapQueryInformation / HeapSetInformation not available\n"); -+ else -+ { -+ heap = HeapCreate(0, 0, 0); -+ ok(!!heap, "HeapCreate failed\n"); -+ -+ mem1 = HeapAlloc(heap, 0, 16); -+ mem2 = HeapAlloc(heap, 0, 16); -+ -+ ok(pHeapQueryInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci), &size), -+ "HeapQueryInformation failed\n"); -+ trace("HeapQueryInformation returned %d\n", hci); -+ -+ hci = 2; -+ ok(pHeapSetInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci)), -+ "HeapSetInformation failed\n"); -+ ok(pHeapQueryInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci), &size), -+ "HeapQueryInformation failed\n"); -+ trace("HeapQueryInformation returned %d\n", hci); -+ -+ hci = 1; -+ SetLastError(0xdeadbeef); -+ todo_wine -+ ok(!pHeapSetInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci)), -+ "HeapSetInformation succeeded\n"); -+ todo_wine -+ ok(GetLastError() == ERROR_GEN_FAILURE, -+ "expected ERROR_GEN_FAILURE, got %u\n", GetLastError()); -+ -+ mem3 = HeapAlloc(heap, 0, 16); -+ -+ ok(HeapValidate(heap, 0, NULL), "HeapValidate failed\n"); -+ -+ SetLastError(0xdeadbeef); -+ dwSize = HeapSize(heap, 0, mem1); -+ ok(dwSize == 16, "HeapSize failed\n"); -+ ok(GetLastError() == 0xdeadbeef, "GetLastError failed: %u\n", GetLastError()); -+ mem1 = HeapReAlloc(heap, 0, mem1, 1024); -+ ok(mem1 != NULL, "HeapReAlloc failed\n"); -+ -+ dwSize = HeapSize(heap, 0, mem1); -+ ok(dwSize == 1024, "HeapSize failed\n"); -+ -+ dwSize = HeapSize(heap, 0, mem2); -+ ok(dwSize == 16, "HeapSize failed\n"); -+ ok(GetLastError() == 0xdeadbeef, "GetLastError failed: %u\n", GetLastError()); -+ -+ dwSize = HeapSize(heap, 0, mem3); -+ ok(dwSize == 16, "HeapSize failed\n"); -+ ok(GetLastError() == 0xdeadbeef, "GetLastError failed: %u\n", GetLastError()); -+ -+ ok(HeapValidate(heap, 0, NULL), "HeapValidate failed\n"); -+ -+ ok(HeapFree(heap, 0, mem1), "HeapFree failed\n"); -+ ok(HeapFree(heap, 0, mem2), "HeapFree failed\n"); -+ ok(HeapFree(heap, 0, mem3), "HeapFree failed\n"); -+ -+ ok(HeapValidate(heap, 0, NULL), "HeapValidate failed\n"); -+ -+ ok(HeapDestroy(heap),"HeapDestroy failed\n"); -+ } - } - - - -From d0249a662c5930b8b5f3ea4c85414de0d10bf8aa Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Mar 2021 19:20:28 +0100 -Subject: [PATCH 03/18] kernelbase: Allocate at least 1024 bytes in - Local/GlobalAlloc. - ---- - dlls/kernelbase/memory.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c -index 847005e8abe..2910d9617e1 100644 ---- a/dlls/kernelbase/memory.c -+++ b/dlls/kernelbase/memory.c -@@ -638,7 +638,12 @@ HLOCAL WINAPI DECLSPEC_HOTPATCH LocalAlloc( UINT flags, SIZE_T size ) - - if (!(flags & LMEM_MOVEABLE)) /* pointer */ - { -- ptr = HeapAlloc( GetProcessHeap(), heap_flags, size ); -+ if (size >= 1024) ptr = HeapAlloc( GetProcessHeap(), heap_flags, size ); -+ else -+ { -+ ptr = HeapAlloc( GetProcessHeap(), heap_flags, 1024 ); -+ ptr = HeapReAlloc( GetProcessHeap(), heap_flags, ptr, size ); -+ } - TRACE( "(flags=%04x) returning %p\n", flags, ptr ); - return ptr; - } - -From 5752f2e959bb4a4a07a7a5cbc843bb3124d133bf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 28 Aug 2019 22:24:42 +0200 -Subject: [PATCH 04/18] ntdll: Lock heap critical section outside of - HEAP_IsRealArena. - ---- - dlls/ntdll/heap.c | 58 +++++++++++++++++++++++++---------------------- - 1 file changed, 31 insertions(+), 27 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index cae41cba0d9..69a3de404fb 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -451,21 +451,26 @@ static HEAP *HEAP_GetPtr( - HANDLE heap /* [in] Handle to the heap */ - ) { - HEAP *heapPtr = heap; -+ BOOL ret; -+ - if (!heapPtr || (heapPtr->magic != HEAP_MAGIC)) - { - ERR("Invalid heap %p!\n", heap ); - return NULL; - } -- if ((heapPtr->flags & HEAP_VALIDATE_ALL) && !HEAP_IsRealArena( heapPtr, 0, NULL, NOISY )) -+ if (!(heapPtr->flags & HEAP_VALIDATE_ALL)) return heapPtr; -+ -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ ret = HEAP_IsRealArena( heapPtr, heapPtr->flags, NULL, NOISY ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ -+ if (ret) return heapPtr; -+ if (TRACE_ON(heap)) - { -- if (TRACE_ON(heap)) -- { -- HEAP_Dump( heapPtr ); -- assert( FALSE ); -- } -- return NULL; -+ HEAP_Dump( heapPtr ); -+ assert( FALSE ); - } -- return heapPtr; -+ return NULL; - } - - -@@ -1331,15 +1336,8 @@ static BOOL HEAP_IsRealArena( HEAP *heapPtr, /* [in] ptr to the heap */ - * does not complain */ - { - SUBHEAP *subheap; -- BOOL ret = FALSE; - const ARENA_LARGE *large_arena; - -- flags &= HEAP_NO_SERIALIZE; -- flags |= heapPtr->flags; -- /* calling HeapLock may result in infinite recursion, so do the critsect directly */ -- if (!(flags & HEAP_NO_SERIALIZE)) -- enter_critical_section( &heapPtr->critSection ); -- - if (block) /* only check this single memory block */ - { - const ARENA_INUSE *arena = (const ARENA_INUSE *)block - 1; -@@ -1353,11 +1351,11 @@ static BOOL HEAP_IsRealArena( HEAP *heapPtr, /* [in] ptr to the heap */ - ERR("Heap %p: block %p is not inside heap\n", heapPtr, block ); - else if (WARN_ON(heap)) - WARN("Heap %p: block %p is not inside heap\n", heapPtr, block ); -+ return FALSE; - } -- else ret = validate_large_arena( heapPtr, large_arena, quiet ); -+ return validate_large_arena( heapPtr, large_arena, quiet ); - } -- else ret = HEAP_ValidateInUseArena( subheap, arena, quiet ); -- goto done; -+ return HEAP_ValidateInUseArena( subheap, arena, quiet ); - } - - LIST_FOR_EACH_ENTRY( subheap, &heapPtr->subheap_list, SUBHEAP, entry ) -@@ -1367,25 +1365,21 @@ static BOOL HEAP_IsRealArena( HEAP *heapPtr, /* [in] ptr to the heap */ - { - if (*(DWORD *)ptr & ARENA_FLAG_FREE) - { -- if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) goto done; -+ if (!HEAP_ValidateFreeArena( subheap, (ARENA_FREE *)ptr )) return FALSE; - ptr += sizeof(ARENA_FREE) + (*(DWORD *)ptr & ARENA_SIZE_MASK); - } - else - { -- if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) goto done; -+ if (!HEAP_ValidateInUseArena( subheap, (ARENA_INUSE *)ptr, NOISY )) return FALSE; - ptr += sizeof(ARENA_INUSE) + (*(DWORD *)ptr & ARENA_SIZE_MASK); - } - } - } - - LIST_FOR_EACH_ENTRY( large_arena, &heapPtr->large_list, ARENA_LARGE, entry ) -- if (!validate_large_arena( heapPtr, large_arena, quiet )) goto done; -- -- ret = TRUE; -+ if (!validate_large_arena( heapPtr, large_arena, quiet )) return FALSE; - --done: -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- return ret; -+ return TRUE; - } - - -@@ -2062,9 +2056,19 @@ SIZE_T WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, const void *ptr ) - */ - BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, LPCVOID ptr ) - { -+ BOOLEAN ret; - HEAP *heapPtr = HEAP_GetPtr( heap ); - if (!heapPtr) return FALSE; -- return HEAP_IsRealArena( heapPtr, flags, ptr, QUIET ); -+ -+ flags &= HEAP_NO_SERIALIZE; -+ flags |= heapPtr->flags; -+ -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ ret = HEAP_IsRealArena( heapPtr, flags, ptr, QUIET ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ -+ TRACE("(%p,%08x,%p): returning %d\n", heapPtr, flags, ptr, ret ); -+ return ret; - } - - - -From 32fcd770e6962851d0e3592520e9a85e37b8af59 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Mar 2021 15:05:42 +0100 -Subject: [PATCH 05/18] ntdll: Split RtlSizeHeap standard implementation. - ---- - dlls/ntdll/heap.c | 43 +++++++++++++++++++++-------------------- - dlls/ntdll/ntdll_misc.h | 2 ++ - 2 files changed, 24 insertions(+), 21 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index 69a3de404fb..673223797bf 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -2004,39 +2004,40 @@ BOOLEAN WINAPI RtlUnlockHeap( HANDLE heap ) - */ - SIZE_T WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, const void *ptr ) - { -- SIZE_T ret; -- const ARENA_INUSE *pArena; -- SUBHEAP *subheap; - HEAP *heapPtr = HEAP_GetPtr( heap ); -+ NTSTATUS status; -+ SIZE_T size = ~(SIZE_T)0; - - if (!heapPtr) - { - RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_HANDLE ); - return ~(SIZE_T)0; - } -+ - flags &= HEAP_NO_SERIALIZE; - flags |= heapPtr->flags; -- if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - -- pArena = (const ARENA_INUSE *)ptr - 1; -- if (!validate_block_pointer( heapPtr, &subheap, pArena )) -- { -- RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_PARAMETER ); -- ret = ~(SIZE_T)0; -- } -- else if (!subheap) -- { -- const ARENA_LARGE *large_arena = (const ARENA_LARGE *)ptr - 1; -- ret = large_arena->data_size; -- } -- else -- { -- ret = (pArena->size & ARENA_SIZE_MASK) - pArena->unused_bytes; -- } -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ status = HEAP_std_get_allocated_size( heap, flags, ptr, &size ); - if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - -- TRACE("(%p,%08x,%p): returning %08lx\n", heap, flags, ptr, ret ); -- return ret; -+ TRACE("(%p,%08x,%p): status %#x, size %08lx\n", heapPtr, flags, ptr, status, size ); -+ if (!status) return size; -+ RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status ); -+ return ~(SIZE_T)0; -+} -+ -+NTSTATUS HEAP_std_get_allocated_size( HANDLE heap, ULONG flags, const void *ptr, SIZE_T *out ) -+{ -+ const ARENA_LARGE *large_arena = (const ARENA_LARGE *)ptr - 1; -+ const ARENA_INUSE *arena = (const ARENA_INUSE *)ptr - 1; -+ HEAP *heapPtr = heap; -+ SUBHEAP *subheap; -+ -+ if (!validate_block_pointer( heapPtr, &subheap, arena )) return STATUS_INVALID_PARAMETER; -+ else if (!subheap) *out = large_arena->data_size; -+ else *out = (arena->size & ARENA_SIZE_MASK) - arena->unused_bytes; -+ return STATUS_SUCCESS; - } - - -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index 30640366f5b..81e1387e734 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -105,6 +105,8 @@ static inline TEB64 *NtCurrentTeb64(void) { return NULL; } - static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } - #endif - -+NTSTATUS HEAP_std_get_allocated_size( HANDLE heap, ULONG flags, const void *ptr, SIZE_T *out ); -+ - #define HASH_STRING_ALGORITHM_DEFAULT 0 - #define HASH_STRING_ALGORITHM_X65599 1 - #define HASH_STRING_ALGORITHM_INVALID 0xffffffff - -From 7e40660dca2e29c5a1ad406d6c33d06a37c98092 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Mar 2021 15:09:12 +0100 -Subject: [PATCH 06/18] ntdll: Split RtlFreeHeap standard implementation. - ---- - dlls/ntdll/heap.c | 30 ++++++++++++++++++------------ - dlls/ntdll/ntdll_misc.h | 1 + - 2 files changed, 19 insertions(+), 12 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index 673223797bf..f6e05cc3aa1 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -1729,8 +1729,7 @@ void * WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE heap, ULONG flags, SIZE_ - */ - BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE heap, ULONG flags, void *ptr ) - { -- ARENA_INUSE *pInUse; -- SUBHEAP *subheap; -+ NTSTATUS status; - HEAP *heapPtr; - - /* Validate the parameters */ -@@ -1746,29 +1745,36 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE heap, ULONG flags, void *pt - - flags &= HEAP_NO_SERIALIZE; - flags |= heapPtr->flags; -+ - if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ status = HEAP_std_free( heap, flags, ptr ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ -+ TRACE("(%p,%08x,%p), status %#x\n", heapPtr, flags, ptr, status ); -+ if (!status) return TRUE; -+ RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status ); -+ return FALSE; -+} -+ -+NTSTATUS HEAP_std_free( HANDLE heap, ULONG flags, void *ptr ) -+{ -+ ARENA_INUSE *pInUse; -+ HEAP *heapPtr = heap; -+ SUBHEAP *subheap; - - /* Inform valgrind we are trying to free memory, so it can throw up an error message */ - notify_free( ptr ); - - /* Some sanity checks */ - pInUse = (ARENA_INUSE *)ptr - 1; -- if (!validate_block_pointer( heapPtr, &subheap, pInUse )) goto error; -+ if (!validate_block_pointer( heapPtr, &subheap, pInUse )) return STATUS_INVALID_PARAMETER; - - if (!subheap) - free_large_block( heapPtr, flags, ptr ); - else - HEAP_MakeInUseBlockFree( subheap, pInUse ); - -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- TRACE("(%p,%08x,%p): returning TRUE\n", heap, flags, ptr ); -- return TRUE; -- --error: -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_PARAMETER ); -- TRACE("(%p,%08x,%p): returning FALSE\n", heap, flags, ptr ); -- return FALSE; -+ return STATUS_SUCCESS; - } - - -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index 81e1387e734..d134000f949 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -105,6 +105,7 @@ static inline TEB64 *NtCurrentTeb64(void) { return NULL; } - static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } - #endif - -+NTSTATUS HEAP_std_free( HANDLE heap, ULONG flags, void *ptr ); - NTSTATUS HEAP_std_get_allocated_size( HANDLE heap, ULONG flags, const void *ptr, SIZE_T *out ); - - #define HASH_STRING_ALGORITHM_DEFAULT 0 - -From c3d16d6c08ea66c3b53fb846017ab002ee98dd8a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Mar 2021 15:13:43 +0100 -Subject: [PATCH 07/18] ntdll: Split RtlAllocateHeap standard implementation. - ---- - dlls/ntdll/heap.c | 56 ++++++++++++++++++++--------------------- - dlls/ntdll/ntdll_misc.h | 1 + - 2 files changed, 29 insertions(+), 28 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index f6e05cc3aa1..0d42dbaccea 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -1644,46 +1644,48 @@ HANDLE WINAPI RtlDestroyHeap( HANDLE heap ) - */ - void * WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE heap, ULONG flags, SIZE_T size ) - { -- ARENA_FREE *pArena; -- ARENA_INUSE *pInUse; -- SUBHEAP *subheap; -+ NTSTATUS status; - HEAP *heapPtr = HEAP_GetPtr( heap ); -- SIZE_T rounded_size; -+ void *ptr; - - /* Validate the parameters */ - - if (!heapPtr) return NULL; - flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY; - flags |= heapPtr->flags; -- rounded_size = ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE; -- if (rounded_size < size) /* overflow */ -- { -- if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY ); -- return NULL; -- } -- if (rounded_size < HEAP_MIN_DATA_SIZE) rounded_size = HEAP_MIN_DATA_SIZE; - - if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ status = HEAP_std_allocate( heap, flags, size, &ptr ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ -+ TRACE("(%p,%08x,%08lx), status %#x, ptr %p\n", heapPtr, flags, size, status, ptr ); -+ if (!status) return ptr; -+ if ((flags & HEAP_GENERATE_EXCEPTIONS) && status == STATUS_NO_MEMORY) RtlRaiseStatus( status ); -+ RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status ); -+ return NULL; -+} -+ -+NTSTATUS HEAP_std_allocate( HANDLE heap, ULONG flags, SIZE_T size, void **out ) -+{ -+ HEAP *heapPtr = heap; -+ ARENA_FREE *pArena; -+ ARENA_INUSE *pInUse; -+ SUBHEAP *subheap; -+ SIZE_T rounded_size; -+ -+ rounded_size = ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE; -+ if (rounded_size < size) return STATUS_NO_MEMORY; /* overflow */ -+ if (rounded_size < HEAP_MIN_DATA_SIZE) rounded_size = HEAP_MIN_DATA_SIZE; - - if (rounded_size >= HEAP_MIN_LARGE_BLOCK_SIZE && (flags & HEAP_GROWABLE)) - { -- void *ret = allocate_large_block( heap, flags, size ); -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- if (!ret && (flags & HEAP_GENERATE_EXCEPTIONS)) RtlRaiseStatus( STATUS_NO_MEMORY ); -- TRACE("(%p,%08x,%08lx): returning %p\n", heap, flags, size, ret ); -- return ret; -+ if (!(*out = allocate_large_block( heapPtr, flags, size ))) return STATUS_NO_MEMORY; -+ return STATUS_SUCCESS; - } - - /* Locate a suitable free block */ - -- if (!(pArena = HEAP_FindFreeBlock( heapPtr, rounded_size, &subheap ))) -- { -- TRACE("(%p,%08x,%08lx): returning NULL\n", -- heap, flags, size ); -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY ); -- return NULL; -- } -+ if (!(pArena = HEAP_FindFreeBlock( heapPtr, rounded_size, &subheap ))) return STATUS_NO_MEMORY; - - /* Remove the arena from the free list */ - -@@ -1706,10 +1708,8 @@ void * WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE heap, ULONG flags, SIZE_ - notify_alloc( pInUse + 1, size, flags & HEAP_ZERO_MEMORY ); - initialize_block( pInUse + 1, size, pInUse->unused_bytes, flags ); - -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- -- TRACE("(%p,%08x,%08lx): returning %p\n", heap, flags, size, pInUse + 1 ); -- return pInUse + 1; -+ *out = pInUse + 1; -+ return STATUS_SUCCESS; - } - - -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index d134000f949..0a629e09510 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -105,6 +105,7 @@ static inline TEB64 *NtCurrentTeb64(void) { return NULL; } - static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } - #endif - -+NTSTATUS HEAP_std_allocate( HANDLE heap, ULONG flags, SIZE_T size, void **out ); - NTSTATUS HEAP_std_free( HANDLE heap, ULONG flags, void *ptr ); - NTSTATUS HEAP_std_get_allocated_size( HANDLE heap, ULONG flags, const void *ptr, SIZE_T *out ); - - -From 0568b9fbef50d3487a4a24b5dd4172d7072d614b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Mar 2021 15:19:29 +0100 -Subject: [PATCH 08/18] ntdll: Split RtlReAllocateHeap standard implementation. - ---- - dlls/ntdll/heap.c | 60 ++++++++++++++++++++--------------------- - dlls/ntdll/ntdll_misc.h | 1 + - 2 files changed, 30 insertions(+), 31 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index 0d42dbaccea..4a9b45856b7 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -1795,10 +1795,8 @@ NTSTATUS HEAP_std_free( HANDLE heap, ULONG flags, void *ptr ) - */ - PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size ) - { -- ARENA_INUSE *pArena; -+ NTSTATUS status; - HEAP *heapPtr; -- SUBHEAP *subheap; -- SIZE_T oldBlockSize, oldActualSize, rounded_size; - void *ret; - - if (!ptr) return NULL; -@@ -1814,17 +1812,33 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - HEAP_REALLOC_IN_PLACE_ONLY; - flags |= heapPtr->flags; - if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ status = HEAP_std_reallocate( heap, flags, ptr, size, &ret ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ -+ TRACE("(%p,%08x,%p,%08lx): returning %p, status %#x\n", heapPtr, flags, ptr, size, ret, status ); -+ if (!status) return ret; -+ if ((flags & HEAP_GENERATE_EXCEPTIONS) && (status == STATUS_NO_MEMORY)) RtlRaiseStatus( status ); -+ RtlSetLastWin32ErrorAndNtStatusFromNtStatus( status ); -+ return NULL; -+} -+ -+NTSTATUS HEAP_std_reallocate( HANDLE heap, ULONG flags, void *ptr, SIZE_T size, void **out ) -+{ -+ HEAP *heapPtr = heap; -+ ARENA_INUSE *pArena; -+ SUBHEAP *subheap; -+ SIZE_T oldBlockSize, oldActualSize, rounded_size; - - rounded_size = ROUND_SIZE(size) + HEAP_TAIL_EXTRA_SIZE; -- if (rounded_size < size) goto oom; /* overflow */ -+ if (rounded_size < size) return STATUS_NO_MEMORY; /* overflow */ - if (rounded_size < HEAP_MIN_DATA_SIZE) rounded_size = HEAP_MIN_DATA_SIZE; - - pArena = (ARENA_INUSE *)ptr - 1; -- if (!validate_block_pointer( heapPtr, &subheap, pArena )) goto error; -+ if (!validate_block_pointer( heapPtr, &subheap, pArena )) return STATUS_INVALID_PARAMETER; - if (!subheap) - { -- if (!(ret = realloc_large_block( heapPtr, flags, ptr, size ))) goto oom; -- goto done; -+ if (!(*out = realloc_large_block( heapPtr, flags, ptr, size ))) return STATUS_NO_MEMORY; -+ return STATUS_SUCCESS; - } - - /* Check if we need to grow the block */ -@@ -1837,12 +1851,12 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - - if (rounded_size >= HEAP_MIN_LARGE_BLOCK_SIZE && (flags & HEAP_GROWABLE)) - { -- if (flags & HEAP_REALLOC_IN_PLACE_ONLY) goto oom; -- if (!(ret = allocate_large_block( heapPtr, flags, size ))) goto oom; -- memcpy( ret, pArena + 1, oldActualSize ); -+ if (flags & HEAP_REALLOC_IN_PLACE_ONLY) return STATUS_NO_MEMORY; -+ if (!(*out = allocate_large_block( heapPtr, flags, size ))) return STATUS_NO_MEMORY; -+ memcpy( *out, pArena + 1, oldActualSize ); - notify_free( pArena + 1 ); - HEAP_MakeInUseBlockFree( subheap, pArena ); -- goto done; -+ return STATUS_SUCCESS; - } - if ((pNext < (char *)subheap->base + subheap->size) && - (*(DWORD *)pNext & ARENA_FLAG_FREE) && -@@ -1852,7 +1866,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - ARENA_FREE *pFree = (ARENA_FREE *)pNext; - list_remove( &pFree->entry ); - pArena->size += (pFree->size & ARENA_SIZE_MASK) + sizeof(*pFree); -- if (!HEAP_Commit( subheap, pArena, rounded_size )) goto oom; -+ if (!HEAP_Commit( subheap, pArena, rounded_size )) return STATUS_NO_MEMORY; - notify_realloc( pArena + 1, oldActualSize, size ); - HEAP_ShrinkBlock( subheap, pArena, rounded_size ); - } -@@ -1864,7 +1878,7 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - - if ((flags & HEAP_REALLOC_IN_PLACE_ONLY) || - !(pNew = HEAP_FindFreeBlock( heapPtr, rounded_size, &newsubheap ))) -- goto oom; -+ return STATUS_NO_MEMORY; - - /* Build the in-use arena */ - -@@ -1905,24 +1919,8 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - - /* Return the new arena */ - -- ret = pArena + 1; --done: -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- TRACE("(%p,%08x,%p,%08lx): returning %p\n", heap, flags, ptr, size, ret ); -- return ret; -- --oom: -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- if (flags & HEAP_GENERATE_EXCEPTIONS) RtlRaiseStatus( STATUS_NO_MEMORY ); -- RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_NO_MEMORY ); -- TRACE("(%p,%08x,%p,%08lx): returning NULL\n", heap, flags, ptr, size ); -- return NULL; -- --error: -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -- RtlSetLastWin32ErrorAndNtStatusFromNtStatus( STATUS_INVALID_PARAMETER ); -- TRACE("(%p,%08x,%p,%08lx): returning NULL\n", heap, flags, ptr, size ); -- return NULL; -+ *out = pArena + 1; -+ return STATUS_SUCCESS; - } - - -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index 0a629e09510..468202d17eb 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -107,6 +107,7 @@ static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiB - - NTSTATUS HEAP_std_allocate( HANDLE heap, ULONG flags, SIZE_T size, void **out ); - NTSTATUS HEAP_std_free( HANDLE heap, ULONG flags, void *ptr ); -+NTSTATUS HEAP_std_reallocate( HANDLE heap, ULONG flags, void *ptr, SIZE_T size, void **out ); - NTSTATUS HEAP_std_get_allocated_size( HANDLE heap, ULONG flags, const void *ptr, SIZE_T *out ); - - #define HASH_STRING_ALGORITHM_DEFAULT 0 - -From 3dd5314d54770631bae800d5d9b83477a615411c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 28 Aug 2019 22:24:40 +0200 -Subject: [PATCH 09/18] ntdll: Add thread destroy notification function. - -This will be used in LFH to recycle the thread local data. ---- - dlls/ntdll/heap.c | 4 ++++ - dlls/ntdll/loader.c | 1 + - dlls/ntdll/ntdll_misc.h | 2 ++ - dlls/ntdll/thread.c | 1 + - 4 files changed, 8 insertions(+) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index 4a9b45856b7..43543bdb304 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -2266,3 +2266,7 @@ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE heap, HEAP_INFORMATION_CLASS info_ - FIXME("%p %d %p %ld stub\n", heap, info_class, info, size); - return STATUS_SUCCESS; - } -+ -+void HEAP_notify_thread_destroy( BOOLEAN last ) -+{ -+} -diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c -index 54806b0ab22..925742a81fd 100644 ---- a/dlls/ntdll/loader.c -+++ b/dlls/ntdll/loader.c -@@ -3369,6 +3369,7 @@ void WINAPI RtlExitUserProcess( DWORD status ) - RtlAcquirePebLock(); - NtTerminateProcess( 0, status ); - LdrShutdownProcess(); -+ HEAP_notify_thread_destroy(TRUE); - for (;;) NtTerminateProcess( GetCurrentProcess(), status ); - } - -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index 468202d17eb..6dadf3a74a5 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -110,6 +110,8 @@ NTSTATUS HEAP_std_free( HANDLE heap, ULONG flags, void *ptr ); - NTSTATUS HEAP_std_reallocate( HANDLE heap, ULONG flags, void *ptr, SIZE_T size, void **out ); - NTSTATUS HEAP_std_get_allocated_size( HANDLE heap, ULONG flags, const void *ptr, SIZE_T *out ); - -+void HEAP_notify_thread_destroy( BOOLEAN last ); -+ - #define HASH_STRING_ALGORITHM_DEFAULT 0 - #define HASH_STRING_ALGORITHM_X65599 1 - #define HASH_STRING_ALGORITHM_INVALID 0xffffffff -diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c -index d0c2a89d4bb..cdac28eb14d 100644 ---- a/dlls/ntdll/thread.c -+++ b/dlls/ntdll/thread.c -@@ -188,6 +188,7 @@ void WINAPI RtlExitUserThread( ULONG status ) - NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL ); - if (last) RtlExitUserProcess( status ); - LdrShutdownThread(); -+ HEAP_notify_thread_destroy(FALSE); - for (;;) NtTerminateThread( GetCurrentThread(), status ); - } - - -From 3ad5427e10fc7c7b06617d1f529b5067000ee918 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Mar 2021 18:40:11 +0100 -Subject: [PATCH 10/18] ntdll: Add extended heap type and LFH stubs. - ---- - dlls/ntdll/Makefile.in | 1 + - dlls/ntdll/heap.c | 92 ++++++++++++++++++++++++++++++++--------- - dlls/ntdll/heap_lfh.c | 57 +++++++++++++++++++++++++ - dlls/ntdll/ntdll_misc.h | 12 ++++++ - 4 files changed, 143 insertions(+), 19 deletions(-) - create mode 100644 dlls/ntdll/heap_lfh.c - -diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in -index 6dfe2eb12f9..f05d4cf831a 100644 ---- a/dlls/ntdll/Makefile.in -+++ b/dlls/ntdll/Makefile.in -@@ -18,6 +18,7 @@ C_SRCS = \ - exception.c \ - handletable.c \ - heap.c \ -+ heap_lfh.c \ - large_int.c \ - loader.c \ - locale.c \ -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index 43543bdb304..e4ed51ef522 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -163,6 +163,7 @@ typedef struct tagHEAP - ARENA_INUSE **pending_free; /* Ring buffer for pending free requests */ - RTL_CRITICAL_SECTION critSection; /* Critical section for serialization */ - FREE_LIST_ENTRY *freeList; /* Free lists */ -+ int extended_type; /* Extended heap type */ - } HEAP; - - #define HEAP_MAGIC ((DWORD)('H' | ('E'<<8) | ('A'<<16) | ('P'<<24))) -@@ -1506,6 +1507,8 @@ void heap_set_debug_flags( HANDLE handle ) - MAX_FREE_PENDING * sizeof(*heap->pending_free) ); - heap->pending_pos = 0; - } -+ -+ HEAP_lfh_set_debug_flags( flags ); - } - - -@@ -1549,11 +1552,13 @@ HANDLE WINAPI RtlCreateHeap( ULONG flags, PVOID addr, SIZE_T totalSize, SIZE_T c - HEAP *heapPtr = subheap->heap; - enter_critical_section( &processHeap->critSection ); - list_add_head( &processHeap->entry, &heapPtr->entry ); -+ heapPtr->extended_type = HEAP_STD; - leave_critical_section( &processHeap->critSection ); - } - else if (!addr) - { - processHeap = subheap->heap; /* assume the first heap we create is the process main heap */ -+ processHeap->extended_type = HEAP_STD; - list_init( &processHeap->entry ); - } - -@@ -1654,9 +1659,17 @@ void * WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE heap, ULONG flags, SIZE_ - flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY; - flags |= heapPtr->flags; - -- if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -- status = HEAP_std_allocate( heap, flags, size, &ptr ); -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ switch (heapPtr->extended_type) -+ { -+ case HEAP_LFH: -+ if (!(status = HEAP_lfh_allocate( heap, flags, size, &ptr ))) break; -+ /* fallthrough */ -+ default: -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ status = HEAP_std_allocate( heap, flags, size, &ptr ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ break; -+ } - - TRACE("(%p,%08x,%08lx), status %#x, ptr %p\n", heapPtr, flags, size, status, ptr ); - if (!status) return ptr; -@@ -1746,9 +1759,17 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE heap, ULONG flags, void *pt - flags &= HEAP_NO_SERIALIZE; - flags |= heapPtr->flags; - -- if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -- status = HEAP_std_free( heap, flags, ptr ); -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ switch (heapPtr->extended_type) -+ { -+ case HEAP_LFH: -+ if (!(status = HEAP_lfh_free( heap, flags, ptr ))) break; -+ /* fallthrough */ -+ default: -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ status = HEAP_std_free( heap, flags, ptr ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ break; -+ } - - TRACE("(%p,%08x,%p), status %#x\n", heapPtr, flags, ptr, status ); - if (!status) return TRUE; -@@ -1811,9 +1832,18 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - flags &= HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY | - HEAP_REALLOC_IN_PLACE_ONLY; - flags |= heapPtr->flags; -- if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -- status = HEAP_std_reallocate( heap, flags, ptr, size, &ret ); -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ -+ switch (heapPtr->extended_type) -+ { -+ case HEAP_LFH: -+ if (!(status = HEAP_lfh_reallocate( heap, flags, ptr, size, &ret ))) break; -+ /* fallthrough */ -+ default: -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ status = HEAP_std_reallocate( heap, flags, ptr, size, &ret ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ break; -+ } - - TRACE("(%p,%08x,%p,%08lx): returning %p, status %#x\n", heapPtr, flags, ptr, size, ret, status ); - if (!status) return ret; -@@ -2021,9 +2051,17 @@ SIZE_T WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, const void *ptr ) - flags &= HEAP_NO_SERIALIZE; - flags |= heapPtr->flags; - -- if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -- status = HEAP_std_get_allocated_size( heap, flags, ptr, &size ); -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ switch (heapPtr->extended_type) -+ { -+ case HEAP_LFH: -+ if (!(status = HEAP_lfh_get_allocated_size( heap, flags, ptr, &size ))) break; -+ /* fallthrough */ -+ default: -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ status = HEAP_std_get_allocated_size( heap, flags, ptr, &size ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ break; -+ } - - TRACE("(%p,%08x,%p): status %#x, size %08lx\n", heapPtr, flags, ptr, status, size ); - if (!status) return size; -@@ -2061,19 +2099,27 @@ NTSTATUS HEAP_std_get_allocated_size( HANDLE heap, ULONG flags, const void *ptr, - */ - BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, LPCVOID ptr ) - { -- BOOLEAN ret; -+ NTSTATUS status = STATUS_SUCCESS; - HEAP *heapPtr = HEAP_GetPtr( heap ); - if (!heapPtr) return FALSE; - - flags &= HEAP_NO_SERIALIZE; - flags |= heapPtr->flags; - -- if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -- ret = HEAP_IsRealArena( heapPtr, flags, ptr, QUIET ); -- if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ switch (heapPtr->extended_type) -+ { -+ case HEAP_LFH: -+ if (!(status = HEAP_lfh_validate( heapPtr, flags, ptr ))) return TRUE; -+ /* fallthrough */ -+ default: -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); -+ if (!HEAP_IsRealArena( heapPtr, flags, ptr, QUIET )) status = STATUS_INVALID_PARAMETER; -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); -+ break; -+ } - -- TRACE("(%p,%08x,%p): returning %d\n", heapPtr, flags, ptr, ret ); -- return ret; -+ TRACE("(%p,%08x,%p): status %#x\n", heapPtr, flags, ptr, status ); -+ return !status; - } - - -@@ -2241,6 +2287,13 @@ ULONG WINAPI RtlGetProcessHeaps( ULONG count, HANDLE *heaps ) - NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE heap, HEAP_INFORMATION_CLASS info_class, - PVOID info, SIZE_T size_in, PSIZE_T size_out) - { -+ HEAP *heapPtr; -+ -+ TRACE("%p %d %p %ld\n", heap, info_class, info, size_in); -+ -+ if (!(heapPtr = HEAP_GetPtr( heap ))) -+ return STATUS_INVALID_PARAMETER; -+ - switch (info_class) - { - case HeapCompatibilityInformation: -@@ -2249,7 +2302,7 @@ NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE heap, HEAP_INFORMATION_CLASS inf - if (size_in < sizeof(ULONG)) - return STATUS_BUFFER_TOO_SMALL; - -- *(ULONG *)info = 0; /* standard heap */ -+ *(ULONG *)info = heapPtr->extended_type; - return STATUS_SUCCESS; - - default: -@@ -2269,4 +2322,5 @@ NTSTATUS WINAPI RtlSetHeapInformation( HANDLE heap, HEAP_INFORMATION_CLASS info_ - - void HEAP_notify_thread_destroy( BOOLEAN last ) - { -+ HEAP_lfh_notify_thread_destroy( last ); - } -diff --git a/dlls/ntdll/heap_lfh.c b/dlls/ntdll/heap_lfh.c -new file mode 100644 -index 00000000000..0c324472e32 ---- /dev/null -+++ b/dlls/ntdll/heap_lfh.c -@@ -0,0 +1,57 @@ -+/* -+ * Wine Low Fragmentation Heap -+ * -+ * Copyright 2020 Remi 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 "ntstatus.h" -+#define WIN32_NO_STATUS -+ -+#include "ntdll_misc.h" -+ -+NTSTATUS HEAP_lfh_allocate( HANDLE std_heap, ULONG flags, SIZE_T size, void **out ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+NTSTATUS HEAP_lfh_free( HANDLE std_heap, ULONG flags, void *ptr ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+NTSTATUS HEAP_lfh_reallocate( HANDLE std_heap, ULONG flags, void *ptr, SIZE_T size, void **out ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+NTSTATUS HEAP_lfh_get_allocated_size( HANDLE std_heap, ULONG flags, const void *ptr, SIZE_T *out ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+NTSTATUS HEAP_lfh_validate( HANDLE std_heap, ULONG flags, const void *ptr ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+void HEAP_lfh_notify_thread_destroy(BOOLEAN last) -+{ -+} -+ -+void HEAP_lfh_set_debug_flags(ULONG flags) -+{ -+} -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index 6dadf3a74a5..a6d42a1628e 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -105,12 +105,24 @@ static inline TEB64 *NtCurrentTeb64(void) { return NULL; } - static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiBatchCount; } - #endif - -+#define HEAP_STD 0 -+#define HEAP_LAL 1 -+#define HEAP_LFH 2 -+ - NTSTATUS HEAP_std_allocate( HANDLE heap, ULONG flags, SIZE_T size, void **out ); - NTSTATUS HEAP_std_free( HANDLE heap, ULONG flags, void *ptr ); - NTSTATUS HEAP_std_reallocate( HANDLE heap, ULONG flags, void *ptr, SIZE_T size, void **out ); - NTSTATUS HEAP_std_get_allocated_size( HANDLE heap, ULONG flags, const void *ptr, SIZE_T *out ); - -+NTSTATUS HEAP_lfh_allocate( HANDLE std_heap, ULONG flags, SIZE_T size, void **out ); -+NTSTATUS HEAP_lfh_free( HANDLE std_heap, ULONG flags, void *ptr ); -+NTSTATUS HEAP_lfh_reallocate( HANDLE std_heap, ULONG flags, void *ptr, SIZE_T size, void **out ); -+NTSTATUS HEAP_lfh_get_allocated_size( HANDLE std_heap, ULONG flags, const void *ptr, SIZE_T *out ); -+NTSTATUS HEAP_lfh_validate( HANDLE std_heap, ULONG flags, const void *ptr ); -+ - void HEAP_notify_thread_destroy( BOOLEAN last ); -+void HEAP_lfh_notify_thread_destroy( BOOLEAN last ); -+void HEAP_lfh_set_debug_flags( ULONG flags ); - - #define HASH_STRING_ALGORITHM_DEFAULT 0 - #define HASH_STRING_ALGORITHM_X65599 1 - -From a1c217d99a5de73999f9383ccebd567265eeb7b2 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 5 May 2020 14:24:35 +0200 -Subject: [PATCH 11/18] ntdll: Better implement RtlSetHeapInformation. - -And set extended_type heap field when HeapCompatibilityInformation is -used. ---- - dlls/kernel32/tests/heap.c | 23 +++++++++++++++++++++-- - dlls/ntdll/heap.c | 36 ++++++++++++++++++++++++++++++++++-- - include/winnt.h | 3 ++- - 3 files changed, 57 insertions(+), 5 deletions(-) - -diff --git a/dlls/kernel32/tests/heap.c b/dlls/kernel32/tests/heap.c -index db96fb010b4..9e613995e39 100644 ---- a/dlls/kernel32/tests/heap.c -+++ b/dlls/kernel32/tests/heap.c -@@ -644,7 +644,28 @@ static void test_HeapCreate(void) - "HeapQueryInformation failed\n"); - trace("HeapQueryInformation returned %d\n", hci); - -+ hci = 0; -+ ok(pHeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0), -+ "HeapSetInformation(HeapEnableTerminationOnCorruption) failed\n"); -+ ok(pHeapSetInformation((HANDLE)0xdeadbeef, HeapEnableTerminationOnCorruption, &hci, sizeof(hci)), -+ "HeapSetInformation(HeapEnableTerminationOnCorruption) succeeded\n"); -+ ok(pHeapSetInformation(heap, HeapEnableTerminationOnCorruption, &hci, sizeof(hci)), -+ "HeapSetInformation(HeapEnableTerminationOnCorruption) succeeded\n"); -+ ok(pHeapSetInformation(heap, HeapEnableTerminationOnCorruption, NULL, 0), -+ "HeapSetInformation(HeapEnableTerminationOnCorruption) failed\n"); -+ ok(!pHeapQueryInformation(heap, HeapEnableTerminationOnCorruption, NULL, 0, &size), -+ "HeapQueryInformation(HeapEnableTerminationOnCorruption) succeeded\n"); -+ - hci = 2; -+ SetLastError(0xdeadbeef); -+ ok(!pHeapSetInformation(NULL, HeapCompatibilityInformation, NULL, 0), -+ "HeapSetInformation succeeded\n"); -+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, -+ "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); -+ ok(!pHeapSetInformation(NULL, HeapCompatibilityInformation, &hci, 2), -+ "HeapSetInformation succeeded\n"); -+ ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, -+ "expected ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError()); - ok(pHeapSetInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci)), - "HeapSetInformation failed\n"); - ok(pHeapQueryInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci), &size), -@@ -653,10 +674,8 @@ static void test_HeapCreate(void) - - hci = 1; - SetLastError(0xdeadbeef); -- todo_wine - ok(!pHeapSetInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci)), - "HeapSetInformation succeeded\n"); -- todo_wine - ok(GetLastError() == ERROR_GEN_FAILURE, - "expected ERROR_GEN_FAILURE, got %u\n", GetLastError()); - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index e4ed51ef522..bb31f60b9d2 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -2316,8 +2316,40 @@ NTSTATUS WINAPI RtlQueryHeapInformation( HANDLE heap, HEAP_INFORMATION_CLASS inf - */ - NTSTATUS WINAPI RtlSetHeapInformation( HANDLE heap, HEAP_INFORMATION_CLASS info_class, PVOID info, SIZE_T size) - { -- FIXME("%p %d %p %ld stub\n", heap, info_class, info, size); -- return STATUS_SUCCESS; -+ TRACE("%p %d %p %ld stub\n", heap, info_class, info, size); -+ -+ switch (info_class) -+ { -+ case HeapEnableTerminationOnCorruption: -+ FIXME("unimplemented HeapEnableTerminationOnCorruption\n"); -+ return STATUS_SUCCESS; -+ -+ case HeapCompatibilityInformation: -+ { -+ HEAP *heapPtr; -+ heapPtr = HEAP_GetPtr( heap ); -+ -+ if (size < sizeof(ULONG)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ if (heapPtr->extended_type != HEAP_STD) -+ return STATUS_UNSUCCESSFUL; -+ -+ if (*(ULONG *)info != HEAP_STD && -+ *(ULONG *)info != HEAP_LFH) -+ { -+ FIXME("unimplemented HeapCompatibilityInformation %d\n", *(ULONG *)info); -+ return STATUS_SUCCESS; -+ } -+ -+ heapPtr->extended_type = *(ULONG *)info; -+ return STATUS_SUCCESS; -+ } -+ -+ default: -+ FIXME("Unknown heap information class %u\n", info_class); -+ return STATUS_INVALID_INFO_CLASS; -+ } - } - - void HEAP_notify_thread_destroy( BOOLEAN last ) -diff --git a/include/winnt.h b/include/winnt.h -index b83f588a16d..424651ea673 100644 ---- a/include/winnt.h -+++ b/include/winnt.h -@@ -921,7 +921,8 @@ NTSYSAPI WORD WINAPI RtlQueryDepthSList(PSLIST_HEADER); - #define HEAP_SHARED 0x04000000 - - typedef enum _HEAP_INFORMATION_CLASS { -- HeapCompatibilityInformation, -+ HeapCompatibilityInformation = 0, -+ HeapEnableTerminationOnCorruption = 1, - } HEAP_INFORMATION_CLASS; - - /* Processor feature flags. */ - -From a39b771c377b731568883a503ca7255f49c391e6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 3 Feb 2020 13:25:59 +0100 -Subject: [PATCH 12/18] ntdll: Move undocumented flags to ntdll_misc.h. - ---- - dlls/ntdll/heap.c | 6 ------ - dlls/ntdll/ntdll_misc.h | 6 ++++++ - 2 files changed, 6 insertions(+), 6 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index bb31f60b9d2..1e0408c028c 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -172,12 +172,6 @@ typedef struct tagHEAP - #define COMMIT_MASK 0xffff /* bitmask for commit/decommit granularity */ - #define MAX_FREE_PENDING 1024 /* max number of free requests to delay */ - --/* some undocumented flags (names are made up) */ --#define HEAP_PAGE_ALLOCS 0x01000000 --#define HEAP_VALIDATE 0x10000000 --#define HEAP_VALIDATE_ALL 0x20000000 --#define HEAP_VALIDATE_PARAMS 0x40000000 -- - static HEAP *processHeap; /* main process heap */ - - static BOOL HEAP_IsRealArena( HEAP *heapPtr, DWORD flags, LPCVOID block, BOOL quiet ); -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index a6d42a1628e..15b102fb75e 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -109,6 +109,12 @@ static inline TEB64 *NtCurrentTeb64(void) { return (TEB64 *)NtCurrentTeb()->GdiB - #define HEAP_LAL 1 - #define HEAP_LFH 2 - -+/* some undocumented flags (names are made up) */ -+#define HEAP_PAGE_ALLOCS 0x01000000 -+#define HEAP_VALIDATE 0x10000000 -+#define HEAP_VALIDATE_ALL 0x20000000 -+#define HEAP_VALIDATE_PARAMS 0x40000000 -+ - NTSTATUS HEAP_std_allocate( HANDLE heap, ULONG flags, SIZE_T size, void **out ); - NTSTATUS HEAP_std_free( HANDLE heap, ULONG flags, void *ptr ); - NTSTATUS HEAP_std_reallocate( HANDLE heap, ULONG flags, void *ptr, SIZE_T size, void **out ); - -From 4ef6a513dbf9286f8e7b018c945e0bf5e74195b7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Mar 2021 18:41:16 +0100 -Subject: [PATCH 13/18] ntdll: Implement Low Fragmentation Heap. - -This is a high performance multithreaded heap implementation that tries -to minimize memory fragmentation as well. - -It takes inspiration from rpmalloc / tcmalloc and other thread-local -heap implementations, while avoiding the complexity of a cache. - -The low fragmentation part is achieved by using two layers of pools, or -arenas, classified by block size: - -* The first, coarse grained, pools are called "large" arenas, and are - allocated directly by mapping 4MiB of virtual memory for each pool, - which is then split into blocks of fixed size. The large arena classes - are configured to support block sizes in a range from (64KiB - hs) up - to (2MiB - hs), increasing by 64KiB steps, where hs is the arena - header size. - -* The second pool layer, called "small" and "medium" arenas is built on - top of the first, using the exact same mechanism (and code). Each pool - is allocated by acquiring a block of (64KiB - hs) size from an arena - of the first "large" class. The "small" arena classes are configured - for block sizes in a range from 32 to 2048 bytes, increasing by 32B - steps. The "medium" arena classes are configured for block sizes in a - range from 2048 bytes up to ((64KiB - hs) - hs) / 2, increasing by - 512B steps. - -Any memory allocation that is bigger than what "large" arenas can -provide will be directly mapped from virtual memory. - -The multithreaded part is achieved by keeping thread local heap -structures to hold the currently allocated classified arenas: - -* Whenever a thread needs it, a new thread local heap will be acquired - from a global orphan list - using an interlocked singly linked list of - unused heaps - or allocated from virtual memory. Whenever a thread - terminates, it will release its thread local heap to the global orphan - list. - -* Every alloc is done by using the current thread heap, and by - allocating a new block from its arenas. The virtual memory mapping - that may eventually be called is already thread safe and does not - require additional locking. - -* Every free is deferred to the thread that allocated the block, by - using an interlocked singly linked list. - -* Every time a thread allocates a new block, it will first cleanup its - deferred free block list. - -The thread local heaps may not be always associated with an live -thread, so this means that deferred blocks may have to wait for the -orphan heap to be adopted by a new thread before they are actually -released. ---- - dlls/ntdll/heap_lfh.c | 1095 +++++++++++++++++++++++++++++++- - dlls/ntdll/unix/unix_private.h | 1 + - 2 files changed, 1086 insertions(+), 10 deletions(-) - -diff --git a/dlls/ntdll/heap_lfh.c b/dlls/ntdll/heap_lfh.c -index 0c324472e32..8c982f91ea0 100644 ---- a/dlls/ntdll/heap_lfh.c -+++ b/dlls/ntdll/heap_lfh.c -@@ -21,37 +21,1112 @@ - #include "ntstatus.h" - #define WIN32_NO_STATUS - -+#include "wine/list.h" -+#include "wine/debug.h" -+ - #include "ntdll_misc.h" - --NTSTATUS HEAP_lfh_allocate( HANDLE std_heap, ULONG flags, SIZE_T size, void **out ) -+WINE_DEFAULT_DEBUG_CHANNEL(heap); -+ -+typedef struct LFH_ptr LFH_ptr; -+typedef struct LFH_block LFH_block; -+typedef enum LFH_block_type LFH_block_type; -+typedef struct LFH_arena LFH_arena; -+typedef struct LFH_class LFH_class; -+typedef struct LFH_heap LFH_heap; -+typedef struct LFH_slist LFH_slist; -+ -+#define ARENA_HEADER_SIZE (sizeof(LFH_arena)) -+ -+#define LARGE_ARENA_SIZE 0x400000 /* 4MiB */ -+#define LARGE_ARENA_MASK (LARGE_ARENA_SIZE - 1) -+ -+#define BLOCK_ARENA_SIZE 0x10000 /* 64kiB */ -+#define BLOCK_ARENA_MASK (BLOCK_ARENA_SIZE - 1) -+ -+#define SMALL_CLASS_STEP 0x20 -+#define SMALL_CLASS_MASK (SMALL_CLASS_STEP - 1) -+#define SMALL_CLASS_MIN_SIZE SMALL_CLASS_STEP -+#define SMALL_CLASS_MAX_SIZE 0x800 -+#define SMALL_CLASS_COUNT ((SMALL_CLASS_MAX_SIZE - SMALL_CLASS_MIN_SIZE) / SMALL_CLASS_STEP + 1) -+#define SMALL_CLASS_FIRST 0 -+#define SMALL_CLASS_LAST (SMALL_CLASS_FIRST + SMALL_CLASS_COUNT - 1) -+ -+#define MEDIUM_CLASS_STEP (16 * SMALL_CLASS_STEP) -+#define MEDIUM_CLASS_MASK (MEDIUM_CLASS_STEP - 1) -+#define MEDIUM_CLASS_MIN_SIZE SMALL_CLASS_MAX_SIZE -+#define MEDIUM_CLASS_MAX_SIZE ((BLOCK_ARENA_SIZE - ARENA_HEADER_SIZE - ARENA_HEADER_SIZE) / 2) -+#define MEDIUM_CLASS_COUNT ((MEDIUM_CLASS_MAX_SIZE - MEDIUM_CLASS_MIN_SIZE + MEDIUM_CLASS_MASK) / MEDIUM_CLASS_STEP + 1) -+#define MEDIUM_CLASS_FIRST (SMALL_CLASS_LAST + 1) -+#define MEDIUM_CLASS_LAST (MEDIUM_CLASS_FIRST + MEDIUM_CLASS_COUNT - 1) -+ -+#define LARGE_CLASS_STEP BLOCK_ARENA_SIZE -+#define LARGE_CLASS_MASK (LARGE_CLASS_STEP - 1) -+#define LARGE_CLASS_MIN_SIZE (BLOCK_ARENA_SIZE - ARENA_HEADER_SIZE) -+#define LARGE_CLASS_MAX_SIZE (LARGE_ARENA_SIZE / 2 - ARENA_HEADER_SIZE) /* we need an arena header for every large block */ -+#define LARGE_CLASS_COUNT ((LARGE_CLASS_MAX_SIZE - LARGE_CLASS_MIN_SIZE) / LARGE_CLASS_STEP + 1) -+#define LARGE_CLASS_FIRST 0 -+#define LARGE_CLASS_LAST (LARGE_CLASS_FIRST + LARGE_CLASS_COUNT - 1) -+ -+#define TOTAL_BLOCK_CLASS_COUNT (MEDIUM_CLASS_LAST + 1) -+#define TOTAL_LARGE_CLASS_COUNT (LARGE_CLASS_LAST + 1) -+ -+struct LFH_slist -+{ -+ LFH_slist *next; -+}; -+ -+static inline void LFH_slist_push(LFH_slist **list, LFH_slist *entry) -+{ -+ /* There will be no ABA issue here, other threads can only replace -+ * list->next with a different entry, or NULL. */ -+ entry->next = __atomic_load_n(list, __ATOMIC_RELAXED); -+ while (!__atomic_compare_exchange_n(list, &entry->next, entry, 0, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)); -+} -+ -+static inline LFH_slist *LFH_slist_flush(LFH_slist **list) -+{ -+ if (!__atomic_load_n(list, __ATOMIC_RELAXED)) return NULL; -+ return __atomic_exchange_n(list, NULL, __ATOMIC_ACQUIRE); -+} -+ -+/* be sure to keep these different from ARENA_INUSE magic */ -+enum LFH_block_type -+{ -+ LFH_block_type_used = 0xa55a5aa5a55a5aa5ul, -+ LFH_block_type_free = 0xc33c3cc3c33c3cc3ul, -+}; -+ -+struct DECLSPEC_ALIGN(16) LFH_block -+{ -+ union -+ { -+ ssize_t next_free; -+ LFH_slist entry_defer; -+ size_t alloc_size; -+ }; -+ -+ LFH_block_type type; -+}; -+ -+C_ASSERT(sizeof(LFH_block) == 0x10); -+C_ASSERT(offsetof(LFH_block, entry_defer) == 0); -+ -+struct DECLSPEC_ALIGN(16) LFH_arena -+{ -+ ssize_t next_free; -+ LFH_arena *class_entry; -+ -+ union -+ { -+ LFH_arena *parent; -+ LFH_class *class; -+ }; -+ -+ union -+ { -+ size_t huge_size; -+ size_t used_count; -+ }; -+}; -+ -+#ifdef _WIN64 -+C_ASSERT(sizeof(LFH_arena) == 0x20); -+#else -+C_ASSERT(sizeof(LFH_arena) == 0x10); -+#endif -+ -+struct LFH_class -+{ -+ LFH_arena *next; -+ size_t size; -+}; -+ -+struct LFH_heap -+{ -+ LFH_slist *list_defer; -+ LFH_arena *cached_large_arena; -+ -+ LFH_class block_class[TOTAL_BLOCK_CLASS_COUNT]; -+ LFH_class large_class[TOTAL_LARGE_CLASS_COUNT]; -+ -+ SLIST_ENTRY entry_orphan; -+#ifdef _WIN64 -+ void *pad[0xc2]; -+#else -+ void *pad[0xc3]; -+#endif -+}; -+ -+C_ASSERT(TOTAL_BLOCK_CLASS_COUNT == 0x7d); -+C_ASSERT(TOTAL_LARGE_CLASS_COUNT == 0x20); -+ -+/* arena->class/arena->parent pointer low bits are used to discriminate between the two */ -+C_ASSERT(offsetof(LFH_heap, block_class[0]) > 0); -+C_ASSERT(offsetof(LFH_heap, large_class[TOTAL_LARGE_CLASS_COUNT]) < BLOCK_ARENA_SIZE); -+ -+/* helpers to retrieve parent arena from a child, or class pointer from a large or block arena */ -+static inline LFH_arena *LFH_parent_from_arena(const LFH_arena *arena) -+{ -+ if (!arena->parent) return (LFH_arena *)arena; -+ if (!((UINT_PTR)(arena)->parent & BLOCK_ARENA_MASK)) return arena->parent; -+ return (LFH_arena *)arena; -+} -+ -+static inline LFH_class *LFH_class_from_arena(const LFH_arena *arena) -+{ -+ const LFH_arena *parent = LFH_parent_from_arena(arena); -+ if ((UINT_PTR)parent->class & BLOCK_ARENA_MASK) return parent->class; -+ return NULL; -+} -+ -+/* make sure its aligns to power of two so we can mask class pointers in LFH_heap_from_arena */ -+#ifdef _WIN64 -+C_ASSERT(sizeof(LFH_heap) == 0x1000); -+#else -+C_ASSERT(sizeof(LFH_heap) == 0x800); -+#endif -+ -+/* helper to retrieve the heap from an arena, using its class pointer */ -+static inline LFH_heap *LFH_heap_from_arena(const LFH_arena *arena) -+{ -+ LFH_class *class = LFH_class_from_arena(arena); -+ return (LFH_heap *)((UINT_PTR)class & ~(sizeof(LFH_heap) - 1)); -+} -+ -+/* helpers to retrieve block pointers to the containing block or large (maybe child) arena */ -+static inline LFH_arena *LFH_large_arena_from_block(const LFH_block *block) -+{ -+ return (LFH_arena *)((UINT_PTR)block & ~BLOCK_ARENA_MASK); -+} -+ -+static inline LFH_arena *LFH_block_arena_from_block(const LFH_block *block) -+{ -+ return LFH_large_arena_from_block(block) + 1; -+} -+ -+static inline LFH_arena *LFH_arena_from_block(const LFH_block *block) -+{ -+ LFH_arena *block_arena = LFH_block_arena_from_block(block); -+ if (block_arena == (LFH_arena *)block) return LFH_large_arena_from_block(block); -+ return block_arena; -+} -+ -+/* helpers to translate between data pointer and LFH_block header */ -+static inline LFH_block *LFH_block_from_ptr(const LFH_ptr *ptr) -+{ -+ return ((LFH_block *)ptr) - 1; -+} -+ -+static inline void *LFH_ptr_from_block(const LFH_block *block) -+{ -+ return (LFH_ptr *)(block + 1); -+} -+ -+static inline size_t LFH_block_get_class_size(const LFH_block *block) -+{ -+ const LFH_arena *arena = LFH_arena_from_block(block); -+ const LFH_class *class = LFH_class_from_arena(arena); -+ if (class) return class->size; -+ return arena->huge_size; -+} -+ -+static inline size_t LFH_block_get_alloc_size(const LFH_block *block, ULONG flags) -+{ -+ return block->alloc_size; -+} -+ -+static inline size_t LFH_get_class_size(ULONG flags, size_t size) -+{ -+ size_t extra = sizeof(LFH_block) + ((flags & HEAP_TAIL_CHECKING_ENABLED) ? 16 : 0); -+ if (size + extra < size) return ~(size_t)0; -+ return size + extra; -+} -+ -+static inline void *LFH_memory_allocate(size_t size) -+{ -+ void *addr = NULL; -+ SIZE_T alloc_size = size; -+ -+ if (NtAllocateVirtualMemory(NtCurrentProcess(), (void **)&addr, 0, &alloc_size, -+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) -+ return NULL; -+ -+ return addr; -+} -+ -+static inline BOOLEAN LFH_memory_deallocate(void *addr, size_t size) -+{ -+ SIZE_T release_size = 0; -+ -+ if (NtFreeVirtualMemory(NtCurrentProcess(), &addr, &release_size, MEM_RELEASE)) -+ return FALSE; -+ -+ return TRUE; -+} -+ -+static inline LFH_block *LFH_arena_get_block(const LFH_arena *arena, size_t offset) -+{ -+ return (LFH_block *)((UINT_PTR)arena + offset); -+} -+ -+static inline void LFH_arena_push_block(LFH_arena *arena, LFH_block *block) -+{ -+ block->type = LFH_block_type_free; -+ block->next_free = arena->next_free; -+ arena->next_free = (UINT_PTR)block - (UINT_PTR)arena; -+ arena->used_count--; -+} -+ -+static inline LFH_block *LFH_arena_pop_block(LFH_arena *arena) -+{ -+ if (arena->next_free > 0) -+ { -+ LFH_block *block = LFH_arena_get_block(arena, arena->next_free); -+ arena->next_free = block->next_free; -+ arena->used_count++; -+ return block; -+ } -+ else -+ { -+ LFH_arena *child, *large_arena = LFH_large_arena_from_block((LFH_block *)arena); -+ LFH_class *class = LFH_class_from_arena(arena); -+ LFH_block *block = LFH_arena_get_block(arena, -arena->next_free); -+ ssize_t extra = 0, limit; -+ -+ if (arena == large_arena) -+ { -+ extra = ARENA_HEADER_SIZE; -+ limit = LARGE_ARENA_SIZE; -+ child = LFH_large_arena_from_block(block); -+ if (arena != child) child->parent = arena; -+ } -+ else limit = LFH_class_from_arena(large_arena)->size; -+ -+ arena->next_free -= class->size + extra; -+ if (-arena->next_free > limit - class->size) -+ arena->next_free = 0; -+ -+ arena->used_count++; -+ return block; -+ } -+} -+ -+static inline int LFH_arena_is_empty(LFH_arena *arena) -+{ -+ return arena->next_free == 0; -+} -+ -+static inline int LFH_arena_is_used(LFH_arena *arena) - { -- return STATUS_NOT_IMPLEMENTED; -+ return arena->used_count > 0; - } - --NTSTATUS HEAP_lfh_free( HANDLE std_heap, ULONG flags, void *ptr ) -+static inline int LFH_class_is_block(LFH_heap *heap, LFH_class *class) - { -- return STATUS_NOT_IMPLEMENTED; -+ return class >= heap->block_class && class < (heap->block_class + TOTAL_BLOCK_CLASS_COUNT); - } - --NTSTATUS HEAP_lfh_reallocate( HANDLE std_heap, ULONG flags, void *ptr, SIZE_T size, void **out ) -+static void LFH_class_initialize(LFH_heap *heap, LFH_class *class, size_t index) - { -- return STATUS_NOT_IMPLEMENTED; -+ class->next = NULL; -+ -+ if (LFH_class_is_block(heap, class)) -+ { -+ if (index <= SMALL_CLASS_LAST) -+ class->size = min(SMALL_CLASS_MIN_SIZE + SMALL_CLASS_STEP * (index - SMALL_CLASS_FIRST), SMALL_CLASS_MAX_SIZE); -+ else -+ class->size = min(MEDIUM_CLASS_MIN_SIZE + MEDIUM_CLASS_STEP * (index - MEDIUM_CLASS_FIRST), MEDIUM_CLASS_MAX_SIZE); -+ } -+ else -+ { -+ class->size = min(LARGE_CLASS_MIN_SIZE + LARGE_CLASS_STEP * (index - LARGE_CLASS_FIRST), LARGE_CLASS_MAX_SIZE); -+ } -+} -+ -+static inline LFH_arena *LFH_class_pop_arena(LFH_class *class) -+{ -+ LFH_arena *arena = class->next; -+ if (!arena) return NULL; -+ class->next = arena->class_entry; -+ return arena; - } - --NTSTATUS HEAP_lfh_get_allocated_size( HANDLE std_heap, ULONG flags, const void *ptr, SIZE_T *out ) -+static inline void LFH_class_remove_arena(LFH_class *class, LFH_arena *arena) - { -- return STATUS_NOT_IMPLEMENTED; -+ LFH_arena **next = &class->next; -+ while (*next != arena) next = &(*next)->class_entry; -+ *next = arena->class_entry; - } - --NTSTATUS HEAP_lfh_validate( HANDLE std_heap, ULONG flags, const void *ptr ) -+static inline LFH_arena *LFH_class_peek_arena(LFH_class *class) - { -- return STATUS_NOT_IMPLEMENTED; -+ return class->next; -+} -+ -+static inline void LFH_class_push_arena(LFH_class *class, LFH_arena *arena) -+{ -+ arena->class_entry = class->next; -+ class->next = arena; -+} -+ -+static inline LFH_class *LFH_heap_get_class(LFH_heap *heap, size_t size) -+{ -+ if (size == 0) -+ return &heap->block_class[0]; -+ else if (size <= SMALL_CLASS_MAX_SIZE) -+ return &heap->block_class[SMALL_CLASS_FIRST + (size + SMALL_CLASS_MASK - SMALL_CLASS_MIN_SIZE) / SMALL_CLASS_STEP]; -+ else if (size <= MEDIUM_CLASS_MAX_SIZE) -+ return &heap->block_class[MEDIUM_CLASS_FIRST + (size + MEDIUM_CLASS_MASK - MEDIUM_CLASS_MIN_SIZE) / MEDIUM_CLASS_STEP]; -+ else if (size <= LARGE_CLASS_MAX_SIZE) -+ return &heap->large_class[LARGE_CLASS_FIRST + (size + LARGE_CLASS_MASK - LARGE_CLASS_MIN_SIZE) / LARGE_CLASS_STEP]; -+ else -+ return NULL; -+} -+ -+static void LFH_arena_initialize(LFH_heap *heap, LFH_class *class, LFH_arena *arena, size_t huge_size) -+{ -+ arena->class = class; -+ arena->next_free = -ARENA_HEADER_SIZE; -+ -+ if (class == NULL) -+ arena->huge_size = huge_size; -+ else -+ arena->used_count = 0; -+} -+ -+static LFH_arena *LFH_acquire_arena(LFH_heap *heap, LFH_class *class); -+static BOOLEAN LFH_release_arena(LFH_heap *heap, LFH_arena *arena); -+ -+static inline LFH_block *LFH_allocate_block(LFH_heap *heap, LFH_class *class, LFH_arena *arena); -+static inline BOOLEAN LFH_deallocate_block(LFH_heap *heap, LFH_arena *arena, LFH_block *block); -+ -+static inline BOOLEAN LFH_deallocate_deferred_blocks(LFH_heap *heap) -+{ -+ LFH_slist *entry = LFH_slist_flush(&heap->list_defer); -+ -+ while (entry) -+ { -+ LFH_block *block = LIST_ENTRY(entry, LFH_block, entry_defer); -+ entry = entry->next; -+ -+ if (!LFH_deallocate_block(heap, LFH_arena_from_block(block), block)) -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static inline void LFH_deallocated_cached_arenas(LFH_heap *heap) -+{ -+ if (!heap->cached_large_arena) return; -+ LFH_memory_deallocate(heap->cached_large_arena, LARGE_ARENA_SIZE); -+ heap->cached_large_arena = NULL; -+} -+ -+static inline size_t LFH_huge_alloc_size(size_t size) -+{ -+ return (ARENA_HEADER_SIZE + size + BLOCK_ARENA_MASK) & ~BLOCK_ARENA_MASK; -+} -+ -+static inline LFH_arena *LFH_allocate_huge_arena(LFH_heap *heap, size_t size) -+{ -+ LFH_arena *arena; -+ size_t alloc_size = LFH_huge_alloc_size(size); -+ if (alloc_size < size) return NULL; -+ -+ if ((arena = LFH_memory_allocate(alloc_size))) -+ LFH_arena_initialize(heap, NULL, arena, size); -+ -+ return arena; -+} -+ -+static inline LFH_arena *LFH_allocate_large_arena(LFH_heap *heap, LFH_class *class) -+{ -+ LFH_arena *arena; -+ -+ if ((arena = heap->cached_large_arena) || -+ (arena = LFH_memory_allocate(LARGE_ARENA_SIZE))) -+ { -+ heap->cached_large_arena = NULL; -+ LFH_arena_initialize(heap, class, arena, 0); -+ LFH_class_push_arena(class, arena); -+ } -+ -+ return arena; -+} -+ -+static inline LFH_arena *LFH_allocate_block_arena(LFH_heap *heap, LFH_class *large_class, LFH_class *block_class) -+{ -+ LFH_arena *large_arena; -+ LFH_arena *arena = NULL; -+ -+ if ((large_arena = LFH_acquire_arena(heap, large_class))) -+ { -+ arena = (LFH_arena *)LFH_allocate_block(heap, large_class, large_arena); -+ LFH_arena_initialize(heap, block_class, arena, 0); -+ LFH_class_push_arena(block_class, arena); -+ } -+ -+ return arena; -+} -+ -+static inline LFH_arena *LFH_acquire_arena(LFH_heap *heap, LFH_class *class) -+{ -+ LFH_arena *arena; -+ -+ if (!(arena = LFH_class_peek_arena(class))) -+ { -+ if (LFH_class_is_block(heap, class)) -+ arena = LFH_allocate_block_arena(heap, &heap->large_class[0], class); -+ else -+ arena = LFH_allocate_large_arena(heap, class); -+ } -+ -+ return arena; -+} -+ -+static inline BOOLEAN LFH_release_arena(LFH_heap *heap, LFH_arena *arena) -+{ -+ LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); -+ if (arena == large_arena && !heap->cached_large_arena) -+ { -+ heap->cached_large_arena = arena; -+ return TRUE; -+ } -+ else if (arena == large_arena) -+ return LFH_memory_deallocate(arena, LARGE_ARENA_SIZE); -+ else -+ return LFH_deallocate_block(heap, large_arena, (LFH_block *)arena); -+}; -+ -+static inline LFH_block *LFH_allocate_block(LFH_heap *heap, LFH_class *class, LFH_arena *arena) -+{ -+ LFH_block *block = LFH_arena_pop_block(arena); -+ if (LFH_arena_is_empty(arena)) -+ LFH_class_pop_arena(class); -+ return block; -+} -+ -+static inline BOOLEAN LFH_deallocate_block(LFH_heap *heap, LFH_arena *arena, LFH_block *block) -+{ -+ LFH_class *class = LFH_class_from_arena(arena); -+ -+ arena = LFH_parent_from_arena(arena); -+ if (LFH_arena_is_empty(arena)) -+ LFH_class_push_arena(class, arena); -+ -+ LFH_arena_push_block(arena, block); -+ if (LFH_arena_is_used(arena)) -+ return TRUE; -+ -+ LFH_class_remove_arena(class, arena); -+ return LFH_release_arena(heap, arena); -+} -+ -+static void LFH_heap_initialize(LFH_heap *heap) -+{ -+ size_t i; -+ -+ for (i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) -+ LFH_class_initialize(heap, &heap->large_class[i], i); -+ for (i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) -+ LFH_class_initialize(heap, &heap->block_class[i], i); -+ -+ heap->list_defer = NULL; -+ heap->cached_large_arena = NULL; -+} -+ -+static SLIST_HEADER *LFH_orphan_list(void) -+{ -+ static SLIST_HEADER *header; -+ SLIST_HEADER *ptr, *expected = NULL; -+ LFH_heap *tmp; -+ -+ C_ASSERT(sizeof(LFH_heap) >= sizeof(SLIST_HEADER)); -+ -+ if ((ptr = __atomic_load_n(&header, __ATOMIC_RELAXED))) -+ return ptr; -+ -+ if (!(ptr = LFH_memory_allocate(BLOCK_ARENA_SIZE))) -+ return NULL; -+ -+ RtlInitializeSListHead(ptr); -+ for (tmp = (LFH_heap *)ptr + 1; tmp < (LFH_heap *)ptr + BLOCK_ARENA_SIZE / sizeof(*tmp); tmp++) -+ { -+ LFH_heap_initialize(tmp); -+ RtlInterlockedPushEntrySList(ptr, &tmp->entry_orphan); -+ } -+ -+ if (__atomic_compare_exchange_n(&header, &expected, ptr, 0, __ATOMIC_RELEASE, __ATOMIC_ACQUIRE)) -+ return ptr; -+ -+ LFH_memory_deallocate(ptr, BLOCK_ARENA_SIZE); -+ return expected; -+} -+ -+static void LFH_heap_finalize(LFH_heap *heap) -+{ -+ LFH_arena *arena; -+ -+ LFH_deallocate_deferred_blocks(heap); -+ -+ for (size_t i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) -+ { -+ while ((arena = LFH_class_pop_arena(&heap->block_class[i]))) -+ { -+ WARN("block arena %p still has used blocks\n", arena); -+ LFH_release_arena(heap, arena); -+ } -+ } -+ -+ for (size_t i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) -+ { -+ while ((arena = LFH_class_pop_arena(&heap->large_class[i]))) -+ { -+ WARN("large arena %p still has used blocks\n", arena); -+ LFH_memory_deallocate(arena, LARGE_ARENA_SIZE); -+ } -+ } -+ -+ LFH_deallocated_cached_arenas(heap); -+} -+ -+static LFH_heap *LFH_heap_allocate(void) -+{ -+ SLIST_HEADER *list_orphan = LFH_orphan_list(); -+ LFH_heap *heap, *tmp; -+ -+ heap = LFH_memory_allocate(BLOCK_ARENA_SIZE); -+ if (!heap) -+ return NULL; -+ -+ for (tmp = heap + 1; tmp < heap + BLOCK_ARENA_SIZE / sizeof(*tmp); tmp++) -+ { -+ LFH_heap_initialize(tmp); -+ RtlInterlockedPushEntrySList(list_orphan, &tmp->entry_orphan); -+ } -+ -+ LFH_heap_initialize(heap); -+ return heap; -+} -+ -+static LFH_heap *LFH_create_thread_heap(void) -+{ -+ SLIST_ENTRY *entry; -+ LFH_heap *heap; -+ -+ if ((entry = RtlInterlockedPopEntrySList(LFH_orphan_list()))) -+ heap = LIST_ENTRY(entry, LFH_heap, entry_orphan); -+ else -+ heap = LFH_heap_allocate(); -+ -+ return (NtCurrentTeb()->Reserved5[2] = heap); -+} -+ -+static inline LFH_heap *LFH_thread_heap(BOOL create) -+{ -+ LFH_heap *heap = (LFH_heap *)NtCurrentTeb()->Reserved5[2]; -+ if (!heap && create) return LFH_create_thread_heap(); -+ return heap; -+} -+ -+static void LFH_dump_arena(LFH_heap *heap, LFH_class *class, LFH_arena *arena) -+{ -+ LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); -+ LFH_arena *block_arena = LFH_block_arena_from_block((LFH_block *)arena); -+ -+ if (arena == block_arena) -+ WARN(" block arena: %p-%p", arena, (void *)((UINT_PTR)large_arena + BLOCK_ARENA_SIZE - 1)); -+ else if (arena == large_arena) -+ WARN(" large arena: %p-%p", arena, (void *)((UINT_PTR)large_arena + LARGE_ARENA_SIZE - 1)); -+ -+ WARN(" heap: %p class: %p parent: %p free: %Id used: %Id\n", -+ LFH_heap_from_arena(arena), LFH_class_from_arena(arena), LFH_parent_from_arena(arena), arena->next_free, arena->used_count); -+} -+ -+static void LFH_dump_class(LFH_heap *heap, LFH_class *class) -+{ -+ LFH_arena *arena = class->next; -+ if (!arena) return; -+ -+ if (LFH_class_is_block(heap, class)) -+ WARN(" block class: %p size: %Ix\n", class, class->size); -+ else -+ WARN(" large class: %p size: %Ix\n", class, class->size); -+ -+ while (arena) -+ { -+ LFH_dump_arena(heap, class, arena); -+ arena = arena->class_entry; -+ } -+} -+ -+static void LFH_dump_heap(LFH_heap *heap) -+{ -+ size_t i; -+ -+ WARN("heap: %p\n", heap); -+ -+ for (i = 0; i < TOTAL_BLOCK_CLASS_COUNT; ++i) -+ LFH_dump_class(heap, &heap->block_class[i]); -+ -+ for (i = 0; i < TOTAL_LARGE_CLASS_COUNT; ++i) -+ LFH_dump_class(heap, &heap->large_class[i]); -+} -+ -+static BOOLEAN LFH_validate_arena(ULONG flags, const LFH_arena *arena); -+static BOOLEAN LFH_validate_heap(ULONG flags, const LFH_heap *heap); -+ -+static inline BOOLEAN LFH_validate_block(ULONG flags, const LFH_block *block) -+{ -+ const LFH_arena *arena = LFH_arena_from_block(block); -+ const LFH_arena *large_arena = LFH_large_arena_from_block(block); -+ const LFH_arena *block_arena = LFH_block_arena_from_block(block); -+ const LFH_arena *arena_arena = LFH_large_arena_from_block((LFH_block *)arena); -+ const char *err = NULL; -+ -+ if (flags & HEAP_VALIDATE) -+ return LFH_validate_arena(flags, arena); -+ -+ if (!arena) -+ err = "invalid arena"; -+ else if (arena != arena_arena && arena != (arena_arena + 1)) -+ err = "invalid arena alignment"; -+ else if (arena == block_arena) -+ { -+ if ((UINT_PTR)block < (UINT_PTR)block_arena + ARENA_HEADER_SIZE) -+ err = "invalid block alignment"; -+ if (((UINT_PTR)block & (sizeof(*block) - 1))) -+ err = "invalid block alignment"; -+ } -+ else if (arena != large_arena) -+ err = "large/huge arena mismatch"; -+ else if ((UINT_PTR)block != (UINT_PTR)block_arena) -+ err = "invalid block for large/huge arena"; -+ -+ if (err) WARN("%08x %p: %s\n", flags, block, err); -+ return err == NULL; -+} -+ -+static BOOLEAN LFH_validate_free_block(ULONG flags, const LFH_block *block) -+{ -+ const char *err = NULL; -+ -+ if (!LFH_validate_block(flags, block)) -+ return FALSE; -+ if (block->type != LFH_block_type_free) -+ err = "invalid free block type"; -+ -+ if (err) WARN("%08x %p: %s\n", flags, block, err); -+ return err == NULL; -+} -+ -+static BOOLEAN LFH_validate_defer_block(ULONG flags, const LFH_block *block) -+{ -+ const char *err = NULL; -+ -+ if (!LFH_validate_block(flags, block)) -+ return FALSE; -+ if (block->type != LFH_block_type_free) -+ err = "invalid defer block type"; -+ else if (flags & HEAP_FREE_CHECKING_ENABLED) -+ { -+ const unsigned int *data = (const unsigned int *)LFH_ptr_from_block(block); -+ size_t class_size = LFH_block_get_class_size(block); -+ for (size_t i = 0; i < class_size / 4 - (data - (const unsigned int *)block) && !err; ++i) -+ if (data[i] != 0xfeeefeee) err = "invalid free filler"; -+ } -+ -+ if (err) WARN("%08x %p: %s\n", flags, block, err); -+ return err == NULL; -+} -+ -+static inline BOOLEAN LFH_validate_used_block(ULONG flags, const LFH_block *block) -+{ -+ const char *err = NULL; -+ -+ if (!LFH_validate_block(flags, block)) -+ return FALSE; -+ if (block->type != LFH_block_type_used) -+ err = "invalid used block type"; -+ else if (flags & HEAP_TAIL_CHECKING_ENABLED) -+ { -+ const unsigned char *data = (const unsigned char *)LFH_ptr_from_block(block); -+ size_t alloc_size = LFH_block_get_alloc_size(block, flags); -+ size_t class_size = LFH_block_get_class_size(block); -+ for (size_t i = alloc_size; i < class_size - (data - (const unsigned char *)block) && !err; ++i) -+ if (data[i] != 0xab) err = "invalid tail filler"; -+ } -+ -+ if (err) WARN("%08x %p: %s\n", flags, block, err); -+ return err == NULL; -+} -+ -+static BOOLEAN LFH_validate_arena_free_blocks(ULONG flags, const LFH_arena *arena) -+{ -+ ssize_t offset = arena->next_free; -+ while (offset > 0) -+ { -+ LFH_block *block = LFH_arena_get_block(arena, offset); -+ if (!LFH_validate_free_block(flags, block)) -+ return FALSE; -+ offset = block->next_free; -+ } -+ -+ return TRUE; -+} -+ -+static BOOLEAN LFH_validate_arena(ULONG flags, const LFH_arena *arena) -+{ -+ const char *err = NULL; -+ const LFH_arena *parent; -+ const LFH_arena *block_arena = LFH_block_arena_from_block((LFH_block *)arena); -+ const LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); -+ -+ if (flags & HEAP_VALIDATE) -+ return LFH_validate_heap(flags, LFH_heap_from_arena(arena)); -+ -+ if (arena != large_arena && arena != block_arena) -+ err = "invalid arena alignment"; -+ else if (arena == block_arena) -+ { -+ if (!LFH_validate_block(flags, (LFH_block *)arena)) -+ err = "invalid block arena"; -+ else if (!LFH_validate_arena_free_blocks(flags, arena)) -+ err = "invalid block arena free list"; -+ } -+ else if (arena == large_arena && !LFH_class_from_arena(arena)) -+ { -+ if (arena->huge_size <= LARGE_CLASS_MAX_SIZE) -+ err = "invalid huge arena size"; -+ } -+ else if (arena == large_arena && (parent = LFH_parent_from_arena(arena)) != arena) -+ { -+ if (arena > parent || LFH_large_arena_from_block((LFH_block *)parent) != parent) -+ err = "invalid child arena parent"; -+ } -+ else -+ { -+ if (!LFH_validate_arena_free_blocks(flags, arena)) -+ err = "invalid large arena free list"; -+ } -+ -+ if (err) WARN("%08x %p: %s\n", flags, arena, err); -+ return err == NULL; -+} -+ -+static BOOLEAN LFH_validate_class_arenas(ULONG flags, const LFH_class *class) -+{ -+ LFH_arena *arena = class->next; -+ while (arena) -+ { -+ if (!LFH_validate_arena(flags, arena)) -+ return FALSE; -+ -+ arena = arena->class_entry; -+ } -+ -+ return TRUE; -+} -+ -+static BOOLEAN LFH_validate_heap_defer_blocks(ULONG flags, const LFH_heap *heap) -+{ -+ const LFH_slist *entry = heap->list_defer; -+ -+ while (entry) -+ { -+ const LFH_block *block = LIST_ENTRY(entry, LFH_block, entry_defer); -+ if (!LFH_validate_defer_block(flags, block)) -+ return FALSE; -+ entry = entry->next; -+ } -+ -+ return TRUE; -+} -+ -+static BOOLEAN LFH_validate_heap(ULONG flags, const LFH_heap *heap) -+{ -+ const char *err = NULL; -+ UINT i; -+ -+ flags &= ~HEAP_VALIDATE; -+ -+ if (heap != LFH_thread_heap(FALSE)) -+ err = "unable to validate foreign heap"; -+ else if (!LFH_validate_heap_defer_blocks(flags, heap)) -+ err = "invalid heap defer blocks"; -+ else -+ { -+ for (i = 0; err == NULL && i < TOTAL_BLOCK_CLASS_COUNT; ++i) -+ { -+ if (!LFH_validate_class_arenas(flags, &heap->block_class[i])) -+ return FALSE; -+ } -+ -+ for (i = 0; err == NULL && i < TOTAL_LARGE_CLASS_COUNT; ++i) -+ { -+ if (!LFH_validate_class_arenas(flags, &heap->large_class[i])) -+ return FALSE; -+ } -+ } -+ -+ if (err) WARN("%08x %p: %s\n", flags, heap, err); -+ return err == NULL; -+} -+ -+static inline void LFH_block_initialize(LFH_block *block, ULONG flags, size_t old_size, size_t new_size, size_t class_size) -+{ -+ char *ptr = (char *)LFH_ptr_from_block(block); -+ -+ TRACE("block %p, flags %x, old_size %Ix, new_size %Ix, class_size %Ix, ptr %p\n", block, flags, old_size, new_size, class_size, ptr); -+ -+ if ((flags & HEAP_ZERO_MEMORY) && new_size > old_size) -+ memset(ptr + old_size, 0, new_size - old_size); -+ else if ((flags & HEAP_FREE_CHECKING_ENABLED) && new_size > old_size && class_size < BLOCK_ARENA_SIZE) -+ memset(ptr + old_size, 0x55, new_size - old_size); -+ -+ if ((flags & HEAP_TAIL_CHECKING_ENABLED)) -+ memset(ptr + new_size, 0xab, class_size - new_size - (ptr - (char *)block)); -+ -+ block->type = LFH_block_type_used; -+ block->alloc_size = new_size; -+} -+ -+static FORCEINLINE LFH_ptr *LFH_allocate(ULONG flags, size_t size) -+{ -+ LFH_block *block = NULL; -+ LFH_class *class; -+ LFH_arena *arena; -+ LFH_heap *heap = LFH_thread_heap(TRUE); -+ size_t class_size = LFH_get_class_size(flags, size); -+ -+ if (class_size == ~(size_t)0) -+ return NULL; -+ -+ if (!LFH_deallocate_deferred_blocks(heap)) -+ return NULL; -+ -+ if ((class = LFH_heap_get_class(heap, class_size))) -+ { -+ arena = LFH_acquire_arena(heap, class); -+ if (arena) block = LFH_allocate_block(heap, class, arena); -+ if (block) LFH_block_initialize(block, flags, 0, size, LFH_block_get_class_size(block)); -+ } -+ else -+ { -+ arena = LFH_allocate_huge_arena(heap, class_size); -+ if (arena) block = LFH_arena_get_block(arena, ARENA_HEADER_SIZE); -+ if (block) LFH_block_initialize(block, flags, 0, size, LFH_block_get_class_size(block)); -+ } -+ -+ LFH_deallocated_cached_arenas(heap); -+ -+ if (!block) return NULL; -+ return LFH_ptr_from_block(block); -+} -+ -+static FORCEINLINE BOOLEAN LFH_free(ULONG flags, LFH_ptr *ptr) -+{ -+ LFH_block *block = LFH_block_from_ptr(ptr); -+ LFH_arena *arena = LFH_arena_from_block(block); -+ LFH_heap *heap = LFH_heap_from_arena(arena); -+ -+ if (!LFH_class_from_arena(arena)) -+ return LFH_memory_deallocate(arena, LFH_block_get_class_size(block)); -+ -+ if (flags & HEAP_FREE_CHECKING_ENABLED) -+ { -+ unsigned int *data = (unsigned int *)LFH_ptr_from_block(block); -+ size_t class_size = LFH_block_get_class_size(block); -+ for (size_t i = 0; i < class_size / 4 - (data - (const unsigned int *)block); ++i) -+ data[i] = 0xfeeefeee; -+ } -+ -+ block->type = LFH_block_type_free; -+ -+ if (heap == LFH_thread_heap(FALSE) && !(flags & HEAP_FREE_CHECKING_ENABLED)) -+ LFH_deallocate_block(heap, LFH_arena_from_block(block), block); -+ else -+ LFH_slist_push(&heap->list_defer, &block->entry_defer); -+ -+ return TRUE; -+} -+ -+static FORCEINLINE LFH_ptr *LFH_reallocate(ULONG flags, LFH_ptr *old_ptr, size_t new_size) -+{ -+ LFH_block *block = LFH_block_from_ptr(old_ptr); -+ LFH_arena *arena = LFH_arena_from_block(block); -+ LFH_heap *heap = LFH_heap_from_arena(arena); -+ size_t old_size = LFH_block_get_alloc_size(block, flags); -+ size_t old_class_size = LFH_block_get_class_size(block); -+ size_t new_class_size = LFH_get_class_size(flags, new_size); -+ LFH_class *new_class, *old_class = LFH_class_from_arena(arena); -+ LFH_ptr *new_ptr = NULL; -+ -+ if (new_class_size == ~(size_t)0) -+ return NULL; -+ -+ if (new_class_size <= old_class_size) -+ goto in_place; -+ -+ if ((new_class = LFH_heap_get_class(heap, new_class_size)) && new_class == old_class) -+ goto in_place; -+ -+ old_class_size = LFH_huge_alloc_size(old_class_size); -+ new_class_size = LFH_huge_alloc_size(new_class_size); -+ if (!new_class && !old_class && old_class_size == new_class_size) -+ goto in_place; -+ -+ if (flags & HEAP_REALLOC_IN_PLACE_ONLY) -+ return NULL; -+ -+ if (!(new_ptr = LFH_allocate(flags, new_size))) -+ return NULL; -+ -+ memcpy(new_ptr, old_ptr, old_size); -+ -+ if (LFH_free(flags, old_ptr)) -+ return new_ptr; -+ -+ LFH_free(flags, new_ptr); -+ return NULL; -+ -+in_place: -+ LFH_block_initialize(block, flags, old_size, new_size, old_class_size); -+ return old_ptr; -+} -+ -+static inline size_t LFH_get_allocated_size(ULONG flags, const LFH_ptr *ptr) -+{ -+ const LFH_block *block = LFH_block_from_ptr(ptr); -+ return LFH_block_get_alloc_size(block, flags); -+} -+ -+static inline BOOLEAN LFH_validate(ULONG flags, const LFH_ptr *ptr) -+{ -+ const LFH_block *block = LFH_block_from_ptr(ptr); -+ const LFH_heap *heap; -+ -+ /* clear HEAP_VALIDATE so we only validate block */ -+ if (ptr) -+ return LFH_validate_used_block(flags & ~HEAP_VALIDATE, block); -+ -+ if (!(heap = LFH_thread_heap(FALSE))) -+ return TRUE; -+ -+ return LFH_validate_heap(flags, heap); -+} -+ -+static inline BOOLEAN LFH_try_validate_all(ULONG flags) -+{ -+ if (!(flags & HEAP_VALIDATE_ALL)) -+ return TRUE; -+ -+ if (LFH_validate(flags, NULL)) -+ return TRUE; -+ -+ LFH_dump_heap(LFH_thread_heap(FALSE)); -+ return FALSE; -+} -+ -+NTSTATUS HEAP_lfh_allocate(HANDLE heap, ULONG flags, SIZE_T size, void **out) -+{ -+ TRACE("heap %p, flags %08x, size %lx, out %p.\n", heap, flags, size, out); -+ -+ if (!LFH_try_validate_all(flags)) -+ return STATUS_INVALID_PARAMETER; -+ -+ if (!(*out = LFH_allocate(flags, size))) -+ return STATUS_NO_MEMORY; -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS HEAP_lfh_free(HANDLE heap, ULONG flags, void *ptr) -+{ -+ TRACE("heap %p, flags %08x, ptr %p.\n", heap, flags, ptr); -+ -+ if (!LFH_try_validate_all(flags)) -+ return STATUS_INVALID_PARAMETER; -+ -+ if (!LFH_validate(flags, ptr)) -+ return STATUS_INVALID_PARAMETER; -+ -+ if (!LFH_free(flags, ptr)) -+ return STATUS_INVALID_PARAMETER; -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS HEAP_lfh_reallocate(HANDLE heap, ULONG flags, void *ptr, SIZE_T size, void **out) -+{ -+ TRACE("heap %p, flags %08x, ptr %p, size %lx, out %p.\n", heap, flags, ptr, size, out); -+ -+ if (!LFH_try_validate_all(flags)) -+ return STATUS_INVALID_PARAMETER; -+ -+ if (!LFH_validate(flags, ptr)) -+ return STATUS_INVALID_PARAMETER; -+ -+ if (!(*out = LFH_reallocate(flags, ptr, size))) -+ return STATUS_NO_MEMORY; -+ -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS HEAP_lfh_get_allocated_size(HANDLE heap, ULONG flags, const void *ptr, SIZE_T* out) -+{ -+ TRACE("heap %p, flags %08x, ptr %p, out %p.\n", heap, flags, ptr, out); -+ -+ if (!LFH_try_validate_all(flags)) -+ return STATUS_INVALID_PARAMETER; -+ -+ if (!LFH_validate(flags, ptr)) -+ return STATUS_INVALID_PARAMETER; -+ -+ *out = LFH_get_allocated_size(flags, ptr); -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS HEAP_lfh_validate(HANDLE heap, ULONG flags, const void *ptr) -+{ -+ TRACE("heap %p, flags %08x, ptr %p.\n", heap, flags, ptr); -+ -+ if (!LFH_try_validate_all(flags)) -+ return STATUS_INVALID_PARAMETER; -+ -+ if (!LFH_validate(flags, ptr)) -+ return STATUS_INVALID_PARAMETER; -+ -+ return STATUS_SUCCESS; - } - - void HEAP_lfh_notify_thread_destroy(BOOLEAN last) - { -+ SLIST_HEADER *list_orphan = LFH_orphan_list(); -+ SLIST_ENTRY *entry_orphan = NULL; -+ LFH_heap *heap; -+ -+ if (last) -+ { -+ while ((entry_orphan || (entry_orphan = RtlInterlockedFlushSList(list_orphan)))) -+ { -+ LFH_heap *orphan = LIST_ENTRY(entry_orphan, LFH_heap, entry_orphan); -+ entry_orphan = entry_orphan->Next; -+ LFH_heap_finalize(orphan); -+ } -+ LFH_memory_deallocate(list_orphan, BLOCK_ARENA_SIZE); -+ } -+ else if ((heap = LFH_thread_heap(FALSE)) && LFH_validate_heap(0, heap)) -+ RtlInterlockedPushEntrySList(list_orphan, &heap->entry_orphan); - } - - void HEAP_lfh_set_debug_flags(ULONG flags) - { -+ LFH_heap *heap = LFH_thread_heap(FALSE); -+ if (!heap) return; -+ -+ LFH_deallocate_deferred_blocks(heap); -+ LFH_deallocated_cached_arenas(heap); - } -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index a864604377e..aa6c279bf9a 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -60,6 +60,7 @@ struct ntdll_thread_data - PRTL_THREAD_START_ROUTINE start; /* thread entry point */ - void *param; /* thread entry point parameter */ - void *jmp_buf; /* setjmp buffer for exception handling */ -+ void *heap; /* thread local heap data */ - }; - - C_ASSERT( sizeof(struct ntdll_thread_data) <= sizeof(((TEB *)0)->GdiTebBatch) ); - -From 361dc9564a98d195ee8442d9f89acc5aa8e87c7b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 9 Apr 2021 23:09:17 +0200 -Subject: [PATCH 14/18] ntdll: Enable LFH for process heap. - ---- - dlls/ntdll/loader.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c -index 925742a81fd..29166e42ee1 100644 ---- a/dlls/ntdll/loader.c -+++ b/dlls/ntdll/loader.c -@@ -3750,6 +3750,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR - ANSI_STRING func_name; - WINE_MODREF *kernel32; - PEB *peb = NtCurrentTeb()->Peb; -+ DWORD hci = 2; - - peb->LdrData = &ldr; - peb->FastPebLock = &peb_lock; -@@ -3773,6 +3774,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR - wm->ldr.LoadCount = -1; - - build_ntdll_module(); -+ RtlSetHeapInformation( GetProcessHeap(), HeapCompatibilityInformation, &hci, sizeof(hci) ); - - if ((status = load_dll( NULL, L"kernel32.dll", NULL, 0, &kernel32 )) != STATUS_SUCCESS) - { - -From 83c381834b0a5ef35cf1e9e81faebbbec7424172 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 5 May 2020 15:00:46 +0200 -Subject: [PATCH 15/18] msvcrt: Enable LFH for internal heaps. - ---- - dlls/msvcrt/heap.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/dlls/msvcrt/heap.c b/dlls/msvcrt/heap.c -index b74a759227a..5941d0a4934 100644 ---- a/dlls/msvcrt/heap.c -+++ b/dlls/msvcrt/heap.c -@@ -530,7 +530,9 @@ int CDECL _set_sbh_threshold(size_t threshold) - - if(!sb_heap) - { -+ ULONG hci = 2; - sb_heap = HeapCreate(0, 0, 0); -+ HeapSetInformation(sb_heap, HeapCompatibilityInformation, &hci, sizeof(hci)); - if(!sb_heap) - return 0; - } -@@ -867,7 +869,9 @@ int CDECL strncpy_s(char *dest, size_t numberOfElements, - - BOOL msvcrt_init_heap(void) - { -+ ULONG hci = 2; - heap = HeapCreate(0, 0, 0); -+ HeapSetInformation(heap, HeapCompatibilityInformation, &hci, sizeof(hci)); - return heap != NULL; - } - - -From 646422a2d45396c94c487aba54e1b98385ad2d6c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Mar 2021 18:57:40 +0100 -Subject: [PATCH 16/18] ntdll: Force indirect branches for the error cases. - ---- - dlls/ntdll/heap_lfh.c | 104 +++++++++++++++++++++++------------------- - 1 file changed, 56 insertions(+), 48 deletions(-) - -diff --git a/dlls/ntdll/heap_lfh.c b/dlls/ntdll/heap_lfh.c -index 8c982f91ea0..1ec822c7de1 100644 ---- a/dlls/ntdll/heap_lfh.c -+++ b/dlls/ntdll/heap_lfh.c -@@ -26,6 +26,14 @@ - - #include "ntdll_misc.h" - -+#if defined(__GNUC__) || defined(__clang__) -+#define likely(x) __builtin_expect(!!(x), 1) -+#define unlikely(x) __builtin_expect(!!(x), 0) -+#else -+#define likely(x) x -+#define unlikely(x) x -+#endif -+ - WINE_DEFAULT_DEBUG_CHANNEL(heap); - - typedef struct LFH_ptr LFH_ptr; -@@ -686,26 +694,26 @@ static inline BOOLEAN LFH_validate_block(ULONG flags, const LFH_block *block) - const LFH_arena *arena_arena = LFH_large_arena_from_block((LFH_block *)arena); - const char *err = NULL; - -- if (flags & HEAP_VALIDATE) -+ if (unlikely(flags & HEAP_VALIDATE)) - return LFH_validate_arena(flags, arena); - -- if (!arena) -+ if (unlikely(!arena)) - err = "invalid arena"; -- else if (arena != arena_arena && arena != (arena_arena + 1)) -+ else if (unlikely(arena != arena_arena && arena != (arena_arena + 1))) - err = "invalid arena alignment"; -- else if (arena == block_arena) -+ else if (likely(arena == block_arena)) - { -- if ((UINT_PTR)block < (UINT_PTR)block_arena + ARENA_HEADER_SIZE) -+ if (unlikely((UINT_PTR)block < (UINT_PTR)block_arena + ARENA_HEADER_SIZE)) - err = "invalid block alignment"; -- if (((UINT_PTR)block & (sizeof(*block) - 1))) -+ if (unlikely(((UINT_PTR)block & (sizeof(*block) - 1)))) - err = "invalid block alignment"; - } -- else if (arena != large_arena) -+ else if (unlikely(arena != large_arena)) - err = "large/huge arena mismatch"; -- else if ((UINT_PTR)block != (UINT_PTR)block_arena) -+ else if (unlikely((UINT_PTR)block != (UINT_PTR)block_arena)) - err = "invalid block for large/huge arena"; - -- if (err) WARN("%08x %p: %s\n", flags, block, err); -+ if (unlikely(err)) WARN("%08x %p: %s\n", flags, block, err); - return err == NULL; - } - -@@ -713,12 +721,12 @@ static BOOLEAN LFH_validate_free_block(ULONG flags, const LFH_block *block) - { - const char *err = NULL; - -- if (!LFH_validate_block(flags, block)) -+ if (unlikely(!LFH_validate_block(flags, block))) - return FALSE; -- if (block->type != LFH_block_type_free) -+ if (unlikely(block->type != LFH_block_type_free)) - err = "invalid free block type"; - -- if (err) WARN("%08x %p: %s\n", flags, block, err); -+ if (unlikely(err)) WARN("%08x %p: %s\n", flags, block, err); - return err == NULL; - } - -@@ -726,19 +734,19 @@ static BOOLEAN LFH_validate_defer_block(ULONG flags, const LFH_block *block) - { - const char *err = NULL; - -- if (!LFH_validate_block(flags, block)) -+ if (unlikely(!LFH_validate_block(flags, block))) - return FALSE; -- if (block->type != LFH_block_type_free) -+ if (unlikely(block->type != LFH_block_type_free)) - err = "invalid defer block type"; -- else if (flags & HEAP_FREE_CHECKING_ENABLED) -+ else if (unlikely(flags & HEAP_FREE_CHECKING_ENABLED)) - { - const unsigned int *data = (const unsigned int *)LFH_ptr_from_block(block); - size_t class_size = LFH_block_get_class_size(block); - for (size_t i = 0; i < class_size / 4 - (data - (const unsigned int *)block) && !err; ++i) -- if (data[i] != 0xfeeefeee) err = "invalid free filler"; -+ if (unlikely(data[i] != 0xfeeefeee)) err = "invalid free filler"; - } - -- if (err) WARN("%08x %p: %s\n", flags, block, err); -+ if (unlikely(err)) WARN("%08x %p: %s\n", flags, block, err); - return err == NULL; - } - -@@ -746,11 +754,11 @@ static inline BOOLEAN LFH_validate_used_block(ULONG flags, const LFH_block *bloc - { - const char *err = NULL; - -- if (!LFH_validate_block(flags, block)) -+ if (unlikely(!LFH_validate_block(flags, block))) - return FALSE; -- if (block->type != LFH_block_type_used) -+ if (unlikely(block->type != LFH_block_type_used)) - err = "invalid used block type"; -- else if (flags & HEAP_TAIL_CHECKING_ENABLED) -+ else if (unlikely(flags & HEAP_TAIL_CHECKING_ENABLED)) - { - const unsigned char *data = (const unsigned char *)LFH_ptr_from_block(block); - size_t alloc_size = LFH_block_get_alloc_size(block, flags); -@@ -759,7 +767,7 @@ static inline BOOLEAN LFH_validate_used_block(ULONG flags, const LFH_block *bloc - if (data[i] != 0xab) err = "invalid tail filler"; - } - -- if (err) WARN("%08x %p: %s\n", flags, block, err); -+ if (unlikely(err)) WARN("%08x %p: %s\n", flags, block, err); - return err == NULL; - } - -@@ -784,35 +792,35 @@ static BOOLEAN LFH_validate_arena(ULONG flags, const LFH_arena *arena) - const LFH_arena *block_arena = LFH_block_arena_from_block((LFH_block *)arena); - const LFH_arena *large_arena = LFH_large_arena_from_block((LFH_block *)arena); - -- if (flags & HEAP_VALIDATE) -+ if (unlikely(flags & HEAP_VALIDATE)) - return LFH_validate_heap(flags, LFH_heap_from_arena(arena)); - -- if (arena != large_arena && arena != block_arena) -+ if (unlikely(arena != large_arena && arena != block_arena)) - err = "invalid arena alignment"; -- else if (arena == block_arena) -+ else if (unlikely(arena == block_arena)) - { -- if (!LFH_validate_block(flags, (LFH_block *)arena)) -+ if (unlikely(!LFH_validate_block(flags, (LFH_block *)arena))) - err = "invalid block arena"; -- else if (!LFH_validate_arena_free_blocks(flags, arena)) -+ else if (unlikely(!LFH_validate_arena_free_blocks(flags, arena))) - err = "invalid block arena free list"; - } -- else if (arena == large_arena && !LFH_class_from_arena(arena)) -+ else if (unlikely(arena == large_arena && !LFH_class_from_arena(arena))) - { -- if (arena->huge_size <= LARGE_CLASS_MAX_SIZE) -+ if (unlikely(arena->huge_size <= LARGE_CLASS_MAX_SIZE)) - err = "invalid huge arena size"; - } -- else if (arena == large_arena && (parent = LFH_parent_from_arena(arena)) != arena) -+ else if (unlikely(arena == large_arena && (parent = LFH_parent_from_arena(arena)) != arena)) - { -- if (arena > parent || LFH_large_arena_from_block((LFH_block *)parent) != parent) -+ if (unlikely(arena > parent || LFH_large_arena_from_block((LFH_block *)parent) != parent)) - err = "invalid child arena parent"; - } - else - { -- if (!LFH_validate_arena_free_blocks(flags, arena)) -+ if (unlikely(!LFH_validate_arena_free_blocks(flags, arena))) - err = "invalid large arena free list"; - } - -- if (err) WARN("%08x %p: %s\n", flags, arena, err); -+ if (unlikely(err)) WARN("%08x %p: %s\n", flags, arena, err); - return err == NULL; - } - -@@ -871,7 +879,7 @@ static BOOLEAN LFH_validate_heap(ULONG flags, const LFH_heap *heap) - } - } - -- if (err) WARN("%08x %p: %s\n", flags, heap, err); -+ if (unlikely(err)) WARN("%08x %p: %s\n", flags, heap, err); - return err == NULL; - } - -@@ -1009,7 +1017,7 @@ static inline BOOLEAN LFH_validate(ULONG flags, const LFH_ptr *ptr) - const LFH_heap *heap; - - /* clear HEAP_VALIDATE so we only validate block */ -- if (ptr) -+ if (likely(ptr)) - return LFH_validate_used_block(flags & ~HEAP_VALIDATE, block); - - if (!(heap = LFH_thread_heap(FALSE))) -@@ -1020,10 +1028,10 @@ static inline BOOLEAN LFH_validate(ULONG flags, const LFH_ptr *ptr) - - static inline BOOLEAN LFH_try_validate_all(ULONG flags) - { -- if (!(flags & HEAP_VALIDATE_ALL)) -+ if (likely(!(flags & HEAP_VALIDATE_ALL))) - return TRUE; - -- if (LFH_validate(flags, NULL)) -+ if (likely(LFH_validate(flags, NULL))) - return TRUE; - - LFH_dump_heap(LFH_thread_heap(FALSE)); -@@ -1034,10 +1042,10 @@ NTSTATUS HEAP_lfh_allocate(HANDLE heap, ULONG flags, SIZE_T size, void **out) - { - TRACE("heap %p, flags %08x, size %lx, out %p.\n", heap, flags, size, out); - -- if (!LFH_try_validate_all(flags)) -+ if (unlikely(!LFH_try_validate_all(flags))) - return STATUS_INVALID_PARAMETER; - -- if (!(*out = LFH_allocate(flags, size))) -+ if (unlikely(!(*out = LFH_allocate(flags, size)))) - return STATUS_NO_MEMORY; - - return STATUS_SUCCESS; -@@ -1047,13 +1055,13 @@ NTSTATUS HEAP_lfh_free(HANDLE heap, ULONG flags, void *ptr) - { - TRACE("heap %p, flags %08x, ptr %p.\n", heap, flags, ptr); - -- if (!LFH_try_validate_all(flags)) -+ if (unlikely(!LFH_try_validate_all(flags))) - return STATUS_INVALID_PARAMETER; - -- if (!LFH_validate(flags, ptr)) -+ if (unlikely(!LFH_validate(flags, ptr))) - return STATUS_INVALID_PARAMETER; - -- if (!LFH_free(flags, ptr)) -+ if (unlikely(!LFH_free(flags, ptr))) - return STATUS_INVALID_PARAMETER; - - return STATUS_SUCCESS; -@@ -1063,13 +1071,13 @@ NTSTATUS HEAP_lfh_reallocate(HANDLE heap, ULONG flags, void *ptr, SIZE_T size, v - { - TRACE("heap %p, flags %08x, ptr %p, size %lx, out %p.\n", heap, flags, ptr, size, out); - -- if (!LFH_try_validate_all(flags)) -+ if (unlikely(!LFH_try_validate_all(flags))) - return STATUS_INVALID_PARAMETER; - -- if (!LFH_validate(flags, ptr)) -+ if (unlikely(!LFH_validate(flags, ptr))) - return STATUS_INVALID_PARAMETER; - -- if (!(*out = LFH_reallocate(flags, ptr, size))) -+ if (unlikely(!(*out = LFH_reallocate(flags, ptr, size)))) - return STATUS_NO_MEMORY; - - return STATUS_SUCCESS; -@@ -1079,10 +1087,10 @@ NTSTATUS HEAP_lfh_get_allocated_size(HANDLE heap, ULONG flags, const void *ptr, - { - TRACE("heap %p, flags %08x, ptr %p, out %p.\n", heap, flags, ptr, out); - -- if (!LFH_try_validate_all(flags)) -+ if (unlikely(!LFH_try_validate_all(flags))) - return STATUS_INVALID_PARAMETER; - -- if (!LFH_validate(flags, ptr)) -+ if (unlikely(!LFH_validate(flags, ptr))) - return STATUS_INVALID_PARAMETER; - - *out = LFH_get_allocated_size(flags, ptr); -@@ -1093,10 +1101,10 @@ NTSTATUS HEAP_lfh_validate(HANDLE heap, ULONG flags, const void *ptr) - { - TRACE("heap %p, flags %08x, ptr %p.\n", heap, flags, ptr); - -- if (!LFH_try_validate_all(flags)) -+ if (unlikely(!LFH_try_validate_all(flags))) - return STATUS_INVALID_PARAMETER; - -- if (!LFH_validate(flags, ptr)) -+ if (unlikely(!LFH_validate(flags, ptr))) - return STATUS_INVALID_PARAMETER; - - return STATUS_SUCCESS; - -From e716aa2bfdbf18acbf372345b318efe50645b38c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 24 May 2021 19:21:13 +0200 -Subject: [PATCH 18/18] ntdll: Unroll memcpy instead of preventing - optimisations. - ---- - dlls/ntdll/string.c | 154 ++++++++++++++++++++++++++++++++++++-------- - 1 file changed, 126 insertions(+), 28 deletions(-) - -diff --git a/dlls/ntdll/string.c b/dlls/ntdll/string.c -index bd7bc287201..badc6707988 100644 ---- a/dlls/ntdll/string.c -+++ b/dlls/ntdll/string.c -@@ -94,6 +94,130 @@ int __cdecl memcmp( const void *ptr1, const void *ptr2, size_t n ) - } - - -+static FORCEINLINE void memmove_c_unaligned_32( char *d, const char *s, size_t n ) -+{ -+ uint64_t tmp0, tmp1, tmp2, tmpn; -+ -+ if (n >= 24) -+ { -+ tmp0 = *(uint64_t *)s; -+ tmp1 = *(uint64_t *)(s + 8); -+ tmp2 = *(uint64_t *)(s + 16); -+ tmpn = *(uint64_t *)(s + n - 8); -+ *(uint64_t *)d = tmp0; -+ *(uint64_t *)(d + 8) = tmp1; -+ *(uint64_t *)(d + 16) = tmp2; -+ *(uint64_t *)(d + n - 8) = tmpn; -+ } -+ else if (n >= 16) -+ { -+ tmp0 = *(uint64_t *)s; -+ tmp1 = *(uint64_t *)(s + 8); -+ tmpn = *(uint64_t *)(s + n - 8); -+ *(uint64_t *)d = tmp0; -+ *(uint64_t *)(d + 8) = tmp1; -+ *(uint64_t *)(d + n - 8) = tmpn; -+ } -+ else if (n >= 8) -+ { -+ tmp0 = *(uint64_t *)s; -+ tmpn = *(uint64_t *)(s + n - 8); -+ *(uint64_t *)d = tmp0; -+ *(uint64_t *)(d + n - 8) = tmpn; -+ } -+ else if (n >= 4) -+ { -+ tmp0 = *(uint32_t *)s; -+ tmpn = *(uint32_t *)(s + n - 4); -+ *(uint32_t *)d = tmp0; -+ *(uint32_t *)(d + n - 4) = tmpn; -+ } -+ else if (n >= 2) -+ { -+ tmp0 = *(uint16_t *)s; -+ tmpn = *(uint16_t *)(s + n - 2); -+ *(uint16_t *)d = tmp0; -+ *(uint16_t *)(d + n - 2) = tmpn; -+ } -+ else if (n >= 1) -+ { -+ *(uint8_t *)d = *(uint8_t *)s; -+ } -+} -+ -+ -+static FORCEINLINE void *memmove_c( char *d, const char *s, size_t n ) -+{ -+ if (n <= 32) memmove_c_unaligned_32( d, s, n ); -+ else if (d <= s) -+ { -+ uint64_t tmp0, tmp1, tmp2; -+ size_t k = 0; -+ while (n >= 48) -+ { -+ tmp0 = *(uint64_t *)(s + 0); -+ tmp1 = *(uint64_t *)(s + 8); -+ tmp2 = *(uint64_t *)(s + 16); -+ *(uint64_t*)(d + 0) = tmp0; -+ *(uint64_t*)(d + 8) = tmp1; -+ *(uint64_t*)(d + 16) = tmp2; -+ tmp0 = *(uint64_t *)(s + 24); -+ tmp1 = *(uint64_t *)(s + 32); -+ tmp2 = *(uint64_t *)(s + 40); -+ *(uint64_t*)(d + 24) = tmp0; -+ *(uint64_t*)(d + 32) = tmp1; -+ *(uint64_t*)(d + 40) = tmp2; -+ d += 48; s += 48; n -= 48; k += 48; -+ } -+ while (n >= 24) -+ { -+ tmp0 = *(uint64_t *)(s + 0); -+ tmp1 = *(uint64_t *)(s + 8); -+ tmp2 = *(uint64_t *)(s + 16); -+ *(uint64_t*)(d + 0) = tmp0; -+ *(uint64_t*)(d + 8) = tmp1; -+ *(uint64_t*)(d + 16) = tmp2; -+ d += 24; s += 24; n -= 24; k += 24; -+ } -+ memmove_c_unaligned_32( d, s, n ); -+ return d - k; -+ } -+ else -+ { -+ uint64_t tmp0, tmp1, tmp2; -+ size_t k = n; -+ while (k >= 48) -+ { -+ tmp0 = *(uint64_t *)(s + k - 8); -+ tmp1 = *(uint64_t *)(s + k - 16); -+ tmp2 = *(uint64_t *)(s + k - 24); -+ *(uint64_t*)(d + k - 8) = tmp0; -+ *(uint64_t*)(d + k - 16) = tmp1; -+ *(uint64_t*)(d + k - 24) = tmp2; -+ tmp0 = *(uint64_t *)(s + k - 32); -+ tmp1 = *(uint64_t *)(s + k - 40); -+ tmp2 = *(uint64_t *)(s + k - 48); -+ *(uint64_t*)(d + k - 32) = tmp0; -+ *(uint64_t*)(d + k - 40) = tmp1; -+ *(uint64_t*)(d + k - 48) = tmp2; -+ k -= 48; -+ } -+ while (k >= 24) -+ { -+ tmp0 = *(uint64_t *)(s + k - 8); -+ tmp1 = *(uint64_t *)(s + k - 16); -+ tmp2 = *(uint64_t *)(s + k - 24); -+ *(uint64_t*)(d + k - 8) = tmp0; -+ *(uint64_t*)(d + k - 16) = tmp1; -+ *(uint64_t*)(d + k - 24) = tmp2; -+ k -= 24; -+ } -+ memmove_c_unaligned_32( d, s, k ); -+ } -+ return d; -+} -+ -+ - /********************************************************************* - * memcpy (NTDLL.@) - * -@@ -102,20 +226,7 @@ int __cdecl memcmp( const void *ptr1, const void *ptr2, size_t n ) - */ - void * __cdecl memcpy( void *dst, const void *src, size_t n ) - { -- volatile unsigned char *d = dst; /* avoid gcc optimizations */ -- const unsigned char *s = src; -- -- if ((size_t)dst - (size_t)src >= n) -- { -- while (n--) *d++ = *s++; -- } -- else -- { -- d += n - 1; -- s += n - 1; -- while (n--) *d-- = *s--; -- } -- return dst; -+ return memmove_c( dst, src, n ); - } - - -@@ -124,20 +235,7 @@ void * __cdecl memcpy( void *dst, const void *src, size_t n ) - */ - void * __cdecl memmove( void *dst, const void *src, size_t n ) - { -- volatile unsigned char *d = dst; /* avoid gcc optimizations */ -- const unsigned char *s = src; -- -- if ((size_t)dst - (size_t)src >= n) -- { -- while (n--) *d++ = *s++; -- } -- else -- { -- d += n - 1; -- s += n - 1; -- while (n--) *d-- = *s--; -- } -- return dst; -+ return memmove_c( dst, src, n ); - } - - -From c56598427c4bc89ea01cbb72ec551545c2bd6e3d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 19 May 2021 18:49:10 +0200 -Subject: [PATCH] ntdll: Always add 16 bytes to heap block tail. - -To prevent crashing in buffer overflows, and as Windows default heap -apparently does as well. - -Journey does some at the very end of the game, and it sometimes silently -corrupts the heap until it crashes. - -CW-Bug-Id: 18894 ---- - dlls/ntdll/heap_lfh.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/ntdll/heap_lfh.c b/dlls/ntdll/heap_lfh.c -index 8c982f91ea0..5411ea31847 100644 ---- a/dlls/ntdll/heap_lfh.c -+++ b/dlls/ntdll/heap_lfh.c -@@ -238,7 +238,7 @@ static inline size_t LFH_block_get_alloc_size(const LFH_block *block, ULONG flag - - static inline size_t LFH_get_class_size(ULONG flags, size_t size) - { -- size_t extra = sizeof(LFH_block) + ((flags & HEAP_TAIL_CHECKING_ENABLED) ? 16 : 0); -+ size_t extra = sizeof(LFH_block) + 16; - if (size + extra < size) return ~(size_t)0; - return size + extra; - } -From ddf89dae5b5b000df51daf558177d663522811e8 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 20 Jul 2021 21:16:09 +0300 -Subject: [PATCH] fixup! ntdll: Add extended heap type and LFH stubs. - ---- - dlls/ntdll/heap.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index d6e32e7c3fc..e9d7f248a24 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -2229,7 +2229,7 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, LPCVOID ptr ) - switch (heapPtr->extended_type) - { - case HEAP_LFH: -- if (!(status = HEAP_lfh_validate( heapPtr, flags, ptr ))) return TRUE; -+ if (!HEAP_lfh_validate( heapPtr, flags, ptr )) break; - /* fallthrough */ - default: - if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); diff --git a/patches/proton/51-proton_fonts.patch b/patches/proton/51-proton_fonts.patch deleted file mode 100644 index 81b4ba5f9..000000000 --- a/patches/proton/51-proton_fonts.patch +++ /dev/null @@ -1,692 +0,0 @@ -From 76530c770cc27af5022b8d077cb7d13ca277b094 Mon Sep 17 00:00:00 2001 -From: Nikolay Sivov -Date: Tue, 23 Oct 2018 16:18:20 +0300 -Subject: [PATCH] wine.inf: Add font registry entries. - ---- - loader/wine.inf.in | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index c0d600a00e3..8dfe41166c9 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -261,6 +261,7 @@ CurrentVersion="Software\Microsoft\Windows\CurrentVersion" - FontSubStr="Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes" - Control="System\CurrentControlSet\Control" - Packages="Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppModel\PackageRepository\Packages" -+FontsNT="Software\Microsoft\Windows NT\CurrentVersion\Fonts" - - [Classes] - HKCR,.chm,,2,"chm.file" -@@ -679,6 +680,10 @@ HKLM,%FontSubStr%,"Times New Roman CYR,204",,"Times New Roman,204" - HKLM,%FontSubStr%,"Times New Roman Greek,161",,"Times New Roman,161" - HKLM,%FontSubStr%,"Times New Roman TUR,162",,"Times New Roman,162" - HKLM,System\CurrentControlSet\Hardware Profiles\Current\Software\Fonts,"LogPixels",0x10003,0x00000060 -+HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" -+HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" -+HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" -+HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" - - [MCI] - HKLM,%Mci32Str%,"AVIVideo",,"mciavi32.dll" -From 58cfb3d5fc97f5f418bbedea3aec084ab88eaa79 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 30 Oct 2018 13:04:06 -0500 -Subject: [PATCH] wine.inf: Substitute Times New Roman for Palatino Linotype - -For AOE2HD launcher. ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 8dfe41166c9..13723f2b8dc 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -684,6 +684,7 @@ HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" - HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" - HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" - HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" -+HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" - - [MCI] - HKLM,%Mci32Str%,"AVIVideo",,"mciavi32.dll" -From 05899e5bac238252787f56646da16db8e6541e89 Mon Sep 17 00:00:00 2001 -From: Jactry Zeng -Date: Thu, 13 Dec 2018 22:21:34 +0800 -Subject: [PATCH] win32u: Add CJK font replacements. - ---- - dlls/win32u/font.c | 143 +++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 143 insertions(+) - -diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c -index e7d2c3a13e3..bda31b0a5dd 100644 ---- a/dlls/win32u/font.c -+++ b/dlls/win32u/font.c -@@ -961,6 +961,130 @@ static BOOL add_family_replacement( const WCHAR *new_name, const WCHAR *replace - return TRUE; - } - -+/* Simplified Chinese fonts */ -+static const WCHAR SimSun[] = {'S','i','m','S','u','n',0}; -+static const WCHAR atSimSun[] = {'@','S','i','m','S','u','n',0}; -+static const WCHAR Microsoft_YaHei[] = {'M','i','c','r','o','s','o','f','t',' ','Y','a','H','e','i',0}; -+static const WCHAR LiSu[] = {'L','i','S','u',0}; -+/* Traditional Chinese fonts */ -+static const WCHAR PMingLiU[] = {'P','M','i','n','g','L','i','U',0}; -+static const WCHAR atPMingLiU[] = {'@','P','M','i','n','g','L','i','U',0}; -+/* Korean fonts */ -+static const WCHAR Gulim[] = {'G','u','l','i','m',0}; -+static const WCHAR atGulim[] = {'@','G','u','l','i','m',0}; -+/* Japanese fonts */ -+static const WCHAR MS_UI_Gothic[] = {'M','S',' ','U','I',' ','G','o','t','h','i','c',0}; -+static const WCHAR atMS_UI_Gothic[] = {'@','M','S',' ','U','I',' ','G','o','t','h','i','c',0}; -+ -+static const WCHAR new_sc_fonts[] = { -+ /* Ubuntu 16.04 or later, Mint 19, Fedora 29 */ -+ 'N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','S','C',' ','R','e','g','u','l','a','r',0, -+ /* Manjaro 18 */ -+ 'N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','S','C',0, -+ /* Popular open source Chinese font */ -+ 'W','e','n','Q','u','a','n','Y','i',' ','M','i','c','r','o',' ','H','e','i',0, -+ 0 -+}; -+ -+static const WCHAR vertical_new_sc_fonts[] = { -+ /* Ubuntu 16.04 or later, Mint 19, Fedora 29 */ -+ '@','N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','S','C',' ','R','e','g','u','l','a','r',0, -+ /* Manjaro 18 */ -+ '@','N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','S','C',0, -+ /* popular open source Chinese font */ -+ '@','W','e','n','Q','u','a','n','Y','i',' ','M','i','c','r','o',' ','H','e','i',0, -+ 0 -+}; -+ -+static const WCHAR new_tc_fonts[] = { -+ /* Ubuntu 16.04 or later, Mint 19, Fedora 29 */ -+ 'N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','T','C',' ','R','e','g','u','l','a','r',0, -+ /* Manjaro 18 */ -+ 'N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','T','C',0, -+ /* popular open source Chinese font */ -+ 'W','e','n','Q','u','a','n','Y','i',' ','M','i','c','r','o',' ','H','e','i',0, -+ 0 -+}; -+ -+static const WCHAR vertical_new_tc_fonts[] = { -+ /* Ubuntu 16.04 or later */ -+ '@','N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','T','C',' ','R','e','g','u','l','a','r',0, -+ /* Manjaro 18 */ -+ '@','N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','T','C',0, -+ /* popular open source Chinese font */ -+ '@','W','e','n','Q','u','a','n','Y','i',' ','M','i','c','r','o',' ','H','e','i',0, -+ 0 -+}; -+ -+static const WCHAR new_jp_fonts[] = { -+ /* Ubuntu 16.04 or later */ -+ 'N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','J','P',' ','R','e','g','u','l','a','r',0, -+ /* Manjaro 18 */ -+ 'N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','J','P',0, -+ 0 -+}; -+ -+static const WCHAR vertical_new_jp_fonts[] = { -+ /* Ubuntu 16.04 or later */ -+ '@','N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','J','P',' ','R','e','g','u','l','a','r',0, -+ /* Manjaro 18 */ -+ '@','N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','J','P',0, -+ 0 -+}; -+ -+static const WCHAR new_kr_fonts[] = { -+ /* Ubuntu 16.04 or later */ -+ 'N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','K','R',' ','R','e','g','u','l','a','r',0, -+ /* Manjaro 18 */ -+ 'N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','K','R',0, -+ 0 -+}; -+ -+static const WCHAR vertical_new_kr_fonts[] = { -+ /* Ubuntu 16.04 or later */ -+ '@','N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','K','R',' ','R','e','g','u','l','a','r',0, -+ /* Manjaro 18 */ -+ '@','N','o','t','o',' ','S','a','n','s',' ','C','J','K',' ','K','R',0, -+ 0 -+}; -+ -+static const WCHAR MS_PGothic_cp932[]= {0x30fb,0xff6d,0x30fb,0xff73,' ',0x30fb,0xff70,0x7e67,0xff74,0x7e67,0xff77,0x7e5d,0x30fb,0x3051,0}; -+ -+static struct font_replacements -+{ -+ const WCHAR *replacements[4]; -+ const int count; -+ const WCHAR *new_fonts; -+ const WCHAR *vertical_new_fonts; -+ BOOL *font_seen; -+} font_replacements_list[] = -+{ -+ /* Simplified Chinese */ -+ { -+ { -+ SimSun, atSimSun, Microsoft_YaHei, LiSu -+ }, 4, new_sc_fonts, vertical_new_sc_fonts, NULL -+ }, -+ /* Traditional Chinese */ -+ { -+ { -+ PMingLiU, atPMingLiU -+ }, 2, new_tc_fonts, vertical_new_tc_fonts, NULL -+ }, -+ /* Japanese */ -+ { -+ { -+ MS_UI_Gothic, atMS_UI_Gothic, MS_PGothic_cp932 -+ }, 3, new_jp_fonts, vertical_new_jp_fonts, NULL -+ }, -+ /* Korean */ -+ { -+ { -+ Gulim, atGulim -+ }, 2, new_kr_fonts, vertical_new_kr_fonts, NULL -+ } -+}; -+ - /* - * The replacement list is a way to map an entire font - * family onto another family. For example adding -@@ -991,6 +1115,25 @@ static void load_gdi_font_replacements(void) - /* "NewName"="Oldname" */ - if (!find_family_from_any_name( value )) - { -+ int j; -+ -+ for (j = 0; j < ARRAY_SIZE(font_replacements_list); j++) -+ { -+ int k; -+ -+ struct font_replacements *replacement = &font_replacements_list[j]; -+ -+ replacement->font_seen = calloc(1, replacement->count * sizeof(BOOL)); -+ for (k = 0; k < replacement->count; k++) -+ { -+ if (!replacement->font_seen[k] && !memcmp(value, replacement->replacements[k], sizeof(value))) -+ { -+ replacement->font_seen[k] = TRUE; -+ break; -+ } -+ } -+ } -+ - if (info->Type == REG_MULTI_SZ) - { - WCHAR *replace = data; -From 7517f92a46e9303d585b3aeac116970feacd2b4a Mon Sep 17 00:00:00 2001 -From: Nikolay Sivov -Date: Wed, 8 Mar 2017 20:15:40 +0300 -Subject: [PATCH] HACK: dwrite: Don't recommend outline rendering mode - ---- - dlls/dwrite/font.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c -index 5815c09e8ae..04bf703e003 100644 ---- a/dlls/dwrite/font.c -+++ b/dlls/dwrite/font.c -@@ -1218,7 +1218,8 @@ static HRESULT WINAPI dwritefontface_GetRecommendedRenderingMode(IDWriteFontFace - - ppem = emSize * ppdip; - -- if (ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) { -+ /* HACK: disable outline rendering mode to workaround d2d issue */ -+ if (0 && ppem >= RECOMMENDED_OUTLINE_AA_THRESHOLD) { - *mode = DWRITE_RENDERING_MODE_OUTLINE; - return S_OK; - } -From a64b680dd5044f174a025612c38c6b9c9b4e61cd Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Wed, 9 Dec 2020 11:45:50 +0100 -Subject: [PATCH] dwrite: Add free fallback fonts for CJK. - -Add two fonts which are easily found on modern Linux installations. It might -be wise to add others in the future, so that any random Linux installation -has at least one of them. - -CW-Bug-Id: #18395 ---- - dlls/dwrite/analyzer.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c -index 13ccf8e4434..f8d54ed7ec1 100644 ---- a/dlls/dwrite/analyzer.c -+++ b/dlls/dwrite/analyzer.c -@@ -211,7 +211,7 @@ const char *debugstr_sa_script(UINT16 script) - } - - /* system font falback configuration */ --static const WCHAR *cjk_families[] = { L"Meiryo" }; -+static const WCHAR *cjk_families[] = { L"Meiryo", L"Droid Sans Fallback", L"Noto Serif CJK SC" }; - - static const DWRITE_UNICODE_RANGE cjk_ranges[] = - { -From 12dd1ae2f11fc97921aab1612a2097ee556e3fd1 Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Mon, 7 Dec 2020 19:52:23 +0100 -Subject: [PATCH] dwrite: Support at least some Latin fallbacks. - -CW-Bug-Id: #18395 ---- - dlls/dwrite/analyzer.c | 16 ++++++++++++++++ - 1 file changed, 16 insertions(+) - -diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c -index f8d54ed7ec1..097b7b26596 100644 ---- a/dlls/dwrite/analyzer.c -+++ b/dlls/dwrite/analyzer.c -@@ -220,6 +220,21 @@ static const DWRITE_UNICODE_RANGE cjk_ranges[] = - { 0x4e00, 0x9fff }, /* CJK Unified Ideographs */ - }; - -+static const WCHAR timesW[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0}; -+static const WCHAR liberationW[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0}; -+static const WCHAR dejavuW[] = {'D','e','j','a','V','u',' ','S','e','r','i','f',0}; -+ -+static const WCHAR *latin_families[] = { timesW, liberationW, dejavuW }; -+ -+static const DWRITE_UNICODE_RANGE latin_ranges[] = -+{ -+ { 0x0000, 0x05ff }, -+ { 0x1d00, 0x2eff }, -+ { 0xa700, 0xa7ff }, -+ { 0xfb00, 0xfb4f }, -+ { 0xfe20, 0xfe23 }, -+}; -+ - struct fallback_mapping { - DWRITE_UNICODE_RANGE *ranges; - UINT32 ranges_count; -@@ -236,6 +251,7 @@ static const struct fallback_mapping fontfallback_neutral_data[] = { - (WCHAR **)families, ARRAY_SIZE(families) } - - MAPPING_RANGE(cjk_ranges, cjk_families), -+ MAPPING_RANGE(latin_ranges, latin_families), - - #undef MAPPING_RANGE - }; -From 8e476aafc2c965056f815ff0ea84739769cf67b9 Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Fri, 4 Dec 2020 12:07:30 +0100 -Subject: [PATCH] dwrite: Search more generously for font fallbacks. - -CW-Bug-Id: #18395 ---- - dlls/dwrite/analyzer.c | 57 ++++++++++++++++++++++++------------------ - 1 file changed, 32 insertions(+), 25 deletions(-) - -diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c -index 097b7b26596..df68ba869b4 100644 ---- a/dlls/dwrite/analyzer.c -+++ b/dlls/dwrite/analyzer.c -@@ -2096,7 +2096,7 @@ static HRESULT fallback_map_characters(IDWriteFont *font, const WCHAR *text, UIN - /* stop on first unsupported character */ - exists = FALSE; - hr = IDWriteFont_HasCharacter(font, text[i], &exists); -- if (hr == S_OK && exists) -+ if (SUCCEEDED(hr) && exists) - ++*mapped_length; - else - break; -@@ -2114,11 +2114,12 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback, - UINT32 i; - - *mapped_font = NULL; -+ *mapped_length = 0; - - mapping = find_fallback_mapping(fallback, text[0]); - if (!mapping) { - WARN("No mapping range for %#x.\n", text[0]); -- return E_FAIL; -+ return S_OK; - } - - /* Now let's see what fallback can handle. Pick first font that could be created. */ -@@ -2133,19 +2134,18 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback, - - if (!*mapped_font) { - WARN("Failed to create fallback font.\n"); -- return E_FAIL; -+ return S_OK; - } - - hr = fallback_map_characters(*mapped_font, text, length, mapped_length); -- if (FAILED(hr)) -- WARN("Mapping with fallback family %s failed, hr %#lx.\n", debugstr_w(mapping->families[i]), hr); - - if (!*mapped_length) { -+ WARN("Mapping with fallback family %s failed.\n", debugstr_w(mapping->families[i])); - IDWriteFont_Release(*mapped_font); - *mapped_font = NULL; - } - -- return *mapped_length ? S_OK : E_FAIL; -+ return hr; - } - - static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, -@@ -2180,30 +2180,37 @@ static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback1 *iface, ID - - if (basefamily && *basefamily) { - hr = create_matching_font(basecollection, basefamily, weight, style, stretch, ret_font); -- if (FAILED(hr)) -- goto done; - -- hr = fallback_map_characters(*ret_font, text, length, mapped_length); -- if (FAILED(hr)) -- goto done; -+ /* It is not a fatal error for create_matching_font to -+ fail. We still have other fallbacks to try. */ -+ -+ if (SUCCEEDED(hr)) -+ { -+ hr = fallback_map_characters(*ret_font, text, length, mapped_length); -+ if (FAILED(hr)) -+ goto done; -+ } - } - - if (!*mapped_length) { -- IDWriteFont *mapped_font; -- -- hr = fallback_get_fallback_font(fallback, text, length, weight, style, stretch, mapped_length, &mapped_font); -- if (FAILED(hr)) { -- /* fallback wasn't found, keep base font if any, so we can get at least some visual output */ -- if (*ret_font) { -- *mapped_length = length; -- hr = S_OK; -- } -- } -- else { -- if (*ret_font) -- IDWriteFont_Release(*ret_font); -- *ret_font = mapped_font; -+ if (*ret_font) -+ { -+ IDWriteFont_Release(*ret_font); -+ *ret_font = NULL; - } -+ -+ hr = fallback_get_fallback_font(fallback, text, length, weight, style, stretch, mapped_length, ret_font); -+ if (FAILED(hr)) -+ goto done; -+ } -+ -+ if (!*mapped_length) -+ { -+ /* fallback wasn't found, ask the caller to skip one character -+ and try again; FIXME: skip the appropriate number of -+ characters instead of just one */ -+ *mapped_length = 1; -+ hr = S_OK; - } - - done: -From 858a668e52c56d0a8ce3edf9e357e441e30746df Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Thu, 24 Jun 2021 17:27:08 +0200 -Subject: [PATCH] HACK: gdi32/font: Do font linking for Arial too. - -This helps the Rockstar installer to fallback to appropriate fonts -for CJK languages. - -For Rockstar installer font support. - -CW-Bug-Id: #18969 ---- - dlls/win32u/font.c | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c -index bda31b0a5dd..be374584282 100644 ---- a/dlls/win32u/font.c -+++ b/dlls/win32u/font.c -@@ -1684,6 +1684,8 @@ static const WCHAR p_ming_li_uW[] = - {'P','M','i','n','g','L','i','U',0}; - static const WCHAR batangW[] = - {'B','a','t','a','n','g',0}; -+static const WCHAR arialW[] = -+ {'A','r','i','a','l',0}; - - static const WCHAR * const font_links_list[] = - { -@@ -2879,6 +2881,7 @@ static void update_font_system_link_info(UINT current_ansi_codepage) - set_multi_value_key(hkey, lucida_sans_unicodeW, link, len); - set_multi_value_key(hkey, microsoft_sans_serifW, link, len); - set_multi_value_key(hkey, tahomaW, link, len); -+ set_multi_value_key(hkey, arialW, link, len); - NtClose( hkey ); - } - } -@@ -2909,7 +2912,13 @@ static void update_codepage( UINT screen_dpi ) - if (query_reg_ascii_value( wine_fonts_key, "Codepages", info, sizeof(value_buffer) )) - { - cp_match = !wcscmp( (const WCHAR *)info->Data, cpbufW ); -- if (cp_match && screen_dpi == font_dpi) return; /* already set correctly */ -+ if (cp_match && screen_dpi == font_dpi) -+ { -+ /* already set correctly, but, as a HACK, update font link -+ info anyway, so that old Proton prefixes are fixed */ -+ update_font_system_link_info(ansi_cp); -+ return; -+ } - TRACE( "updating registry, codepages/logpixels changed %s/%u -> %u,%u/%u\n", - debugstr_w((const WCHAR *)info->Data), font_dpi, ansi_cp, oem_cp, screen_dpi ); - } -From 6a311289cf8a45a64d6324355e935328276f1a15 Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Fri, 1 Oct 2021 12:05:09 +0200 -Subject: [PATCH] HACK: dwrite: Fix font mappings for the Cyberpunk 2077 - installer. - -This was first reported at -https://github.com/ValveSoftware/Proton/issues/4450#issuecomment-882996582. - -For Cyberpunk 2077 launcher font support. - -CW-Bug-Id: #19125 ---- - dlls/dwrite/analyzer.c | 27 ++++++++++++++++++++++++++- - 1 file changed, 26 insertions(+), 1 deletion(-) - -diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c -index df68ba869b4..a59f3930ce4 100644 ---- a/dlls/dwrite/analyzer.c -+++ b/dlls/dwrite/analyzer.c -@@ -211,7 +211,7 @@ const char *debugstr_sa_script(UINT16 script) - } - - /* system font falback configuration */ --static const WCHAR *cjk_families[] = { L"Meiryo", L"Droid Sans Fallback", L"Noto Serif CJK SC" }; -+static const WCHAR *cjk_families[] = { L"SimSun", L"Meiryo", L"Droid Sans Fallback", L"Noto Serif CJK SC" }; - - static const DWRITE_UNICODE_RANGE cjk_ranges[] = - { -@@ -220,6 +220,16 @@ static const DWRITE_UNICODE_RANGE cjk_ranges[] = - { 0x4e00, 0x9fff }, /* CJK Unified Ideographs */ - }; - -+static const WCHAR *hangul_families[] = { L"Malgun Gothic" }; -+ -+static const DWRITE_UNICODE_RANGE hangul_ranges[] = -+{ -+ { 0x1100, 0x11ff }, /* Hangul Jamo */ -+ { 0x3130, 0x318f }, /* Hangul Compatibility Jamo */ -+ { 0xa960, 0xa97f }, /* Hangul Jamo Extended-A */ -+ { 0xac00, 0xd7ff }, /* Hangul Syllables, Hangul Jamo Extended-B */ -+}; -+ - static const WCHAR timesW[] = {'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0}; - static const WCHAR liberationW[] = {'L','i','b','e','r','a','t','i','o','n',' ','S','e','r','i','f',0}; - static const WCHAR dejavuW[] = {'D','e','j','a','V','u',' ','S','e','r','i','f',0}; -@@ -235,6 +245,19 @@ static const DWRITE_UNICODE_RANGE latin_ranges[] = - { 0xfe20, 0xfe23 }, - }; - -+static const WCHAR microsoft_sans_serifW[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}; -+ -+static const WCHAR *arabic_families[] = { microsoft_sans_serifW }; -+ -+static const DWRITE_UNICODE_RANGE arabic_ranges[] = -+{ -+ { 0x0600, 0x06ff }, /* Arabic */ -+ { 0x0750, 0x077f }, /* Arabic Supplement */ -+ { 0x08a0, 0x08ff }, /* Arabic Extended-A */ -+ { 0xfb50, 0xfdff }, /* Arabic Presentation Forms-A */ -+ { 0xfe70, 0xfeff }, /* Arabic Presentation Forms-B */ -+}; -+ - struct fallback_mapping { - DWRITE_UNICODE_RANGE *ranges; - UINT32 ranges_count; -@@ -251,7 +274,9 @@ static const struct fallback_mapping fontfallback_neutral_data[] = { - (WCHAR **)families, ARRAY_SIZE(families) } - - MAPPING_RANGE(cjk_ranges, cjk_families), -+ MAPPING_RANGE(hangul_ranges, hangul_families), - MAPPING_RANGE(latin_ranges, latin_families), -+ MAPPING_RANGE(arabic_ranges, arabic_families), - - #undef MAPPING_RANGE - }; -From 3dec8c6c6ad03b7d1ef89d1d75f7e6c4e2ee3017 Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Tue, 10 Aug 2021 11:56:55 +0200 -Subject: [PATCH] HACK: loader/wine.inf: Add registry entries for the new - fonts. - -They are required for DWrite to enumerate the fonts. - -For Cyberpunk 2077 launcher font support. - -CW-Bug-Id: #19125 ---- - loader/wine.inf.in | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 13723f2b8dc..2dcf73380ef 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -684,6 +684,10 @@ HKLM,%FontsNT%,"Arial (TrueType)",,"arial.ttf" - HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" - HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" - HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" -+HKLM,%FontsNT%,"Malgun Gothic (TrueType)",,"malgun.ttf" -+HKLM,%FontsNT%,"Microsoft YaHei (TrueType)",,"msyh.ttf" -+HKLM,%FontsNT%,"MS Gothic (TrueType)",,"msgothic.ttc" -+HKLM,%FontsNT%,"SimSun (TrueType)",,"simsun.ttc" - HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" - - [MCI] -From e929662ceb5c88d5c68f040e4636b7be44f07a4e Mon Sep 17 00:00:00 2001 -From: Jactry Zeng -Date: Sun, 26 Sep 2021 14:58:45 +0800 -Subject: [PATCH] loader/wine.inf: Add registry entries for Microsoft Sans - Serif (micross.ttf) and Nirmala UI (nirmala.ttf). - -CW-Bug-Id: #17132 ---- - loader/wine.inf.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 2dcf73380ef..d9ad8a63fdb 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -685,8 +685,10 @@ HKLM,%FontsNT%,"Arial Bold (TrueType)",,"arialbd.ttf" - HKLM,%FontsNT%,"Times New Roman (TrueType)",,"times.ttf" - HKLM,%FontsNT%,"Courier New (TrueType)",,"cour.ttf" - HKLM,%FontsNT%,"Malgun Gothic (TrueType)",,"malgun.ttf" -+HKLM,%FontsNT%,"Microsoft Sans Serif (TrueType)",,"micross.ttf" - HKLM,%FontsNT%,"Microsoft YaHei (TrueType)",,"msyh.ttf" - HKLM,%FontsNT%,"MS Gothic (TrueType)",,"msgothic.ttc" -+HKLM,%FontsNT%,"Nirmala UI (TrueType)",,"nirmala.ttf" - HKLM,%FontsNT%,"SimSun (TrueType)",,"simsun.ttc" - HKCU,Software\Wine\Fonts\Replacements,"Palatino Linotype",,"Times New Roman" - -From 06ef8f2a913dcd776a80ae54c6df5d54a2f731f7 Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Wed, 12 Jan 2022 13:03:28 +0100 -Subject: [PATCH] HACK: win32u/font: Add other font linking entries. - -They improve CJK rendering for the Rockstar Launcher. - -CW-Bug-Id: #19917 ---- - dlls/win32u/font.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c -index be374584282..46dff27d55b 100644 ---- a/dlls/win32u/font.c -+++ b/dlls/win32u/font.c -@@ -1686,6 +1686,12 @@ static const WCHAR batangW[] = - {'B','a','t','a','n','g',0}; - static const WCHAR arialW[] = - {'A','r','i','a','l',0}; -+static const WCHAR arial_boldW[] = -+ {'A','r','i','a','l',' ','B','o','l','d',0}; -+static const WCHAR courier_newW[] = -+ {'C','o','u','r','i','e','r',' ','N','e','w',0}; -+static const WCHAR courier_new_boldW[] = -+ {'C','o','u','r','i','e','r',' ','N','e','w',' ','B','o','l','d',0}; - - static const WCHAR * const font_links_list[] = - { -@@ -2882,6 +2888,9 @@ static void update_font_system_link_info(UINT current_ansi_codepage) - set_multi_value_key(hkey, microsoft_sans_serifW, link, len); - set_multi_value_key(hkey, tahomaW, link, len); - set_multi_value_key(hkey, arialW, link, len); -+ set_multi_value_key(hkey, arial_boldW, link, len); -+ set_multi_value_key(hkey, courier_newW, link, len); -+ set_multi_value_key(hkey, courier_new_boldW, link, len); - NtClose( hkey ); - } - } -From f095d59170ab2f71c5fd5c91ec02f5d89692ff15 Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Fri, 14 Jan 2022 09:46:20 +0100 -Subject: [PATCH] HACK: riched20: Ignore WM_SETFONT for Grand Theft Auto V. - -CW-Bug-Id: #19917 ---- - dlls/riched20/editor.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c -index 429f023ebe4..6a2c7c0748f 100644 ---- a/dlls/riched20/editor.c -+++ b/dlls/riched20/editor.c -@@ -3570,6 +3570,20 @@ LRESULT editor_handle_message( ME_TextEditor *editor, UINT msg, WPARAM wParam, - CHARFORMAT2W fmt; - HDC hDC; - BOOL bRepaint = LOWORD(lParam); -+ const char *sgi = getenv("STEAM_COMPAT_APP_ID"); -+ -+ /* Grand Theft Auto V installer tries to set font for license -+ * richedit to Arial, which breaks CJK languages. Given that the -+ * RTF already has reasonable fonts set, we can just ignore the -+ * message. This can be removed once our richedit is able to do -+ * font substitution properly. CW bug #19917. -+ * -+ * It's important that STEAM_COMPAT_APP_ID environment variable is -+ * used instead of the usual SteamGameId, because the latter is -+ * not available during the configuration stage, when the -+ * installer is run. */ -+ if (sgi && strcmp(sgi, "271590") == 0) -+ return 0; - - if (!wParam) - wParam = (WPARAM)GetStockObject(SYSTEM_FONT); diff --git a/patches/proton/52-proton_quake_champions_syscall.patch b/patches/proton/52-proton_quake_champions_syscall.patch deleted file mode 100644 index e095da070..000000000 --- a/patches/proton/52-proton_quake_champions_syscall.patch +++ /dev/null @@ -1,318 +0,0 @@ -From cbb4df46b9fdb46ee0f0d1724ac1379ba17d0575 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 14 Jul 2021 20:45:38 +0300 -Subject: [PATCH] ntdll: Add stub implementation for - NtSetInformationFile(FileAllocationInformation). - -CW-Bug-Id: 19085 ---- - dlls/ntdll/unix/file.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 80eb16198b4..517b137e8ba 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -4375,6 +4375,15 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, - else io->u.Status = STATUS_INVALID_PARAMETER_3; - break; - -+ case FileAllocationInformation: -+ { -+ const FILE_ALLOCATION_INFORMATION *info = ptr; -+ -+ FIXME("FileAllocationInformation AllocationSize %p stub.\n", (void *)(ULONG_PTR)info->AllocationSize.QuadPart); -+ io->u.Status = STATUS_SUCCESS; -+ break; -+ } -+ - case FilePipeInformation: - if (len >= sizeof(FILE_PIPE_INFORMATION)) - { -From 2c609dcfd614b111f28e820823c4d77bdf59f1ff Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 15 Jul 2021 00:40:57 +0300 -Subject: [PATCH] winebuild: Output stubs after syscalls. - -CW-Bug-Id: 19085 ---- - tools/winebuild/spec32.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c -index 02029056b30..01124a515ed 100644 ---- a/tools/winebuild/spec32.c -+++ b/tools/winebuild/spec32.c -@@ -762,10 +762,10 @@ void output_spec32_file( DLLSPEC *spec ) - open_output_file(); - output_standard_file_header(); - output_module( spec ); -- output_stubs( spec ); - output_exports( spec ); - output_imports( spec ); - output_syscalls( spec ); -+ output_stubs( spec ); - if (needs_get_pc_thunk) output_get_pc_thunk(); - output_resources( spec ); - output_gnu_stack_note(); -From 7750e85dad194a39a1e5bb17e3afc80399e63fcb Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 14 Jul 2021 20:24:39 +0300 -Subject: [PATCH] ntdll: Catch all syscalls at the lower addresses. - -CW-Bug-Id: 19085 ---- - dlls/ntdll/unix/signal_x86_64.c | 67 ++++++++++++++++++--------------- - tools/winebuild/import.c | 5 +-- - 2 files changed, 39 insertions(+), 33 deletions(-) - -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 3487f761324..ede34a36c3e 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -71,6 +71,7 @@ - # include - # include - # include -+# include - #endif - - #define NONAMELESSUNION -@@ -2491,37 +2492,34 @@ static void install_bpf(struct sigaction *sig_act) - # ifndef SECCOMP_SET_MODE_FILTER - # define SECCOMP_SET_MODE_FILTER 1 - # endif -- static const unsigned int flags = SECCOMP_FILTER_FLAG_SPEC_ALLOW; -- static struct sock_filter filter[] = -+ static const BYTE syscall_trap_test[] = - { -- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -- (offsetof(struct seccomp_data, nr))), -- BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0xf000, 0, 1), -- BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), -- BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -+ 0x48, 0x89, 0xc8, /* mov %rcx, %rax */ -+ 0x0f, 0x05, /* syscall */ -+ 0xc3, /* retq */ - }; -- static struct sock_filter filter_rdr2[] = -+ static const unsigned int flags = SECCOMP_FILTER_FLAG_SPEC_ALLOW; -+ static struct sock_filter filter[] = - { -- /* Trap anything called from RDR2 or the launcher (0x140000000 - 0x150000000)*/ -- /* > 0x140000000 */ -- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 0), -- BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x40000000 /*lsb*/, 0, 7), - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 4), -- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x1 /*msb*/, 0, 5), -- -- /* < 0x150000000 */ -- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 0), -- BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, 0x50000000 /*lsb*/, 3, 0), -- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 4), -- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x1 /*msb*/, 0, 1), -+ /* Native libs are loaded at high addresses. */ -+ BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, 0x7000 /*msb*/, 0, 1), -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -+ /* Allow i386. */ -+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, arch)), -+ BPF_JUMP (BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0), -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -+ /* Allow wine64-preloader */ -+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer)), -+ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x7d400000, 1, 0), -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), -+ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0x7d402000, 0, 1), - BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), -- -- /* Allow everything else */ - BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), - }; -+ long (WINAPI *test_syscall)(long sc_number); - struct syscall_frame *frame = amd64_thread_data()->syscall_frame; - struct sock_fprog prog; -- BOOL rdr2 = FALSE; - NTSTATUS status; - - sig_act->sa_sigaction = sigsys_handler; -@@ -2532,23 +2530,26 @@ static void install_bpf(struct sigaction *sig_act) - const char *sgi = getenv("SteamGameId"); - if (sgi && (!strcmp(sgi, "1174180") || !strcmp(sgi, "1404210"))) - { -- /* Use specific filter and signal handler for Red Dead Redemption 2 */ -- prog.len = ARRAY_SIZE(filter_rdr2); -- prog.filter = filter_rdr2; -+ /* Use specific signal handler for Red Dead Redemption 2 */ - sig_act->sa_sigaction = sigsys_handler_rdr2; -- rdr2 = TRUE; - } - } - - sigaction(SIGSYS, sig_act, NULL); - - frame->syscall_flags = syscall_flags; - frame->syscall_table = KeServiceDescriptorTable; - -- if (rdr2) -+ test_syscall = mmap((void *)0x600000000000, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, -+ MAP_PRIVATE | MAP_ANON, -1, 0); -+ if (test_syscall != (void *)0x600000000000) - { - int ret; - -+ ERR("Could not allocate test syscall, falling back to seccomp presence check, test_syscall %p, errno %d.\n", -+ test_syscall, errno); -+ if (test_syscall != MAP_FAILED) munmap(test_syscall, 0x1000); -+ - if ((ret = prctl(PR_GET_SECCOMP, 0, NULL, 0, 0))) - { - if (ret == 2) -@@ -2554,7 +2555,10 @@ static void install_bpf(struct sigaction *sig_act) - } - else - { -- if ((status = syscall(0xffff)) == STATUS_INVALID_PARAMETER) -+ memcpy(test_syscall, syscall_trap_test, sizeof(syscall_trap_test)); -+ status = test_syscall(0xffff); -+ munmap(test_syscall, 0x1000); -+ if (status == STATUS_INVALID_PARAMETER) - { - TRACE("Seccomp filters already installed.\n"); - return; -@@ -2564,10 +2568,13 @@ static void install_bpf(struct sigaction *sig_act) - ERR("Unexpected status %#x, errno %d.\n", status, errno); - return; - } -- prog.len = ARRAY_SIZE(filter); -- prog.filter = filter; - } - -+ TRACE("Installing seccomp filters.\n"); -+ -+ prog.len = ARRAY_SIZE(filter); -+ prog.filter = filter; -+ - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) - { - ERR("prctl(PR_SET_NO_NEW_PRIVS, ...): %s.\n", strerror(errno)); -@@ -3222,7 +3222,6 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, - "leaq 0x28(%rsp),%rsi\n\t" /* first argument */ - "movq %rcx,%rsp\n\t" - "movq 0x00(%rcx),%rax\n\t" -- "subq $0xf000,%rax\n\t" - "movq 0x18(%rcx),%rdx\n\t" - "movl %eax,%ebx\n\t" - "shrl $8,%ebx\n\t" -diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c -index 234a7d936d7..de4a5436cda 100644 ---- a/tools/winebuild/import.c -+++ b/tools/winebuild/import.c -@@ -1912,7 +1911,7 @@ void output_syscalls( DLLSPEC *spec ) - * validate that instruction, we can just put a jmp there instead. */ - output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */ - output( "\t.byte 0xb8\n" ); /* movl $i,%eax */ -- output( "\t.long %u\n", 0xf000 + id ); -+ output( "\t.long %u\n", id ); - output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */ - output( "\t.byte 0x75,0x03\n" ); /* jne 1f */ - output( "\t.byte 0x0f,0x05\n" ); /* syscall */ -From f78b6f2dac4b118537b9e37f45fac797a2ad0a79 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 14 Jul 2021 20:43:39 +0300 -Subject: [PATCH] ntdll: Support '\??\GlobalRoot' prefix in - get_dos_prefix_len(). - -CW-Bug-Id: 19085 ---- - dlls/ntdll/unix/file.c | 29 ++++++++++++++++++++++------- - 1 file changed, 22 insertions(+), 7 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 517b137e8ba..36c51d27857 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -2934,16 +2934,31 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name ) - { - static const WCHAR nt_prefixW[] = {'\\','?','?','\\'}; - static const WCHAR dosdev_prefixW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\'}; -+ static const WCHAR globalrootW[] = {'\\','?','?','\\','G','l','o','b','a','l','R','o','o','t'}; -+ int prefix_len = 0; -+ WCHAR *prefix; -+ USHORT length; - -- if (name->Length >= sizeof(nt_prefixW) && -- !memcmp( name->Buffer, nt_prefixW, sizeof(nt_prefixW) )) -- return ARRAY_SIZE( nt_prefixW ); -+ prefix = name->Buffer; -+ length = name->Length; - -- if (name->Length >= sizeof(dosdev_prefixW) && -- !wcsnicmp( name->Buffer, dosdev_prefixW, ARRAY_SIZE( dosdev_prefixW ))) -- return ARRAY_SIZE( dosdev_prefixW ); -+ if (length >= ARRAY_SIZE( globalrootW ) && -+ !wcsnicmp( prefix, globalrootW, ARRAY_SIZE( globalrootW ))) -+ { -+ WARN("Stripping off GlobalRoot prefix.\n"); -+ prefix += ARRAY_SIZE( globalrootW ); -+ prefix_len += ARRAY_SIZE( globalrootW ); -+ length -= ARRAY_SIZE( globalrootW ); -+ } - -- return 0; -+ if (length >= sizeof(nt_prefixW) && -+ !memcmp( prefix, nt_prefixW, sizeof(nt_prefixW) )) -+ prefix_len += ARRAY_SIZE( nt_prefixW ); -+ else if (length >= sizeof(dosdev_prefixW) && -+ !wcsnicmp( prefix, dosdev_prefixW, ARRAY_SIZE( dosdev_prefixW ))) -+ prefix_len += ARRAY_SIZE( dosdev_prefixW ); -+ -+ return prefix_len; - } - - -From f1b6baa0ed73f7ca74f4790398a3670e61161976 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 29 Jul 2021 20:33:32 +0300 -Subject: [PATCH] fixup! ntdll: Catch all syscalls at the lower addresses. - ---- - dlls/ntdll/unix/signal_x86_64.c | 14 +++++++++++++- - 1 file changed, 13 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index ede34a36c3e..a177ee862c4 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -2498,11 +2498,14 @@ static void install_bpf(struct sigaction *sig_act) - 0xc3, /* retq */ - }; - static const unsigned int flags = SECCOMP_FILTER_FLAG_SPEC_ALLOW; -+ -+#define NATIVE_SYSCALL_ADDRESS_START 0x700000000000 -+ - static struct sock_filter filter[] = - { - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, instruction_pointer) + 4), - /* Native libs are loaded at high addresses. */ -- BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, 0x7000 /*msb*/, 0, 1), -+ BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, NATIVE_SYSCALL_ADDRESS_START >> 32, 0, 1), - BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), - /* Allow i386. */ - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, arch)), -@@ -2520,6 +2523,15 @@ static void install_bpf(struct sigaction *sig_act) - struct sock_fprog prog; - NTSTATUS status; - -+ if ((ULONG_PTR)sc_seccomp < NATIVE_SYSCALL_ADDRESS_START -+ || (ULONG_PTR)syscall < NATIVE_SYSCALL_ADDRESS_START) -+ { -+ ERR("Native libs are being loaded in low addresses, sc_seccomp %p, syscall %p, not installing seccomp.\n", -+ sc_seccomp, syscall); -+ ERR("The known reasons are /proc/sys/vm/legacy_va_layout set to 1 or 'ulimit -s' being 'unlimited'.\n"); -+ return; -+ } -+ - sig_act->sa_sigaction = sigsys_handler; - memset(&prog, 0, sizeof(prog)); - - diff --git a/patches/proton/54-proton-11_death_loop_registry.patch b/patches/proton/54-proton-11_death_loop_registry.patch deleted file mode 100644 index 54b8c99bd..000000000 --- a/patches/proton/54-proton-11_death_loop_registry.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 239879d9f92bedb35e1999a6884c5cb7a76ffa4b Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 15 Sep 2021 00:21:19 +0300 -Subject: [PATCH] wine.inf: Set amd_ags_x64 to built-in for DeathLoop. - -CW-Bug-ID: #19427 ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index faba4be0b91..16582b1baaf 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4234,6 +4234,7 @@ HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steam - HKCU,Software\Valve\Steam\ActiveProcess,"SteamClientDll64",,"%16426%\Steam\steamclient64.dll" - HKCU,Software\Valve\Steam\ActiveProcess,"SteamPath",,"%16426%\Steam" - HKLM,Software\Wow6432Node\Valve\Steam,"InstallPath",,"%16422%\Steam" -+HKCU,Software\Wine\AppDefaults\Deathloop.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - HKCU,Software\Wine\AppDefaults\ForzaHorizon4.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - HKCU,Software\Wine\AppDefaults\NewColossus_x64vk.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" - HKCU,Software\Wine\AppDefaults\RDR2.exe\DllOverrides,"amd_ags_x64",0x2,"builtin,native" diff --git a/patches/proton/55-proton-bcrypt_rdr2_fixes.patch b/patches/proton/55-proton-bcrypt_rdr2_fixes.patch deleted file mode 100644 index c7186a41e..000000000 --- a/patches/proton/55-proton-bcrypt_rdr2_fixes.patch +++ /dev/null @@ -1,1611 +0,0 @@ -From 717a66470ad13872e7e346e7c6de97da1ba1ee2f Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 7 Dec 2020 12:59:55 +0300 -Subject: [PATCH 1/6] bcrypt: Implement DH. - ---- - dlls/bcrypt/bcrypt_internal.h | 14 +++ - dlls/bcrypt/bcrypt_main.c | 174 +++++++++++++++++++++++++-- - dlls/bcrypt/gnutls.c | 217 +++++++++++++++++++++++++++++++++- - include/bcrypt.h | 29 +++++ - 4 files changed, 426 insertions(+), 8 deletions(-) - -diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h -index 0a600a2ebb5..ae771d085c2 100644 ---- a/dlls/bcrypt/bcrypt_internal.h -+++ b/dlls/bcrypt/bcrypt_internal.h -@@ -131,6 +131,7 @@ enum alg_id - ALG_ID_RSA, - - /* secret agreement */ -+ ALG_ID_DH, - ALG_ID_ECDH_P256, - - /* signature */ -@@ -170,6 +171,8 @@ struct key_symmetric - }; - - #define KEY_FLAG_LEGACY_DSA_V2 0x00000001 -+#define KEY_FLAG_DH_PARAMS_SET 0x00000002 -+#define KEY_FLAG_FINALIZED 0x00000004 - - struct key_asymmetric - { -@@ -177,6 +180,7 @@ struct key_asymmetric - unsigned flags; - UCHAR *pubkey; - unsigned pubkey_len; -+ UCHAR *privkey; /* Used for DH private key only. */ - DSSSEED dss_seed; - }; - -@@ -195,6 +199,8 @@ struct key - struct secret - { - struct object hdr; -+ UCHAR *data; -+ ULONG data_len; - }; - - struct key_symmetric_set_auth_data_params -@@ -283,6 +289,13 @@ struct key_import_params - ULONG len; - }; - -+struct key_secret_agreement_params -+{ -+ struct key *privkey; -+ struct key *pubkey; -+ struct secret *secret; -+}; -+ - enum key_funcs - { - unix_process_attach, -@@ -304,6 +317,7 @@ enum key_funcs - unix_key_import_dsa_capi, - unix_key_import_ecc, - unix_key_import_rsa, -+ unix_key_secret_agreement, - }; - - #endif /* __BCRYPT_INTERNAL_H */ -diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c -index 9e0d06e9cc7..889f6ce85ea 100644 ---- a/dlls/bcrypt/bcrypt_main.c -+++ b/dlls/bcrypt/bcrypt_main.c -@@ -112,6 +112,7 @@ builtin_algorithms[] = - { BCRYPT_MD4_ALGORITHM, BCRYPT_HASH_INTERFACE, 270, 16, 512 }, - { BCRYPT_MD2_ALGORITHM, BCRYPT_HASH_INTERFACE, 270, 16, 128 }, - { BCRYPT_RSA_ALGORITHM, BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE, 0, 0, 0 }, -+ { BCRYPT_DH_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, - { BCRYPT_ECDH_P256_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, - { BCRYPT_RSA_SIGN_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, - { BCRYPT_ECDSA_P256_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, -@@ -713,6 +714,33 @@ static NTSTATUS get_hash_property( const struct hash *hash, const WCHAR *prop, U - return status; - } - -+static NTSTATUS get_dh_property( const struct key *key, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) -+{ -+ BCRYPT_DH_PARAMETER_HEADER *h = (BCRYPT_DH_PARAMETER_HEADER *)buf; -+ ULONG data_size; -+ -+ if (wcscmp( prop, BCRYPT_DH_PARAMETERS )) return STATUS_NOT_SUPPORTED; -+ if (!(key->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_HANDLE; -+ -+ data_size = sizeof(BCRYPT_DH_PARAMETER_HEADER) + key->u.a.bitlen / 8 * 2; -+ -+ if (ret_size) -+ *ret_size = data_size; -+ -+ if (!buf) -+ return STATUS_SUCCESS; -+ -+ if (size < data_size) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ h->cbLength = data_size; -+ h->dwMagic = BCRYPT_DH_PARAMETERS_MAGIC; -+ h->cbKeyLength = key->u.a.bitlen / 8; -+ memcpy( h + 1, (BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1, h->cbKeyLength * 2); -+ -+ return STATUS_SUCCESS; -+} -+ - static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size ) - { - switch (key->alg_id) -@@ -724,6 +752,9 @@ static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHA - if (!wcscmp( prop, BCRYPT_AUTH_TAG_LENGTH )) return STATUS_NOT_SUPPORTED; - return get_aes_property( key->u.s.mode, prop, buf, size, ret_size ); - -+ case ALG_ID_DH: -+ return get_dh_property( key, prop, buf, size, ret_size ); -+ - default: - FIXME( "unsupported algorithm %u\n", key->alg_id ); - return STATUS_NOT_IMPLEMENTED; -@@ -975,6 +1006,21 @@ static NTSTATUS key_asymmetric_create( struct key **ret_key, struct algorithm *a - key->hdr.magic = MAGIC_KEY; - key->alg_id = alg->id; - key->u.a.bitlen = bitlen; -+ -+ if (alg->id == ALG_ID_DH) -+ { -+ if (bitlen < 512) -+ { -+ free( key ); -+ return STATUS_INVALID_PARAMETER; -+ } -+ pubkey_len = sizeof(BCRYPT_DH_KEY_BLOB) + bitlen / 8 * 3; -+ if (!(key->u.a.privkey = malloc( bitlen / 8 ))) -+ { -+ free( key ); -+ return STATUS_NO_MEMORY; -+ } -+ } - key->u.a.pubkey_len = pubkey_len; - - if (!(key->u.a.pubkey = malloc( pubkey_len ))) -@@ -1063,6 +1109,7 @@ static NTSTATUS key_import( BCRYPT_ALG_HANDLE algorithm, const WCHAR *type, BCRY - static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, ULONG output_len, ULONG *size ) - { - struct key_export_params params; -+ BOOL dh_private = FALSE; - - if (!wcscmp( type, BCRYPT_KEY_DATA_BLOB )) - { -@@ -1117,6 +1164,27 @@ static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, U - params.ret_len = size; - return UNIX_CALL( key_export_dsa_capi, ¶ms ); - } -+ else if (!wcscmp( type, BCRYPT_DH_PUBLIC_BLOB ) || (dh_private = !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB ))) -+ { -+ BCRYPT_DH_KEY_BLOB *h = (BCRYPT_DH_KEY_BLOB *)output; -+ -+ if (!(key->u.a.flags & KEY_FLAG_FINALIZED)) -+ return STATUS_INVALID_HANDLE; -+ -+ *size = key->u.a.pubkey_len; -+ if (dh_private) -+ *size += key->u.a.bitlen / 8; -+ -+ if (output_len < *size) return STATUS_SUCCESS; -+ memcpy(output, key->u.a.pubkey, key->u.a.pubkey_len); -+ if (dh_private) -+ memcpy(output + key->u.a.pubkey_len, key->u.a.privkey, key->u.a.bitlen / 8); -+ -+ h->dwMagic = dh_private ? BCRYPT_DH_PRIVATE_MAGIC : BCRYPT_DH_PUBLIC_MAGIC; -+ h->cbKey = key->u.a.bitlen / 8; -+ -+ return STATUS_SUCCESS; -+ } - - FIXME( "unsupported key type %s\n", debugstr_w(type) ); - return STATUS_NOT_IMPLEMENTED; -@@ -1311,6 +1379,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP - ULONG input_len ) - { - struct key_import_params params; -+ BOOL dh_private = FALSE; - struct key *key; - NTSTATUS status; - ULONG size; -@@ -1505,6 +1574,32 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP - *ret_key = key; - return STATUS_SUCCESS; - } -+ else if (!wcscmp( type, BCRYPT_DH_PUBLIC_BLOB ) || (dh_private = !wcscmp( type, BCRYPT_DH_PRIVATE_BLOB ))) -+ { -+ BCRYPT_DH_KEY_BLOB *h = (BCRYPT_DH_KEY_BLOB *)input; -+ ULONG size; -+ -+ if (alg->id != ALG_ID_DH) return STATUS_NOT_SUPPORTED; -+ if (h->dwMagic != (dh_private ? BCRYPT_DH_PRIVATE_MAGIC : BCRYPT_DH_PUBLIC_MAGIC)) -+ { -+ WARN("unexpected dwMagic %#x.\n", h->dwMagic); -+ return STATUS_INVALID_PARAMETER; -+ } -+ -+ size = sizeof(*h) + h->cbKey * 3; -+ if (dh_private) -+ size += h->cbKey; -+ if (input_len != size) return STATUS_INVALID_PARAMETER; -+ if (h->cbKey * 8 < 512) return STATUS_INVALID_PARAMETER; -+ -+ if ((status = key_asymmetric_create( &key, alg, h->cbKey * 8, input, 0 ))) return status; -+ -+ if (dh_private) -+ memcpy( key->u.a.privkey, input + sizeof(*h) + h->cbKey * 3, h->cbKey); -+ -+ *ret_key = key; -+ return STATUS_SUCCESS; -+ } - - FIXME( "unsupported key type %s\n", debugstr_w(type) ); - return STATUS_NOT_SUPPORTED; -@@ -1586,6 +1681,9 @@ NTSTATUS WINAPI BCryptGenerateKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_H - case ALG_ID_DSA: - size = sizeof(BCRYPT_DSA_KEY_BLOB) + 3 * key_len / 8; - break; -+ case ALG_ID_DH: -+ size = sizeof(BCRYPT_DH_KEY_BLOB) + key_len / 8 * 3; -+ break; - default: - FIXME( "algorithm %u not supported\n", alg->id ); - return STATUS_NOT_SUPPORTED; -@@ -1598,11 +1696,15 @@ NTSTATUS WINAPI BCryptGenerateKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_H - NTSTATUS WINAPI BCryptFinalizeKeyPair( BCRYPT_KEY_HANDLE handle, ULONG flags ) - { - struct key *key = handle; -+ NTSTATUS ret; - - TRACE( "%p, %#lx\n", key, flags ); - if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE; - -- return UNIX_CALL( key_asymmetric_generate, key ); -+ if (!(ret = UNIX_CALL( key_asymmetric_generate, key ))) -+ key->u.a.flags |= KEY_FLAG_FINALIZED; -+ -+ return ret; - } - - NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, const WCHAR *type, -@@ -1678,6 +1780,13 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy ) - key_copy->u.a.pubkey_len = key_orig->u.a.pubkey_len; - key_copy->u.a.dss_seed = key_orig->u.a.dss_seed; - -+ if (key_orig->alg_id == ALG_ID_DH && key_orig->u.a.privkey) -+ { -+ if (!(buffer = malloc( key_orig->u.a.bitlen / 8 ))) return STATUS_NO_MEMORY; -+ memcpy( buffer, key_orig->u.a.privkey, key_orig->u.a.bitlen / 8 ); -+ key_copy->u.a.privkey = buffer; -+ } -+ - params.key_orig = key_orig; - params.key_copy = key_copy; - if ((status = UNIX_CALL( key_asymmetric_duplicate, ¶ms ))) return status; -@@ -1699,6 +1808,7 @@ static void key_destroy( struct key *key ) - { - UNIX_CALL( key_asymmetric_destroy, key ); - free( key->u.a.pubkey ); -+ free( key->u.a.privkey ); - } - key->hdr.magic = 0; - free( key ); -@@ -1732,6 +1842,7 @@ NTSTATUS WINAPI BCryptImportKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HAN - BCRYPT_KEY_HANDLE *ret_key, UCHAR *input, ULONG input_len, ULONG flags ) - { - struct algorithm *alg = algorithm; -+ NTSTATUS status; - - TRACE( "%p, %p, %s, %p, %p, %u, %08x\n", algorithm, decrypt_key, debugstr_w(type), ret_key, input, - input_len, flags ); -@@ -1744,7 +1855,10 @@ NTSTATUS WINAPI BCryptImportKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HAN - return STATUS_NOT_IMPLEMENTED; - } - -- return key_import_pair( alg, type, ret_key, input, input_len ); -+ if (!(status = key_import_pair( alg, type, ret_key, input, input_len ))) -+ ((struct key *)*ret_key)->u.a.flags |= KEY_FLAG_FINALIZED; -+ -+ return status; - } - - NTSTATUS WINAPI BCryptSignHash( BCRYPT_KEY_HANDLE handle, void *padding, UCHAR *input, ULONG input_len, -@@ -1887,6 +2001,29 @@ NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHA - case MAGIC_KEY: - { - struct key *key = (struct key *)object; -+ -+ if (key->alg_id == ALG_ID_DH) -+ { -+ if (!lstrcmpW( prop, BCRYPT_DH_PARAMETERS )) -+ { -+ const BCRYPT_DH_PARAMETER_HEADER *h = (const BCRYPT_DH_PARAMETER_HEADER *)value; -+ ULONG param_size = sizeof(BCRYPT_DH_PARAMETER_HEADER) + key->u.a.bitlen / 8 * 2; -+ -+ if (key->u.a.flags & KEY_FLAG_FINALIZED) -+ return STATUS_INVALID_HANDLE; -+ -+ if (size < param_size) -+ return STATUS_BUFFER_TOO_SMALL; -+ if (!h || h->cbLength != param_size || h->dwMagic != BCRYPT_DH_PARAMETERS_MAGIC -+ || h->cbKeyLength != key->u.a.bitlen / 8) -+ return STATUS_INVALID_PARAMETER; -+ -+ memcpy((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1, h + 1, h->cbKeyLength * 2); -+ key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; -+ return STATUS_SUCCESS; -+ } -+ return STATUS_NOT_IMPLEMENTED; -+ } - return set_key_property( key, prop, value, size, flags ); - } - default: -@@ -2043,31 +2180,54 @@ NTSTATUS WINAPI BCryptDeriveKeyPBKDF2( BCRYPT_ALG_HANDLE handle, UCHAR *pwd, ULO - - NTSTATUS WINAPI BCryptSecretAgreement(BCRYPT_KEY_HANDLE privatekey, BCRYPT_KEY_HANDLE publickey, BCRYPT_SECRET_HANDLE *handle, ULONG flags) - { -+ struct key_secret_agreement_params params; - struct key *privkey = privatekey; - struct key *pubkey = publickey; - struct secret *secret; -+ NTSTATUS status; - -- FIXME( "%p, %p, %p, %#lx\n", privatekey, publickey, handle, flags ); -+ TRACE( "%p, %p, %p, %#lx\n", privatekey, publickey, handle, flags ); - - if (!privkey || privkey->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE; - if (!pubkey || pubkey->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE; - if (!handle) return STATUS_INVALID_PARAMETER; -+ if (key_is_symmetric( privkey ) || privkey->alg_id != pubkey->alg_id) return STATUS_INVALID_PARAMETER; -+ if (!(privkey->u.a.flags & pubkey->u.a.flags & KEY_FLAG_FINALIZED)) return STATUS_INVALID_PARAMETER; -+ if (privkey->u.a.bitlen != pubkey->u.a.bitlen) return STATUS_INVALID_PARAMETER; - - if (!(secret = calloc( 1, sizeof(*secret) ))) return STATUS_NO_MEMORY; -- secret->hdr.magic = MAGIC_SECRET; -+ if (!(secret->data = malloc( privkey->u.a.bitlen / 8 ))) -+ { -+ free( secret ); -+ return STATUS_NO_MEMORY; -+ } - -- *handle = secret; -- return STATUS_SUCCESS; -+ params.privkey = privkey; -+ params.pubkey = pubkey; -+ params.secret = secret; -+ -+ if ((status = UNIX_CALL( key_secret_agreement, ¶ms ))) -+ { -+ free( secret ); -+ free( secret->data ); -+ } -+ else -+ { -+ secret->hdr.magic = MAGIC_SECRET; -+ *handle = secret; -+ } -+ return status; - } - - NTSTATUS WINAPI BCryptDestroySecret(BCRYPT_SECRET_HANDLE handle) - { - struct secret *secret = handle; - -- FIXME( "%p\n", handle ); -+ TRACE( "%p\n", handle ); - - if (!secret || secret->hdr.magic != MAGIC_SECRET) return STATUS_INVALID_HANDLE; - secret->hdr.magic = 0; -+ free( secret->data ); - free( secret ); - return STATUS_SUCCESS; - } -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index a015d85f85d..a751310c883 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -34,6 +35,7 @@ - #include - #include - #include -+#include - - #include "ntstatus.h" - #define WIN32_NO_STATUS -@@ -80,6 +80,8 @@ static union key_data *key_data( struct key *key ) - return (union key_data *)key->private; - } - -+static BOOL dh_supported; -+ - /* Not present in gnutls version < 3.0 */ - static int (*pgnutls_cipher_tag)(gnutls_cipher_hd_t, void *, size_t); - static int (*pgnutls_cipher_add_auth)(gnutls_cipher_hd_t, const void *, size_t); -@@ -115,6 +117,17 @@ static int (*pgnutls_privkey_decrypt_data)(gnutls_privkey_t, unsigned int flags, - /* Not present in gnutls version < 3.6.0 */ - static int (*pgnutls_decode_rs_value)(const gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *); - -+static int (*pgnutls_dh_params_init)(gnutls_dh_params_t * dh_params); -+static void (*pgnutls_dh_params_deinit)(gnutls_dh_params_t dh_params); -+static int (*pgnutls_dh_params_generate2)(gnutls_dh_params_t dparams, unsigned int bits); -+static int (*pgnutls_dh_params_import_raw2)(gnutls_dh_params_t dh_params, const gnutls_datum_t * prime, -+ const gnutls_datum_t * generator, unsigned key_bits); -+static int (*pgnutls_dh_params_export_raw)(gnutls_dh_params_t params, gnutls_datum_t * prime, -+ gnutls_datum_t * generator, unsigned int *bits); -+static int (*pgnutls_dh_generate_key)(gnutls_dh_params_t dh_params, gnutls_datum_t *priv_key, gnutls_datum_t *pub_key); -+static int (*pgnutls_dh_compute_key)(gnutls_dh_params_t dh_params, const gnutls_datum_t *priv_key, -+ const gnutls_datum_t *pub_key, const gnutls_datum_t *peer_key, gnutls_datum_t *Z); -+ - static void *libgnutls_handle; - #define MAKE_FUNCPTR(f) static typeof(f) * p##f - MAKE_FUNCPTR(gnutls_cipher_decrypt2); -@@ -303,6 +316,39 @@ static NTSTATUS gnutls_process_attach( void *args ) - pgnutls_perror( ret ); - goto fail; - } -+ if (!(pgnutls_dh_params_init = dlsym( libgnutls_handle, "gnutls_dh_params_init" ))) -+ { -+ WARN("gnutls_dh_params_init not found\n"); -+ } -+ if (!(pgnutls_dh_params_deinit = dlsym( libgnutls_handle, "gnutls_dh_params_deinit" ))) -+ { -+ WARN("gnutls_dh_params_deinit not found\n"); -+ } -+ if (!(pgnutls_dh_params_generate2 = dlsym( libgnutls_handle, "gnutls_dh_params_generate2" ))) -+ { -+ WARN("gnutls_dh_params_generate2 not found\n"); -+ } -+ if (!(pgnutls_dh_params_import_raw2 = dlsym( libgnutls_handle, "gnutls_dh_params_import_raw2" ))) -+ { -+ WARN("gnutls_dh_params_import_raw2 not found\n"); -+ } -+ if (!(pgnutls_dh_params_export_raw = dlsym( libgnutls_handle, "gnutls_dh_params_export_raw" ))) -+ { -+ WARN("gnutls_dh_params_export_raw not found\n"); -+ } -+ if (!(pgnutls_dh_generate_key = dlsym( libgnutls_handle, "_gnutls_dh_generate_key" )) -+ && !(pgnutls_dh_generate_key = dlsym( libgnutls_handle, "gnutls_dh_generate_key" ))) -+ { -+ WARN("gnutls_dh_generate_key not found\n"); -+ } -+ if (!(pgnutls_dh_compute_key = dlsym( libgnutls_handle, "_gnutls_dh_compute_key" )) -+ && !(pgnutls_dh_compute_key = dlsym( libgnutls_handle, "gnutls_dh_compute_key" ))) -+ { -+ WARN("gnutls_dh_compute_key not found\n"); -+ } -+ -+ dh_supported = pgnutls_dh_params_init && pgnutls_dh_params_generate2 && pgnutls_dh_params_import_raw2 -+ && pgnutls_dh_generate_key && pgnutls_dh_compute_key; - - if (TRACE_ON( bcrypt )) - { -@@ -836,6 +882,87 @@ static NTSTATUS export_gnutls_pubkey_dsa_capi( gnutls_privkey_t gnutls_key, cons - return STATUS_SUCCESS; - } - -+static NTSTATUS CDECL key_dh_generate( struct key *key ) -+{ -+ gnutls_datum_t prime, generator, privkey, pubkey; -+ NTSTATUS status = STATUS_SUCCESS; -+ gnutls_dh_params_t dh_params; -+ ULONG key_length; -+ int ret; -+ -+ if (!dh_supported) -+ { -+ ERR("DH is not available.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+ } -+ -+ if ((ret = pgnutls_dh_params_init( &dh_params ))) -+ { -+ pgnutls_perror( ret ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ key_length = key->u.a.bitlen / 8; -+ -+ if (!(key->u.a.flags & KEY_FLAG_DH_PARAMS_SET)) -+ { -+ /* Generate parameters, export and then import them back below. -+ * The bitlen in dh parameters (which is later used for keys generation) -+ * is not set to gnutls_dh_params_generate2 'bits' parameter as one -+ * could expect. gnutls_dh_params_generate2 generates 'q' (which is not -+ * actually needed for DH) with the estimated bit length and then -+ * sets the bit length to the 'q' bitlength. */ -+ if ((ret = pgnutls_dh_params_generate2( dh_params, key->u.a.bitlen ))) -+ { -+ pgnutls_perror( ret ); -+ pgnutls_dh_params_deinit( dh_params ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ if ((ret = pgnutls_dh_params_export_raw( dh_params, &prime, &generator, NULL ))) -+ { -+ pgnutls_perror( ret ); -+ pgnutls_dh_params_deinit( dh_params ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1), key_length, &prime, NULL ); -+ export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1) + key_length, -+ key_length, &generator, NULL ); -+ free( prime.data ); -+ free( generator.data ); -+ -+ key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; -+ } -+ -+ prime.size = generator.size = key_length; -+ prime.data = (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1); -+ generator.data = (BYTE *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1) + key_length; -+ -+ if ((ret = pgnutls_dh_params_import_raw2( dh_params, &prime, &generator, key->u.a.bitlen ))) -+ { -+ pgnutls_perror( ret ); -+ pgnutls_dh_params_deinit( dh_params ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ if ((ret = pgnutls_dh_generate_key( dh_params, &privkey, &pubkey ))) -+ { -+ pgnutls_perror( ret ); -+ pgnutls_dh_params_deinit( dh_params ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ export_gnutls_datum( (BYTE *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1) + 2 * key_length, -+ key_length, &pubkey, NULL ); -+ export_gnutls_datum( key->u.a.privkey, key_length, &privkey, NULL); -+ -+ free( privkey.data ); -+ free( pubkey.data ); -+ pgnutls_dh_params_deinit( dh_params ); -+ -+ return status; -+} -+ - static NTSTATUS key_asymmetric_generate( void *args ) - { - struct key *key = args; -@@ -866,6 +993,9 @@ static NTSTATUS key_asymmetric_generate( void *args ) - bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP256R1 ); - break; - -+ case ALG_ID_DH: -+ return key_dh_generate( key ); -+ - default: - FIXME( "algorithm %u not supported\n", key->alg_id ); - return STATUS_NOT_SUPPORTED; -@@ -879,6 +1009,7 @@ static NTSTATUS key_asymmetric_generate( void *args ) - - if ((ret = pgnutls_privkey_generate( handle, pk_alg, bitlen, 0 ))) - { -+ ERR("gnutls error bitlen %u.\n", bitlen); - pgnutls_perror( ret ); - pgnutls_privkey_deinit( handle ); - return STATUS_INTERNAL_ERROR; -@@ -1787,6 +1918,89 @@ static NTSTATUS key_asymmetric_decrypt( void *args ) - return status; - } - -+static NTSTATUS key_secret_agreement( void *args ) -+{ -+ struct key_secret_agreement_params *params = args; -+ struct secret *secret; -+ struct key *priv_key; -+ struct key *peer_key; -+ int ret; -+ -+ priv_key = params->privkey; -+ peer_key = params->pubkey; -+ secret = params->secret; -+ -+ switch (priv_key->alg_id) -+ { -+ case ALG_ID_DH: -+ { -+ gnutls_datum_t prime, generator, priv, peer, secret_datum; -+ gnutls_dh_params_t dh_params; -+ ULONG key_length; -+ -+ if (!dh_supported) -+ { -+ ERR("DH is not available.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+ } -+ -+ if ((ret = pgnutls_dh_params_init( &dh_params ))) -+ { -+ pgnutls_perror( ret ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ key_length = priv_key->u.a.bitlen / 8; -+ -+ prime.size = generator.size = key_length; -+ prime.data = (UCHAR *)((BCRYPT_DH_KEY_BLOB *)priv_key->u.a.pubkey + 1); -+ generator.data = (BYTE *)((BCRYPT_DH_KEY_BLOB *)priv_key->u.a.pubkey + 1) + key_length; -+ -+ if ((ret = pgnutls_dh_params_import_raw2( dh_params, &prime, &generator, priv_key->u.a.bitlen ))) -+ { -+ pgnutls_perror( ret ); -+ pgnutls_dh_params_deinit( dh_params ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ priv.size = peer.size = key_length; -+ priv.data = priv_key->u.a.privkey; -+ peer.data = peer_key->u.a.pubkey + sizeof(BCRYPT_DH_KEY_BLOB) + key_length * 2; -+ -+ if (memcmp((BCRYPT_DH_KEY_BLOB *)priv_key->u.a.pubkey + 1, -+ peer_key->u.a.pubkey + sizeof(BCRYPT_DH_KEY_BLOB), key_length * 2)) -+ { -+ ERR("peer DH paramaters do not match.\n"); -+ pgnutls_dh_params_deinit( dh_params ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ if ((ret = pgnutls_dh_compute_key( dh_params, &priv, NULL, &peer, &secret_datum ))) -+ { -+ ERR("Error computing shared key.\n"); -+ pgnutls_perror( ret ); -+ pgnutls_dh_params_deinit( dh_params ); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ TRACE("secret_datum.size %u, key_length %u.\n", secret_datum.size, key_length); -+ export_gnutls_datum( secret->data, key_length, &secret_datum, NULL ); -+ secret->data_len = key_length; -+ free( secret_datum.data ); -+ break; -+ } -+ -+ case ALG_ID_ECDH_P256: -+ FIXME("ECDH is not supported.\n"); -+ break; -+ -+ default: -+ ERR( "unhandled algorithm %u\n", priv_key->alg_id ); -+ return STATUS_INVALID_HANDLE; -+ } -+ return STATUS_SUCCESS; -+} -+ - const unixlib_entry_t __wine_unix_call_funcs[] = - { - gnutls_process_attach, -@@ -1807,7 +2021,8 @@ unixlib_entry_t __wine_unix_call_funcs[] = - key_export_ecc, - key_import_dsa_capi, - key_import_ecc, -- key_import_rsa -+ key_import_rsa, -+ key_secret_agreement, - }; - - #ifdef _WIN64 -diff --git a/include/bcrypt.h b/include/bcrypt.h -index a099f2f4b0e..7abcb50a43c 100644 ---- a/include/bcrypt.h -+++ b/include/bcrypt.h -@@ -62,6 +62,8 @@ typedef LONG NTSTATUS; - #define BCRYPT_OPAQUE_KEY_BLOB L"OpaqueKeyBlob" - #define BCRYPT_KEY_DATA_BLOB L"KeyDataBlob" - #define BCRYPT_AES_WRAP_KEY_BLOB L"Rfc3565KeyWrapBlob" -+#define BCRYPT_DH_PUBLIC_BLOB L"DHPUBLICBLOB" -+#define BCRYPT_DH_PRIVATE_BLOB L"DHPRIVATEBLOB" - #define BCRYPT_ECCPUBLIC_BLOB L"ECCPUBLICBLOB" - #define BCRYPT_ECCPRIVATE_BLOB L"ECCPRIVATEBLOB" - #define BCRYPT_RSAPUBLIC_BLOB L"RSAPUBLICBLOB" -@@ -81,6 +83,7 @@ typedef LONG NTSTATUS; - #define BCRYPT_3DES_ALGORITHM L"3DES" - #define BCRYPT_AES_ALGORITHM L"AES" - #define BCRYPT_DES_ALGORITHM L"DES" -+#define BCRYPT_DH_ALGORITHM L"DH" - #define BCRYPT_DSA_ALGORITHM L"DSA" - #define BCRYPT_ECDH_P256_ALGORITHM L"ECDH_P256" - #define BCRYPT_ECDSA_P256_ALGORITHM L"ECDSA_P256" -@@ -111,6 +114,8 @@ typedef LONG NTSTATUS; - #define BCRYPT_KDF_TLS_PRF L"TLS_PRF" - #define BCRYPT_KDF_SP80056A_CONCAT L"SP800_56A_CONCAT" - #define BCRYPT_KDF_RAW_SECRET L"TRUNCATE" -+ -+#define BCRYPT_DH_PARAMETERS L"DHParameters" - #else - static const WCHAR BCRYPT_ALGORITHM_NAME[] = {'A','l','g','o','r','i','t','h','m','N','a','m','e',0}; - static const WCHAR BCRYPT_AUTH_TAG_LENGTH[] = {'A','u','t','h','T','a','g','L','e','n','g','t','h',0}; -@@ -133,6 +138,8 @@ static const WCHAR BCRYPT_SIGNATURE_LENGTH[] = {'S','i','g','n','a','t','u','r', - static const WCHAR BCRYPT_OPAQUE_KEY_BLOB[] = {'O','p','a','q','u','e','K','e','y','B','l','o','b',0}; - static const WCHAR BCRYPT_KEY_DATA_BLOB[] = {'K','e','y','D','a','t','a','B','l','o','b',0}; - static const WCHAR BCRYPT_AES_WRAP_KEY_BLOB[] = {'R','f','c','3','5','6','5','K','e','y','W','r','a','p','B','l','o','b',0}; -+static const WCHAR BCRYPT_DH_PUBLIC_BLOB[] = {'D','H','P','U','B','L','I','C','B','L','O','B',0}; -+static const WCHAR BCRYPT_DH_PRIVATE_BLOB[] = {'D','H','P','R','I','V','A','T','E','B','L','O','B',0}; - static const WCHAR BCRYPT_ECCPUBLIC_BLOB[] = {'E','C','C','P','U','B','L','I','C','B','L','O','B',0}; - static const WCHAR BCRYPT_ECCPRIVATE_BLOB[] = {'E','C','C','P','R','I','V','A','T','E','B','L','O','B',0}; - static const WCHAR BCRYPT_RSAPUBLIC_BLOB[] = {'R','S','A','P','U','B','L','I','C','B','L','O','B',0}; -@@ -154,6 +161,7 @@ static const WCHAR MS_PLATFORM_CRYPTO_PROVIDER[] = \ - static const WCHAR BCRYPT_3DES_ALGORITHM[] = {'3','D','E','S',0}; - static const WCHAR BCRYPT_AES_ALGORITHM[] = {'A','E','S',0}; - static const WCHAR BCRYPT_DES_ALGORITHM[] = {'D','E','S',0}; -+static const WCHAR BCRYPT_DH_ALGORITHM[] = {'D','H',0}; - static const WCHAR BCRYPT_DSA_ALGORITHM[] = {'D','S','A',0}; - static const WCHAR BCRYPT_ECDH_P256_ALGORITHM[] = {'E','C','D','H','_','P','2','5','6',0}; - static const WCHAR BCRYPT_ECDSA_P256_ALGORITHM[] = {'E','C','D','S','A','_','P','2','5','6',0}; -@@ -184,6 +192,7 @@ static const WCHAR BCRYPT_KDF_HMAC[] = {'H','M','A','C',0}; - static const WCHAR BCRYPT_KDF_TLS_PRF[] = {'T','L','S','_','P','R','F',0}; - static const WCHAR BCRYPT_KDF_SP80056A_CONCAT[] = {'S','P','8','0','0','_','5','6','A','_','C','O','N','C','A','T',0}; - static const WCHAR BCRYPT_KDF_RAW_SECRET[] = {'T','R','U','N','C','A','T','E',0}; -+#define BCRYPT_DH_PARAMETERS u"DHParameters" - #endif - - #define BCRYPT_ECDSA_PUBLIC_P256_MAGIC 0x31534345 -@@ -298,6 +307,15 @@ typedef struct _BCRYPT_DSA_KEY_BLOB - #define BCRYPT_DSA_PUBLIC_MAGIC_V2 0x32425044 - #define BCRYPT_DSA_PRIVATE_MAGIC_V2 0x32565044 - -+typedef struct _BCRYPT_DH_KEY_BLOB -+{ -+ ULONG dwMagic; -+ ULONG cbKey; -+} BCRYPT_DH_KEY_BLOB, *PBCRYPT_DH_KEY_BLOB; -+ -+#define BCRYPT_DH_PUBLIC_MAGIC 0x42504844 -+#define BCRYPT_DH_PRIVATE_MAGIC 0x56504844 -+ - typedef enum - { - DSA_HASH_ALGORITHM_SHA1, -@@ -357,6 +375,15 @@ typedef struct _BCRYPT_KEY_DATA_BLOB_HEADER - ULONG cbKeyData; - } BCRYPT_KEY_DATA_BLOB_HEADER, *PBCRYPT_KEY_DATA_BLOB_HEADER; - -+typedef struct _BCRYPT_DH_PARAMETER_HEADER -+{ -+ ULONG cbLength; -+ ULONG dwMagic; -+ ULONG cbKeyLength; -+} BCRYPT_DH_PARAMETER_HEADER; -+ -+#define BCRYPT_DH_PARAMETERS_MAGIC 0x4d504844 -+ - #define KDF_HASH_ALGORITHM 0x00000000 - #define KDF_SECRET_PREPEND 0x00000001 - #define KDF_SECRET_APPEND 0x00000002 -@@ -386,6 +413,8 @@ typedef PVOID BCRYPT_HANDLE; - typedef PVOID BCRYPT_HASH_HANDLE; - typedef PVOID BCRYPT_SECRET_HANDLE; - -+#define BCRYPT_NO_KEY_VALIDATION 0x00000008 -+ - /* Flags for BCryptGenRandom */ - #define BCRYPT_RNG_USE_ENTROPY_IN_BUFFER 0x00000001 - #define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002 --- -2.31.1 - -From f1ebd91fae89bbf76c0e574a37685c11b78dcbd5 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 9 Dec 2020 20:10:13 +0300 -Subject: [PATCH 2/6] bcrypt: Implement BCryptDeriveKey() for _KDF_RAW_SECRET. - -Extracted from the patch implementing ECDH on top of gcrypt by Derek Lesho. ---- - dlls/bcrypt/bcrypt_main.c | 27 +++++++++++++++++++++++++-- - 1 file changed, 25 insertions(+), 2 deletions(-) - -diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c -index 889f6ce85ea..48910aafe3c 100644 ---- a/dlls/bcrypt/bcrypt_main.c -+++ b/dlls/bcrypt/bcrypt_main.c -@@ -2237,12 +2237,35 @@ NTSTATUS WINAPI BCryptDeriveKey(BCRYPT_SECRET_HANDLE handle, LPCWSTR kdf, BCrypt - { - struct secret *secret = handle; - -- FIXME( "%p, %s, %p, %p, %lu, %p, %#lx\n", secret, debugstr_w(kdf), parameter, derived, derived_size, result, flags ); -+ TRACE( "%p, %s, %p, %p, %lu, %p, %#lx\n", secret, debugstr_w(kdf), parameter, derived, derived_size, result, flags ); - - if (!secret || secret->hdr.magic != MAGIC_SECRET) return STATUS_INVALID_HANDLE; - if (!kdf) return STATUS_INVALID_PARAMETER; - -- return STATUS_INTERNAL_ERROR; -+ if (flags) FIXME("flags ignored: %#lx\n", flags); -+ -+ if (!(lstrcmpW( kdf, BCRYPT_KDF_RAW_SECRET ))) -+ { -+ ULONG secret_length = secret->data_len; -+ unsigned int i;; -+ -+ if (!derived) -+ { -+ *result = secret_length; -+ return STATUS_SUCCESS; -+ } -+ -+ /* outputs in little endian for some reason */ -+ for (i = 0; i < min(secret_length, derived_size); i++) -+ { -+ derived[i] = secret->data[secret_length - i - 1]; -+ } -+ -+ *result = i; -+ return STATUS_SUCCESS; -+ } -+ FIXME( "Derivation function %s not supported.\n", debugstr_w(kdf) ); -+ return STATUS_NOT_IMPLEMENTED; - } - - BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) --- -2.31.1 - -From 0d0f5851874c79c1ceb7fe7cfb84738d754d73a9 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 7 Jan 2020 14:22:49 -0600 -Subject: [PATCH 3/6] bcrypt: Implement BCRYPT_KDF_HASH. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47699 -Signed-off-by: Derek Lesho ---- - dlls/bcrypt/bcrypt_main.c | 107 ++++++++++++++++++++++++++++++++++++- - 1 file changed, 107 insertions(+) - -diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c -index 48910aafe3c..e1742fa7a01 100644 ---- a/dlls/bcrypt/bcrypt_main.c -+++ b/dlls/bcrypt/bcrypt_main.c -@@ -2244,7 +2244,112 @@ NTSTATUS WINAPI BCryptDeriveKey(BCRYPT_SECRET_HANDLE handle, LPCWSTR kdf, BCrypt - - if (flags) FIXME("flags ignored: %#lx\n", flags); - -- if (!(lstrcmpW( kdf, BCRYPT_KDF_RAW_SECRET ))) -+ if (!(lstrcmpW( kdf, BCRYPT_KDF_HASH ))) -+ { -+ unsigned int i; -+ BCryptBuffer *hash_algorithm = NULL; -+ BCryptBuffer *secret_prepend = NULL; -+ BCryptBuffer *secret_append = NULL; -+ enum alg_id hash_alg_id; -+ ULONG hash_length; -+ struct hash_impl hash; -+ NTSTATUS status; -+ -+ if (parameter) -+ { -+ for (i = 0; i < parameter->cBuffers; i++) -+ { -+ BCryptBuffer *cur_buffer = ¶meter->pBuffers[i]; -+ switch(cur_buffer->BufferType) -+ { -+ case KDF_HASH_ALGORITHM: -+ if (hash_algorithm) -+ FIXME("Duplicate KDF_HASH_ALGORITHM, untested\n"); -+ hash_algorithm = cur_buffer; -+ break; -+ case KDF_SECRET_PREPEND: -+ if (secret_prepend) -+ FIXME("Multiple prefixes unsupported\n"); -+ secret_prepend = cur_buffer; -+ break; -+ case KDF_SECRET_APPEND: -+ if (secret_append) -+ FIXME("Multiple suffixes unsupported\n"); -+ secret_append = cur_buffer; -+ break; -+ default: -+ FIXME("Unsupported BCRYPT_KDF_HASH parameter type %x\n", cur_buffer->BufferType); -+ break; -+ } -+ } -+ } -+ -+ if (!(hash_algorithm)) -+ hash_alg_id = ALG_ID_SHA1; -+ else -+ { -+ for (i = 0; i < ARRAY_SIZE( builtin_algorithms ); i++) -+ { -+ if (!lstrcmpW( hash_algorithm->pvBuffer, builtin_algorithms[i].name)) -+ { -+ hash_alg_id = i; -+ break; -+ } -+ } -+ if (i == ARRAY_SIZE(builtin_algorithms)) -+ { -+ WARN("Algorithm %s not found\n", debugstr_w(hash_algorithm->pvBuffer)); -+ return STATUS_NOT_SUPPORTED; -+ } -+ if (builtin_algorithms[hash_alg_id].class != BCRYPT_HASH_INTERFACE) -+ { -+ WARN("Incorrect class %u\n", builtin_algorithms[hash_alg_id].class); -+ return STATUS_NOT_SUPPORTED; -+ } -+ } -+ -+ hash_length = builtin_algorithms[hash_alg_id].hash_length; -+ -+ if (!derived) -+ { -+ *result = hash_length; -+ return STATUS_SUCCESS; -+ } -+ -+ if ((status = hash_init(&hash, hash_alg_id))) -+ { -+ return status; -+ } -+ -+ if (secret_prepend) -+ { -+ hash_update(&hash, hash_alg_id, secret_prepend->pvBuffer, secret_prepend->cbBuffer); -+ } -+ -+ hash_update(&hash, hash_alg_id, secret->data, secret->data_len); -+ -+ if (secret_append) -+ { -+ hash_update(&hash, hash_alg_id, secret_append->pvBuffer, secret_append->cbBuffer); -+ } -+ -+ if (derived_size >= hash_length) -+ { -+ hash_finish(&hash, hash_alg_id, derived, derived_size); -+ *result = hash_length; -+ } -+ else -+ { -+ UCHAR *output = malloc(hash_length); -+ hash_finish(&hash, hash_alg_id, output, hash_length); -+ memcpy(derived, output, derived_size); -+ free(output); -+ *result = derived_size; -+ } -+ -+ return STATUS_SUCCESS; -+ } -+ else if (!(lstrcmpW( kdf, BCRYPT_KDF_RAW_SECRET ))) - { - ULONG secret_length = secret->data_len; - unsigned int i;; -2.31.1 - -From f56b6fb6a307d79609e35d464816b0d7295b80dd Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 11 Dec 2020 04:07:13 +0300 -Subject: [PATCH 5/6] bcrypt: Reimplement DH using libgmp instead of private - gnutls functions. - ---- - configure | 97 +++++++++++++ - configure.ac | 8 ++ - dlls/bcrypt/Makefile.in | 2 +- - dlls/bcrypt/gnutls.c | 298 +++++++++++++++++++++++++++++----------- - include/config.h.in | 6 + - 5 files changed, 329 insertions(+), 82 deletions(-) - -diff --git a/configure b/configure -index 8cc68a5cd55..9e70f3a9ea8 100755 ---- a/configure -+++ b/configure -@@ -687,6 +687,8 @@ USB_LIBS - USB_CFLAGS - SANE_LIBS - SANE_CFLAGS -+GMP_LIBS -+GMP_CFLAGS - GNUTLS_LIBS - GNUTLS_CFLAGS - HAL_LIBS -@@ -1929,6 +1931,8 @@ HAL_CFLAGS - HAL_LIBS - GNUTLS_CFLAGS - GNUTLS_LIBS -+GMP_CFLAGS -+GMP_LIBS - SANE_CFLAGS - SANE_LIBS - USB_CFLAGS -@@ -2705,6 +2709,8 @@ Some influential environment variables: - GNUTLS_CFLAGS - C compiler flags for gnutls, overriding pkg-config - GNUTLS_LIBS Linker flags for gnutls, overriding pkg-config -+ GMP_CFLAGS C compiler flags for gmp, overriding pkg-config -+ GMP_LIBS Linker flags for gmp, overriding pkg-config - SANE_CFLAGS C compiler flags for sane-backends, overriding pkg-config - SANE_LIBS Linker flags for sane-backends, overriding pkg-config - USB_CFLAGS C compiler flags for libusb-1.0, overriding pkg-config -@@ -13629,6 +13635,95 @@ esac - - fi - -+if test "x$with_gnutls" != "xno" -+then -+ if ${GMP_CFLAGS:+false} :; then : -+ if ${PKG_CONFIG+:} false; then : -+ GMP_CFLAGS=`$PKG_CONFIG --cflags gmp 2>/dev/null` -+fi -+fi -+ -+if ${GMP_LIBS:+false} :; then : -+ if ${PKG_CONFIG+:} false; then : -+ GMP_LIBS=`$PKG_CONFIG --libs gmp 2>/dev/null` -+fi -+fi -+ -+GMP_LIBS=${GMP_LIBS:-"-lgmp"} -+$as_echo "$as_me:${as_lineno-$LINENO}: gmp cflags: $GMP_CFLAGS" >&5 -+$as_echo "$as_me:${as_lineno-$LINENO}: gmp libs: $GMP_LIBS" >&5 -+ac_save_CPPFLAGS=$CPPFLAGS -+CPPFLAGS="$CPPFLAGS $GMP_CFLAGS" -+for ac_header in gmp.h -+do : -+ ac_fn_c_check_header_mongrel "$LINENO" "gmp.h" "ac_cv_header_gmp_h" "$ac_includes_default" -+if test "x$ac_cv_header_gmp_h" = xyes; then : -+ cat >>confdefs.h <<_ACEOF -+#define HAVE_GMP_H 1 -+_ACEOF -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lgmp" >&5 -+$as_echo_n "checking for -lgmp... " >&6; } -+if ${ac_cv_lib_soname_gmp+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_soname_save_LIBS=$LIBS -+LIBS="-lgmp $GMP_LIBS $LIBS" -+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char __gmpz_init (); -+int -+main () -+{ -+return __gmpz_init (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ case "$LIBEXT" in -+ dll) ac_cv_lib_soname_gmp=`$ac_cv_path_LDD conftest.exe | grep "gmp" | sed -e "s/dll.*/dll/"';2,$d'` ;; -+ dylib) ac_cv_lib_soname_gmp=`$OTOOL -L conftest$ac_exeext | grep "libgmp-*\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libgmp-*\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; -+ *) ac_cv_lib_soname_gmp=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libgmp-*\\.$LIBEXT" | sed -e "s/^.*\\[\\(libgmp-*\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` -+ if ${ac_cv_lib_soname_gmp:+false} :; then : -+ ac_cv_lib_soname_gmp=`$LDD conftest$ac_exeext | grep "libgmp-*\\.$LIBEXT" | sed -e "s/^.*\(libgmp-*\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` -+fi ;; -+ esac -+else -+ ac_cv_lib_soname_gmp= -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+ LIBS=$ac_check_soname_save_LIBS -+fi -+if ${ac_cv_lib_soname_gmp:+false} :; then : -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 -+$as_echo "not found" >&6; } -+ GMP_CFLAGS="" -+else -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_gmp" >&5 -+$as_echo "$ac_cv_lib_soname_gmp" >&6; } -+ -+cat >>confdefs.h <<_ACEOF -+#define SONAME_LIBGMP "$ac_cv_lib_soname_gmp" -+_ACEOF -+ -+ -+fi -+fi -+ -+done -+ -+CPPFLAGS=$ac_save_CPPFLAGS -+ -+fi -+ - if test "x$with_sane" != "xno" - then - if ${SANE_CFLAGS:+false} :; then : -@@ -19635,6 +19730,8 @@ HAL_CFLAGS = $HAL_CFLAGS - HAL_LIBS = $HAL_LIBS - GNUTLS_CFLAGS = $GNUTLS_CFLAGS - GNUTLS_LIBS = $GNUTLS_LIBS -+GMP_CFLAGS = $GMP_CFLAGS -+GMP_LIBS = $GMP_LIBS - SANE_CFLAGS = $SANE_CFLAGS - SANE_LIBS = $SANE_LIBS - USB_CFLAGS = $USB_CFLAGS -diff --git a/configure.ac b/configure.ac -index db8f0fea4fa..577a995a57d 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1391,6 +1391,14 @@ fi - WINE_WARNING_WITH(gnutls,[test "x$ac_cv_lib_soname_gnutls" = "x"], - [libgnutls ${notice_platform}development files not found, no schannel support.]) - -+dnl **** Check for libgmp **** -+if test "x$with_gnutls" != "xno" -+then -+ WINE_PACKAGE_FLAGS(GMP,[gmp],[-lgmp],,, -+ [AC_CHECK_HEADERS([gmp.h], -+ [WINE_CHECK_SONAME(gmp,__gmpz_init,,[GMP_CFLAGS=""],[$GMP_LIBS],[[libgmp-*]])])]) -+fi -+ - dnl **** Check for SANE **** - if test "x$with_sane" != "xno" - then -diff --git a/dlls/bcrypt/Makefile.in b/dlls/bcrypt/Makefile.in -index 9f3510361c4..c5a0e202929 100644 ---- a/dlls/bcrypt/Makefile.in -+++ b/dlls/bcrypt/Makefile.in -@@ -2,7 +2,7 @@ MODULE = bcrypt.dll - IMPORTS = advapi32 - IMPORTLIB = bcrypt - UNIXLIB = bcrypt.so --EXTRAINCL = $(GNUTLS_CFLAGS) -+EXTRAINCL = $(GNUTLS_CFLAGS) $(GMP_CFLAGS) - - C_SRCS = \ - bcrypt_main.c \ -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index a751310c883..66560c56358 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -47,6 +47,13 @@ - #include "wine/debug.h" - #include "wine/unicode.h" - -+#include -+ -+#ifdef HAVE_GMP_H -+#include -+#endif -+ -+ - WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); - WINE_DECLARE_DEBUG_CHANNEL(winediag); - -@@ -80,8 +87,6 @@ static union key_data *key_data( struct key *key ) - return (union key_data *)key->private; - } - --static BOOL dh_supported; -- - /* Not present in gnutls version < 3.0 */ - static int (*pgnutls_cipher_tag)(gnutls_cipher_hd_t, void *, size_t); - static int (*pgnutls_cipher_add_auth)(gnutls_cipher_hd_t, const void *, size_t); -@@ -124,11 +129,9 @@ static int (*pgnutls_dh_params_import_raw2)(gnutls_dh_params_t dh_params, const - const gnutls_datum_t * generator, unsigned key_bits); - static int (*pgnutls_dh_params_export_raw)(gnutls_dh_params_t params, gnutls_datum_t * prime, - gnutls_datum_t * generator, unsigned int *bits); --static int (*pgnutls_dh_generate_key)(gnutls_dh_params_t dh_params, gnutls_datum_t *priv_key, gnutls_datum_t *pub_key); --static int (*pgnutls_dh_compute_key)(gnutls_dh_params_t dh_params, const gnutls_datum_t *priv_key, -- const gnutls_datum_t *pub_key, const gnutls_datum_t *peer_key, gnutls_datum_t *Z); - - static void *libgnutls_handle; -+ - #define MAKE_FUNCPTR(f) static typeof(f) * p##f - MAKE_FUNCPTR(gnutls_cipher_decrypt2); - MAKE_FUNCPTR(gnutls_cipher_deinit); -@@ -146,6 +149,22 @@ MAKE_FUNCPTR(gnutls_privkey_init); - MAKE_FUNCPTR(gnutls_privkey_sign_hash); - MAKE_FUNCPTR(gnutls_pubkey_deinit); - MAKE_FUNCPTR(gnutls_pubkey_init); -+ -+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) -+static BOOL dh_supported; -+static void *libgmp_handle; -+ -+MAKE_FUNCPTR(mpz_init); -+MAKE_FUNCPTR(mpz_clear); -+MAKE_FUNCPTR(mpz_cmp); -+MAKE_FUNCPTR(_mpz_cmp_ui); -+MAKE_FUNCPTR(mpz_sizeinbase); -+MAKE_FUNCPTR(mpz_import); -+MAKE_FUNCPTR(mpz_export); -+MAKE_FUNCPTR(mpz_mod); -+MAKE_FUNCPTR(mpz_powm); -+MAKE_FUNCPTR(mpz_sub_ui); -+#endif - #undef MAKE_FUNCPTR - - static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size) -@@ -287,6 +306,37 @@ static NTSTATUS gnutls_process_attach( void *args ) - LOAD_FUNCPTR(gnutls_pubkey_init); - #undef LOAD_FUNCPTR - -+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) -+#define LOAD_FUNCPTR_STR(f) #f -+#define LOAD_FUNCPTR(f) \ -+ if (!(p##f = dlsym( libgmp_handle, LOAD_FUNCPTR_STR(f) ))) \ -+ { \ -+ ERR( "failed to load %s\n", LOAD_FUNCPTR_STR(f) ); \ -+ goto fail; \ -+ } -+ -+ if ((libgmp_handle = dlopen( SONAME_LIBGMP, RTLD_NOW ))) -+ { -+ LOAD_FUNCPTR(mpz_init); -+ LOAD_FUNCPTR(mpz_clear); -+ LOAD_FUNCPTR(mpz_cmp); -+ LOAD_FUNCPTR(_mpz_cmp_ui); -+ LOAD_FUNCPTR(mpz_sizeinbase); -+ LOAD_FUNCPTR(mpz_import); -+ LOAD_FUNCPTR(mpz_export); -+ LOAD_FUNCPTR(mpz_mod); -+ LOAD_FUNCPTR(mpz_powm); -+ LOAD_FUNCPTR(mpz_sub_ui); -+ } -+ else -+ { -+ ERR_(winediag)( "failed to load libgmp, no support for DH\n" ); -+ goto fail; -+ } -+#undef LOAD_FUNCPTR -+#undef LOAD_FUNCPTR_STR -+#endif -+ - #define LOAD_FUNCPTR_OPT(f) \ - if (!(p##f = dlsym( libgnutls_handle, #f ))) \ - { \ -@@ -336,19 +386,13 @@ static NTSTATUS gnutls_process_attach( void *args ) - { - WARN("gnutls_dh_params_export_raw not found\n"); - } -- if (!(pgnutls_dh_generate_key = dlsym( libgnutls_handle, "_gnutls_dh_generate_key" )) -- && !(pgnutls_dh_generate_key = dlsym( libgnutls_handle, "gnutls_dh_generate_key" ))) -- { -- WARN("gnutls_dh_generate_key not found\n"); -- } -- if (!(pgnutls_dh_compute_key = dlsym( libgnutls_handle, "_gnutls_dh_compute_key" )) -- && !(pgnutls_dh_compute_key = dlsym( libgnutls_handle, "gnutls_dh_compute_key" ))) -- { -- WARN("gnutls_dh_compute_key not found\n"); -- } - -+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) - dh_supported = pgnutls_dh_params_init && pgnutls_dh_params_generate2 && pgnutls_dh_params_import_raw2 -- && pgnutls_dh_generate_key && pgnutls_dh_compute_key; -+ && libgmp_handle; -+#else -+ ERR_(winediag)("Compiled without DH support.\n"); -+#endif - - if (TRACE_ON( bcrypt )) - { -@@ -361,6 +405,14 @@ static NTSTATUS gnutls_process_attach( void *args ) - fail: - dlclose( libgnutls_handle ); - libgnutls_handle = NULL; -+ -+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) -+ if (libgmp_handle) -+ { -+ dlclose( libgmp_handle ); -+ libgmp_handle = NULL; -+ } -+#endif - return STATUS_DLL_NOT_FOUND; - } - -@@ -373,6 +425,11 @@ static NTSTATUS gnutls_process_detach( void *args ) - libgnutls_handle = NULL; - } - return STATUS_SUCCESS; -+ -+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) -+ dlclose( libgmp_handle ); -+ libgmp_handle = NULL; -+#endif - } - - struct buffer -@@ -882,12 +939,61 @@ static NTSTATUS export_gnutls_pubkey_dsa_capi( gnutls_privkey_t gnutls_key, cons - return STATUS_SUCCESS; - } - -+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) -+static NTSTATUS CDECL gen_random(void *buffer, unsigned int length) -+{ -+ unsigned int read_size; -+ int dev_random; -+ -+ dev_random = open("/dev/urandom", O_RDONLY); -+ if (dev_random == -1) -+ { -+ FIXME("couldn't open /dev/urandom.\n"); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ read_size = read(dev_random, buffer, length); -+ close(dev_random); -+ if (read_size != length) -+ { -+ FIXME("Could not read from /dev/urandom."); -+ return STATUS_INTERNAL_ERROR; -+ } -+ return STATUS_SUCCESS; -+} -+ -+static void import_mpz(mpz_t value, const void *input, unsigned int length) -+{ -+ pmpz_import(value, length, 1, 1, 0, 0, input); -+} -+ -+static void export_mpz(void *output, unsigned int length, const mpz_t value) -+{ -+ size_t export_length; -+ unsigned int offset; -+ -+ export_length = (pmpz_sizeinbase(value, 2) + 7) / 8; -+ assert(export_length <= length); -+ offset = length - export_length; -+ memset(output, 0, offset); -+ pmpz_export((BYTE *)output + offset, &export_length, 1, 1, 0, 0, value); -+ if (!export_length) -+ { -+ ERR("Zero export length, value bits %u.\n", (unsigned)pmpz_sizeinbase(value, 2)); -+ memset((BYTE *)output + offset, 0, length - offset); -+ } -+ else -+ { -+ assert(export_length + offset == length); -+ } -+} -+ - static NTSTATUS CDECL key_dh_generate( struct key *key ) - { -- gnutls_datum_t prime, generator, privkey, pubkey; - NTSTATUS status = STATUS_SUCCESS; -- gnutls_dh_params_t dh_params; -+ mpz_t p, psub1, g, privkey, pubkey; - ULONG key_length; -+ unsigned int i; - int ret; - - if (!dh_supported) -@@ -896,22 +1002,18 @@ static NTSTATUS CDECL key_dh_generate( struct key *key ) - return STATUS_NOT_IMPLEMENTED; - } - -- if ((ret = pgnutls_dh_params_init( &dh_params ))) -- { -- pgnutls_perror( ret ); -- return STATUS_INTERNAL_ERROR; -- } -- - key_length = key->u.a.bitlen / 8; - - if (!(key->u.a.flags & KEY_FLAG_DH_PARAMS_SET)) - { -- /* Generate parameters, export and then import them back below. -- * The bitlen in dh parameters (which is later used for keys generation) -- * is not set to gnutls_dh_params_generate2 'bits' parameter as one -- * could expect. gnutls_dh_params_generate2 generates 'q' (which is not -- * actually needed for DH) with the estimated bit length and then -- * sets the bit length to the 'q' bitlength. */ -+ gnutls_datum_t prime, generator; -+ gnutls_dh_params_t dh_params; -+ -+ if ((ret = pgnutls_dh_params_init( &dh_params ))) -+ { -+ pgnutls_perror( ret ); -+ return STATUS_INTERNAL_ERROR; -+ } - if ((ret = pgnutls_dh_params_generate2( dh_params, key->u.a.bitlen ))) - { - pgnutls_perror( ret ); -@@ -924,6 +1026,8 @@ static NTSTATUS CDECL key_dh_generate( struct key *key ) - pgnutls_dh_params_deinit( dh_params ); - return STATUS_INTERNAL_ERROR; - } -+ pgnutls_dh_params_deinit( dh_params ); -+ - - export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1), key_length, &prime, NULL ); - export_gnutls_datum( (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1) + key_length, -@@ -934,34 +1038,73 @@ static NTSTATUS CDECL key_dh_generate( struct key *key ) - key->u.a.flags |= KEY_FLAG_DH_PARAMS_SET; - } - -- prime.size = generator.size = key_length; -- prime.data = (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1); -- generator.data = (BYTE *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1) + key_length; -+ pmpz_init(p); -+ pmpz_init(psub1); -+ pmpz_init(g); -+ pmpz_init(pubkey); -+ pmpz_init(privkey); - -- if ((ret = pgnutls_dh_params_import_raw2( dh_params, &prime, &generator, key->u.a.bitlen ))) -+ import_mpz(p, (BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1, key_length); -+ if (!mpz_sgn(p)) - { -- pgnutls_perror( ret ); -- pgnutls_dh_params_deinit( dh_params ); -- return STATUS_INTERNAL_ERROR; -+ ERR("Got zero modulus.\n"); -+ status = STATUS_INTERNAL_ERROR; -+ goto done; - } -+ pmpz_sub_ui(psub1, p, 1); - -- if ((ret = pgnutls_dh_generate_key( dh_params, &privkey, &pubkey ))) -+ import_mpz(g, (UCHAR *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1) + key_length, key_length); -+ if (!mpz_sgn(g)) - { -- pgnutls_perror( ret ); -- pgnutls_dh_params_deinit( dh_params ); -- return STATUS_INTERNAL_ERROR; -+ ERR("Got zero generator.\n"); -+ status = STATUS_INTERNAL_ERROR; -+ goto done; -+ } -+ for (i = 0; i < 3; ++i) -+ { -+ if ((status = gen_random(key->u.a.privkey, key_length))) -+ { -+ goto done; -+ } -+ import_mpz(privkey, key->u.a.privkey, key_length); -+ -+ pmpz_mod(privkey, privkey, p); -+ pmpz_powm(pubkey, g, privkey, p); -+ if (p_mpz_cmp_ui(pubkey, 1)) -+ break; -+ } -+ if (i == 3) -+ { -+ ERR("Could not generate key after 3 iterations.\n"); -+ status = STATUS_INTERNAL_ERROR; -+ goto done; - } - -- export_gnutls_datum( (BYTE *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1) + 2 * key_length, -- key_length, &pubkey, NULL ); -- export_gnutls_datum( key->u.a.privkey, key_length, &privkey, NULL); -+ if (pmpz_cmp(pubkey, psub1) >= 0) -+ { -+ ERR("pubkey > p - 1.\n"); -+ status = STATUS_INTERNAL_ERROR; -+ goto done; -+ } - -- free( privkey.data ); -- free( pubkey.data ); -- pgnutls_dh_params_deinit( dh_params ); -+ export_mpz(key->u.a.privkey, key_length, privkey); -+ export_mpz((UCHAR *)((BCRYPT_DH_KEY_BLOB *)key->u.a.pubkey + 1) + 2 * key_length, key_length, pubkey); - -+done: -+ pmpz_clear(psub1); -+ pmpz_clear(p); -+ pmpz_clear(g); -+ pmpz_clear(pubkey); -+ pmpz_clear(privkey); - return status; - } -+#else -+static NTSTATUS CDECL key_dh_generate( struct key *key ) -+{ -+ ERR("Compiled without DH support.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+} -+#endif - - static NTSTATUS key_asymmetric_generate( void *args ) - { -@@ -1924,8 +2067,6 @@ static NTSTATUS key_secret_agreement( void *args ) - struct secret *secret; - struct key *priv_key; - struct key *peer_key; -- int ret; -- - priv_key = params->privkey; - peer_key = params->pubkey; - secret = params->secret; -@@ -1933,9 +2074,9 @@ static NTSTATUS key_secret_agreement( void *args ) - switch (priv_key->alg_id) - { - case ALG_ID_DH: -+#if defined(HAVE_GMP_H) && defined(SONAME_LIBGMP) - { -- gnutls_datum_t prime, generator, priv, peer, secret_datum; -- gnutls_dh_params_t dh_params; -+ mpz_t p, priv, peer, k; - ULONG key_length; - - if (!dh_supported) -@@ -1944,51 +2085,46 @@ static NTSTATUS key_secret_agreement( void *args ) - return STATUS_NOT_IMPLEMENTED; - } - -- if ((ret = pgnutls_dh_params_init( &dh_params ))) -- { -- pgnutls_perror( ret ); -- return STATUS_INTERNAL_ERROR; -- } -- - key_length = priv_key->u.a.bitlen / 8; - -- prime.size = generator.size = key_length; -- prime.data = (UCHAR *)((BCRYPT_DH_KEY_BLOB *)priv_key->u.a.pubkey + 1); -- generator.data = (BYTE *)((BCRYPT_DH_KEY_BLOB *)priv_key->u.a.pubkey + 1) + key_length; -- -- if ((ret = pgnutls_dh_params_import_raw2( dh_params, &prime, &generator, priv_key->u.a.bitlen ))) -- { -- pgnutls_perror( ret ); -- pgnutls_dh_params_deinit( dh_params ); -- return STATUS_INTERNAL_ERROR; -- } -- -- priv.size = peer.size = key_length; -- priv.data = priv_key->u.a.privkey; -- peer.data = peer_key->u.a.pubkey + sizeof(BCRYPT_DH_KEY_BLOB) + key_length * 2; -- - if (memcmp((BCRYPT_DH_KEY_BLOB *)priv_key->u.a.pubkey + 1, - peer_key->u.a.pubkey + sizeof(BCRYPT_DH_KEY_BLOB), key_length * 2)) - { - ERR("peer DH paramaters do not match.\n"); -- pgnutls_dh_params_deinit( dh_params ); - return STATUS_INTERNAL_ERROR; - } - -- if ((ret = pgnutls_dh_compute_key( dh_params, &priv, NULL, &peer, &secret_datum ))) -+ pmpz_init(p); -+ pmpz_init(priv); -+ pmpz_init(peer); -+ pmpz_init(k); -+ -+ import_mpz(p, (BCRYPT_DH_KEY_BLOB *)priv_key->u.a.pubkey + 1, key_length); -+ if (pmpz_sizeinbase(p, 2) < 2) - { -- ERR("Error computing shared key.\n"); -- pgnutls_perror( ret ); -- pgnutls_dh_params_deinit( dh_params ); -+ ERR("Invalid prime.\n"); -+ pmpz_clear(p); -+ pmpz_clear(priv); -+ pmpz_clear(peer); -+ pmpz_clear(k); - return STATUS_INTERNAL_ERROR; - } -- -- TRACE("secret_datum.size %u, key_length %u.\n", secret_datum.size, key_length); -- export_gnutls_datum( secret->data, key_length, &secret_datum, NULL ); -+ import_mpz(priv, priv_key->u.a.privkey, key_length); -+ import_mpz(peer, peer_key->u.a.pubkey + sizeof(BCRYPT_DH_KEY_BLOB) + key_length * 2, key_length); -+ pmpz_powm(k, peer, priv, p); -+ export_mpz(secret->data, key_length, k); - secret->data_len = key_length; -- free( secret_datum.data ); -+ -+ pmpz_clear(p); -+ pmpz_clear(priv); -+ pmpz_clear(peer); -+ pmpz_clear(k); - break; - } -+#else -+ ERR_(winediag)("Compiled without DH support.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+#endif - - case ALG_ID_ECDH_P256: - FIXME("ECDH is not supported.\n"); -diff --git a/include/config.h.in b/include/config.h.in -index 13f160c1b00..56adcf3cfe5 100644 ---- a/include/config.h.in -+++ b/include/config.h.in -@@ -135,6 +135,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_GETTEXT_PO_H - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_GMP_H -+ - /* Define to 1 if you have the `gnutls_cipher_init' function. */ - #undef HAVE_GNUTLS_CIPHER_INIT - -@@ -995,6 +998,9 @@ - /* Define to the soname of the libGLESv2 library. */ - #undef SONAME_LIBGLESV2 - -+/* Define to the soname of the libgmp library. */ -+#undef SONAME_LIBGMP -+ - /* Define to the soname of the libgnutls library. */ - #undef SONAME_LIBGNUTLS - --- -2.31.1 - diff --git a/patches/proton/56-proton-12_disable_libglesv2_for_nw.js.patch b/patches/proton/56-proton-12_disable_libglesv2_for_nw.js.patch deleted file mode 100644 index e02adddce..000000000 --- a/patches/proton/56-proton-12_disable_libglesv2_for_nw.js.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 5848899423dbbf763997577e476cf630689c59c6 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Tue, 21 Sep 2021 12:47:43 +0300 -Subject: [PATCH] wine.inf: Use native xinput1_3 for WRC 8, 9 and 10. - -WRC games, when run in a win10 prefix, try to load UWP/xinput1_3.dll -that ships with the games. It seems to be mostly-compatible xinput -implementation built on top of windows.gaming.input.dll. - -However if we try to replace it with the builtin the game crashes -(that's the "mostly-compatible" part), so we need this override. - -Since our windows.gaming.input.dll implementation is just a stub -controllers other than steering wheels (which are handled through -dinput) do not work. - -It's possible to make the controllers work in the meantime by switching -the prefix to win7 and adding `WINEDLLOVERRIDES="xinput1_3=b"`, as on -win7 the game uses the regular xinput and is fine with our builtin. - -Includes contributions by Sven Arvidsson. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51643 -Link: https://github.com/ValveSoftware/wine/pull/121 -CW-Bug-Id: #19337 ---- - loader/wine.inf.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 644a2fcce1d..6bf5d49c730 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4236,6 +4236,9 @@ HKCU,Software\Wine\AppDefaults\NFS16.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\ShadowOfWar.exe\DllOverrides,"amd_ags_x64",,"" - HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\WRC8.exe\DllOverrides,"xinput1_3",,"native" -+HKCU,Software\Wine\AppDefaults\WRC9.exe\DllOverrides,"xinput1_3",,"native" -+HKCU,Software\Wine\AppDefaults\WRC10.exe\DllOverrides,"xinput1_3",,"native" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" -From 13ac81ffd075d9e92486a395be9cfe822562e718 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 6 Oct 2021 16:48:56 +0300 -Subject: [PATCH] wine.inf: HACK: Disable libglesv2 for Paradox launcher. - -CW-Bug-ID: #19501 ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 1cfe19dace6..07d2a576501 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4237,6 +4237,7 @@ HKCU,Software\Wine\AppDefaults\DIRT5.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\WRC8.exe\DllOverrides,"xinput1_3",,"native" - HKCU,Software\Wine\AppDefaults\WRC9.exe\DllOverrides,"xinput1_3",,"native" - HKCU,Software\Wine\AppDefaults\WRC10.exe\DllOverrides,"xinput1_3",,"native" -+HKCU,Software\Wine\AppDefaults\Paradox Launcher.exe\DllOverrides,"libglesv2",,"disabled" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" -From 77fd28cba7764a2dafd1659be87aedb62437e4db Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Mon, 11 Oct 2021 19:36:10 +0300 -Subject: [PATCH] wine.inf: HACK: Disable winusb for Nickelodeon All-Star - Brawl. - -The DLL is just a stub and the game tries to use it for some more exotic -controller handling. It works without it. - -CW-Bug-Id: #19533 ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 07d2a576501..900f172b325 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4238,6 +4238,7 @@ HKCU,Software\Wine\AppDefaults\WRC8.exe\DllOverrides,"xinput1_3",,"native" - HKCU,Software\Wine\AppDefaults\WRC9.exe\DllOverrides,"xinput1_3",,"native" - HKCU,Software\Wine\AppDefaults\WRC10.exe\DllOverrides,"xinput1_3",,"native" - HKCU,Software\Wine\AppDefaults\Paradox Launcher.exe\DllOverrides,"libglesv2",,"disabled" -+HKCU,Software\Wine\AppDefaults\Nickelodeon All-Star Brawl.exe\DllOverrides,"winusb",,"disabled" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" -From 3e7c7f8f7e5a0945a2ba00afeda51e037758a4ac Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Fri, 15 Oct 2021 18:17:27 +0300 -Subject: [PATCH] wine.inf: Disable libglesv2 for nw.js. - -It's Chromium based and doesn't render well without the override, which -is also common with older CEF versions. - -CW-Bug-Id: #19483 ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 900f172b325..58bf6d4bbab 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4239,6 +4239,7 @@ HKCU,Software\Wine\AppDefaults\WRC9.exe\DllOverrides,"xinput1_3",,"native" - HKCU,Software\Wine\AppDefaults\WRC10.exe\DllOverrides,"xinput1_3",,"native" - HKCU,Software\Wine\AppDefaults\Paradox Launcher.exe\DllOverrides,"libglesv2",,"disabled" - HKCU,Software\Wine\AppDefaults\Nickelodeon All-Star Brawl.exe\DllOverrides,"winusb",,"disabled" -+HKCU,Software\Wine\AppDefaults\nw.exe\DllOverrides,"libglesv2",,"disabled" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" - diff --git a/patches/proton/57-fsync_futex_waitv.patch b/patches/proton/57-fsync_futex_waitv.patch deleted file mode 100644 index 9361f5c2c..000000000 --- a/patches/proton/57-fsync_futex_waitv.patch +++ /dev/null @@ -1,1246 +0,0 @@ -From 5fa24654c73dba73aa876482aa7d3214d8c7270f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= -Date: Fri, 27 Nov 2020 14:05:14 -0300 -Subject: [PATCH 2/5] ntdll: Call waitv just when nr_futexes > 1 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -futex_waitv() needs to do an extra copy from userspace compared to -futex(), so use the latter when we are waiting in a single futex. - -Signed-off-by: André Almeida ---- - dlls/ntdll/unix/fsync.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index 1ed91ece3f6..4ccf557e587 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -980,10 +980,18 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; - tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - -- ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); -+ if (waitcount == 1) -+ ret = futex_wait( futexes[0].addr, futexes[0].val, &tmo_p ); -+ else -+ ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); - } - else -- ret = futex_wait_multiple( futexes, waitcount, NULL ); -+ { -+ if (waitcount == 1) -+ ret = futex_wait( futexes[0].addr, futexes[0].val, NULL ); -+ else -+ ret = futex_wait_multiple( futexes, waitcount, NULL ); -+ } - - /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, - * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to --- -2.33.1 - -From fe7f5575abbbde228cdb8843eb6929b5f0877572 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= -Date: Wed, 20 Oct 2021 10:35:58 -0300 -Subject: [PATCH 3/5] ntdll/fsync: Encapsulate timeout conversion -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Simplify the wait path by dealing with the timeout conversion -inside of futex_wait. - -Signed-off-by: André Almeida ---- - dlls/ntdll/unix/fsync.c | 94 ++++++++++++++++++----------------------- - 1 file changed, 42 insertions(+), 52 deletions(-) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index 4ccf557e587..ecc8abc1d67 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -76,10 +76,32 @@ static inline void small_pause(void) - #endif - } - -+static LONGLONG update_timeout( ULONGLONG end ) -+{ -+ LARGE_INTEGER now; -+ LONGLONG timeleft; -+ -+ NtQuerySystemTime( &now ); -+ timeleft = end - now.QuadPart; -+ if (timeleft < 0) timeleft = 0; -+ return timeleft; -+} -+ - static inline int futex_wait_multiple( const struct futex_wait_block *futexes, -- int count, const struct timespec *timeout ) -+ int count, const ULONGLONG *end ) - { -- return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); -+ if (end) -+ { -+ LONGLONG timeleft = update_timeout( *end ); -+ struct timespec timeout; -+ timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -+ timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; -+ return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); -+ } -+ else -+ { -+ return syscall( __NR_futex, futexes, 31, count, NULL, 0, 0 ); -+ } - } - - static inline int futex_wake( int *addr, int val ) -@@ -87,9 +109,20 @@ static inline int futex_wake( int *addr, int val ) - return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); - } - --static inline int futex_wait( int *addr, int val, struct timespec *timeout ) -+static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) - { -- return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); -+ if (end) -+ { -+ LONGLONG timeleft = update_timeout( *end ); -+ struct timespec timeout; -+ timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -+ timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; -+ return syscall( __NR_futex, addr, 0, val, &timeout, 0, 0 ); -+ } -+ else -+ { -+ return syscall( __NR_futex, addr, 0, val, NULL, 0, 0 ); -+ } - } - - static unsigned int spincount = 100; -@@ -645,17 +678,6 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) - return STATUS_SUCCESS; - } - --static LONGLONG update_timeout( ULONGLONG end ) --{ -- LARGE_INTEGER now; -- LONGLONG timeleft; -- -- NtQuerySystemTime( &now ); -- timeleft = end - now.QuadPart; -- if (timeleft < 0) timeleft = 0; -- return timeleft; --} -- - static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) - { - int ret; -@@ -677,32 +699,14 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler - #endif - futexes[0].bitset = futexes[1].bitset = ~0; - -- if (end) -- { -- LONGLONG timeleft = update_timeout( *end ); -- struct timespec tmo_p; -- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; -- ret = futex_wait_multiple( futexes, 2, &tmo_p ); -- } -- else -- ret = futex_wait_multiple( futexes, 2, NULL ); -+ ret = futex_wait_multiple( futexes, 2, end ); - - if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) - return STATUS_USER_APC; - } - else - { -- if (end) -- { -- LONGLONG timeleft = update_timeout( *end ); -- struct timespec tmo_p; -- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; -- ret = futex_wait( addr, val, &tmo_p ); -- } -- else -- ret = futex_wait( addr, val, NULL ); -+ ret = futex_wait( addr, val, end ); - } - - if (!ret) -@@ -973,25 +977,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - TRACE("Wait timed out.\n"); - return STATUS_TIMEOUT; - } -- else if (timeout) -- { -- LONGLONG timeleft = update_timeout( end ); -- struct timespec tmo_p; -- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; - -- if (waitcount == 1) -- ret = futex_wait( futexes[0].addr, futexes[0].val, &tmo_p ); -- else -- ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); -- } -+ if (waitcount == 1) -+ ret = futex_wait( futexes[0].addr, futexes[0].val, timeout ? &end : NULL ); - else -- { -- if (waitcount == 1) -- ret = futex_wait( futexes[0].addr, futexes[0].val, NULL ); -- else -- ret = futex_wait_multiple( futexes, waitcount, NULL ); -- } -+ ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); - - /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, - * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to --- -2.33.1 - -From 86d3547ea3899e2def64ef1e2bab5e0ed760d961 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= -Date: Thu, 21 Oct 2021 13:36:14 -0300 -Subject: [PATCH 4/5] ntdll/fsync: Support futex_waitv() API -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Since an interface for wait on multiple futexes was merged, we no longer -need to support different interfaces. Drop out FUTEX_WAIT_MULTIPLE -(opcode 31) in favor of the futex_waitv() interface accepted by -upstream Linux. - -Signed-off-by: André Almeida ---- - dlls/ntdll/unix/fsync.c | 101 ++++++++++++++++++++-------------------- - server/fsync.c | 19 ++------ - 2 files changed, 55 insertions(+), 65 deletions(-) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index ecc8abc1d67..261f45ac4bf 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -41,6 +41,7 @@ - # include - #endif - #include -+#include - - #include "ntstatus.h" - #define WIN32_NO_STATUS -@@ -56,16 +57,30 @@ - WINE_DEFAULT_DEBUG_CHANNEL(fsync); - - #include "pshpack4.h" --struct futex_wait_block --{ -- int *addr; --#if __SIZEOF_POINTER__ == 4 -- int pad; -+#include "poppack.h" -+ -+/* futex_waitv interface */ -+ -+#ifndef __NR_futex_waitv -+ -+# define __NR_futex_waitv 449 -+# define FUTEX_32 2 -+struct futex_waitv { -+ uint64_t val; -+ uint64_t uaddr; -+ uint32_t flags; -+ uint32_t __reserved; -+}; -+ - #endif -- int val; -- int bitset; -+ -+#define u64_to_ptr(x) (void *)(uintptr_t)(x) -+ -+struct timespec64 -+{ -+ long long tv_sec; -+ long long tv_nsec; - }; --#include "poppack.h" - - static inline void small_pause(void) - { -@@ -87,20 +102,29 @@ static LONGLONG update_timeout( ULONGLONG end ) - return timeleft; - } - --static inline int futex_wait_multiple( const struct futex_wait_block *futexes, -+static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int val ) -+{ -+ waitv->uaddr = (uintptr_t) addr; -+ waitv->val = val; -+ waitv->flags = FUTEX_32; -+ waitv->__reserved = 0; -+} -+ -+static inline int futex_wait_multiple( const struct futex_waitv *futexes, - int count, const ULONGLONG *end ) - { - if (end) - { -- LONGLONG timeleft = update_timeout( *end ); -- struct timespec timeout; -- timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -- timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; -- return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); -+ struct timespec64 timeout; -+ ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; -+ timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; -+ timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; -+ -+ return syscall( __NR_futex_waitv, futexes, count, 0, &timeout, CLOCK_REALTIME ); - } - else - { -- return syscall( __NR_futex, futexes, 31, count, NULL, 0, 0 ); -+ return syscall( __NR_futex_waitv, futexes, count, 0, NULL, 0 ); - } - } - -@@ -134,8 +158,7 @@ int do_fsync(void) - - if (do_fsync_cached == -1) - { -- static const struct timespec zero; -- futex_wait_multiple( NULL, 0, &zero ); -+ syscall( __NR_futex_waitv, NULL, 0, 0, NULL, 0 ); - do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; - if (getenv("WINEFSYNC_SPINCOUNT")) - spincount = atoi(getenv("WINEFSYNC_SPINCOUNT")); -@@ -685,19 +708,13 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler - if (alertable) - { - int *apc_futex = ntdll_get_thread_data()->fsync_apc_futex; -- struct futex_wait_block futexes[2]; -+ struct futex_waitv futexes[2]; - - if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) - return STATUS_USER_APC; - -- futexes[0].addr = addr; -- futexes[0].val = val; -- futexes[1].addr = apc_futex; -- futexes[1].val = 0; --#if __SIZEOF_POINTER__ == 4 -- futexes[0].pad = futexes[1].pad = 0; --#endif -- futexes[0].bitset = futexes[1].bitset = ~0; -+ futex_vector_set( &futexes[0], addr, val ); -+ futex_vector_set( &futexes[1], apc_futex, 0 ); - - ret = futex_wait_multiple( futexes, 2, end ); - -@@ -722,7 +739,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - { - static const LARGE_INTEGER zero = {0}; - -- struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS + 1]; -+ struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; - struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; - int has_fsync = 0, has_server = 0; - BOOL msgwait = FALSE; -@@ -852,8 +869,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - small_pause(); - } - -- futexes[i].addr = &semaphore->count; -- futexes[i].val = 0; -+ futex_vector_set( &futexes[i], &semaphore->count, 0 ); - break; - } - case FSYNC_MUTEX: -@@ -885,8 +901,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - small_pause(); - } - -- futexes[i].addr = &mutex->tid; -- futexes[i].val = tid; -+ futex_vector_set( &futexes[i], &mutex->tid, tid ); - break; - } - case FSYNC_AUTO_EVENT: -@@ -907,8 +922,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - small_pause(); - } - -- futexes[i].addr = &event->signaled; -- futexes[i].val = 0; -+ futex_vector_set( &futexes[i], &event->signaled, 0 ); - break; - } - case FSYNC_MANUAL_EVENT: -@@ -930,8 +944,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - small_pause(); - } - -- futexes[i].addr = &event->signaled; -- futexes[i].val = 0; -+ futex_vector_set( &futexes[i], &event->signaled, 0 ); - break; - } - default: -@@ -942,26 +955,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - else - { - /* Avoid breaking things entirely. */ -- futexes[i].addr = &dummy_futex; -- futexes[i].val = dummy_futex; -+ futex_vector_set( &futexes[i], &dummy_futex, dummy_futex ); - } -- --#if __SIZEOF_POINTER__ == 4 -- futexes[i].pad = 0; --#endif -- futexes[i].bitset = ~0; - } - - if (alertable) - { - /* We already checked if it was signaled; don't bother doing it again. */ -- futexes[i].addr = ntdll_get_thread_data()->fsync_apc_futex; -- futexes[i].val = 0; --#if __SIZEOF_POINTER__ == 4 -- futexes[i].pad = 0; --#endif -- futexes[i].bitset = ~0; -- i++; -+ futex_vector_set( &futexes[i++], ntdll_get_thread_data()->fsync_apc_futex, 0 ); - } - waitcount = i; - -@@ -979,7 +980,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - } - - if (waitcount == 1) -- ret = futex_wait( futexes[0].addr, futexes[0].val, timeout ? &end : NULL ); -+ ret = futex_wait( u64_to_ptr(futexes[0].uaddr), futexes[0].val, timeout ? &end : NULL ); - else - ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); - -diff --git a/server/fsync.c b/server/fsync.c -index 411918aa2be..237e8f2b4a4 100644 ---- a/server/fsync.c -+++ b/server/fsync.c -@@ -47,21 +47,11 @@ - #include "fsync.h" - - #include "pshpack4.h" --struct futex_wait_block --{ -- int *addr; --#if __SIZEOF_POINTER__ == 4 -- int pad; --#endif -- int val; --}; - #include "poppack.h" - --static inline int futex_wait_multiple( const struct futex_wait_block *futexes, -- int count, const struct timespec *timeout ) --{ -- return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); --} -+#ifndef __NR_futex_waitv -+#define __NR_futex_waitv 449 -+#endif - - int do_fsync(void) - { -@@ -70,8 +60,7 @@ int do_fsync(void) - - if (do_fsync_cached == -1) - { -- static const struct timespec zero; -- futex_wait_multiple( NULL, 0, &zero ); -+ syscall( __NR_futex_waitv, 0, 0, 0, 0, 0); - do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; - } - --- -2.33.1 - -From 5116e14a507f9fbe4a26234924db06ff6a0366f0 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Andr=C3=A9=20Almeida?= -Date: Thu, 21 Oct 2021 20:33:58 -0300 -Subject: [PATCH 5/5] ntdll/fsync: Use absolute timeouts for futex_wait -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Use the FUTEX_WAIT_BITSET operation instead of FUTEX_WAIT, that allow us -to use absolute timeouts rather than relative ones that requires an -extra syscall to update the timeout. - -Signed-off-by: André Almeida ---- - dlls/ntdll/unix/fsync.c | 14 ++++++++++---- - 1 file changed, 10 insertions(+), 4 deletions(-) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index 261f45ac4bf..1291f3171a1 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -59,6 +59,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); - #include "pshpack4.h" - #include "poppack.h" - -+#define FUTEX_WAIT_BITSET 9 -+#define FUTEX_CLOCK_REALTIME 256 -+#define FUTEX_BITSET_MATCH_ANY 0xffffffff -+ - /* futex_waitv interface */ - - #ifndef __NR_futex_waitv -@@ -137,11 +141,13 @@ static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) - { - if (end) - { -- LONGLONG timeleft = update_timeout( *end ); - struct timespec timeout; -- timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; -- timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; -- return syscall( __NR_futex, addr, 0, val, &timeout, 0, 0 ); -+ ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; -+ timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; -+ timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; -+ -+ return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, -+ val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); - } - else - { --- -2.33.1 - -From a55a995020e09bfb844b12cac02351cf970287c7 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Mon, 1 Nov 2021 14:25:42 +0200 -Subject: [PATCH] HAX: Disable fsync if we detect the old futex2 patches. - -futex_waitv() has been accepted into locking/core branch of kernel.org's -tip repo and has a fixed syscall number. - -Even though the syscall number matches (449) there were changes that -result in 100% CPU utilization at all times when running with the old, -downstream version of the futex2 patches. - -The new patches do not come with the sysfs entries so we can use that -for the detection. - -Fixes: https://github.com/ValveSoftware/wine/pull/128 ---- - dlls/ntdll/unix/fsync.c | 8 ++++++++ - server/fsync.c | 9 +++++++++ - 2 files changed, 17 insertions(+) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index 1291f3171a1..8f07ed59ae0 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -164,6 +164,14 @@ int do_fsync(void) - - if (do_fsync_cached == -1) - { -+ FILE *f; -+ if ((f = fopen( "/sys/kernel/futex2/wait", "r" ))) -+ { -+ fclose(f); -+ do_fsync_cached = 0; -+ return do_fsync_cached; -+ } -+ - syscall( __NR_futex_waitv, NULL, 0, 0, NULL, 0 ); - do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; - if (getenv("WINEFSYNC_SPINCOUNT")) -diff --git a/server/fsync.c b/server/fsync.c -index 237e8f2b4a4..45760bc0320 100644 ---- a/server/fsync.c -+++ b/server/fsync.c -@@ -60,6 +60,15 @@ int do_fsync(void) - - if (do_fsync_cached == -1) - { -+ FILE *f; -+ if ((f = fopen( "/sys/kernel/futex2/wait", "r" ))) -+ { -+ fclose(f); -+ do_fsync_cached = 0; -+ fprintf( stderr, "fsync: old futex2 patches detected, disabling.\n" ); -+ return do_fsync_cached; -+ } -+ - syscall( __NR_futex_waitv, 0, 0, 0, 0, 0); - do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; - } -From 3196885798787b6a52dbef0f3968f6b5e0216c56 Mon Sep 17 00:00:00 2001 -From: Dmitry Skvortsov -Date: Sun, 26 Dec 2021 16:32:58 +0300 -Subject: [PATCH 1/2] Separate check for definition of FUTEX_32 and struct futex_waitv - ---- - dlls/ntdll/unix/fsync.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index 39d969f061d..c6869b62b4b 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -64,8 +64,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); - /* futex_waitv interface */ - - #ifndef __NR_futex_waitv -- - # define __NR_futex_waitv 449 -+#endif -+ -+#ifndef FUTEX_32 - # define FUTEX_32 2 - struct futex_waitv { - uint64_t val; -@@ -73,7 +75,6 @@ struct futex_waitv { - uint32_t flags; - uint32_t __reserved; - }; -- - #endif - - #define u64_to_ptr(x) (void *)(uintptr_t)(x) --- -2.34.1 - -From 2c15b20ad7dd57778ad2354a14dd441d1cd6cf4f Mon Sep 17 00:00:00 2001 -From: Dmitry Skvortsov -Date: Sun, 26 Dec 2021 16:45:21 +0300 -Subject: [PATCH 2/2] Add check for linux/futex.h - ---- - configure | 6 ++++++ - configure.ac | 1 + - dlls/ntdll/unix/fsync.c | 3 +++ - include/config.h.in | 3 +++ - 4 files changed, 13 insertions(+) - -diff --git a/configure b/configure -index ab3aa34a922..d2bcd778c59 100755 ---- a/configure -+++ b/configure -@@ -8317,6 +8317,12 @@ if test "x$ac_cv_header_linux_filter_h" = xyes - then : - printf "%s\n" "#define HAVE_LINUX_FILTER_H 1" >>confdefs.h - -+fi -+ac_fn_c_check_header_compile "$LINENO" "linux/futex.h" "ac_cv_header_linux_futex_h" "$ac_includes_default" -+if test "x$ac_cv_header_linux_futex_h" = xyes -+then : -+ printf "%s\n" "#define HAVE_LINUX_FUTEX_H 1" >>confdefs.h -+ - fi - ac_fn_c_check_header_compile "$LINENO" "linux/hdreg.h" "ac_cv_header_linux_hdreg_h" "$ac_includes_default" - if test "x$ac_cv_header_linux_hdreg_h" = xyes -diff --git a/include/config.h.in b/include/config.h.in -index 9eb052c6248..910cce10693 100644 ---- a/include/config.h.in -+++ b/include/config.h.in -@@ -200,6 +200,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_LINUX_FILTER_H - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_LINUX_FUTEX_H -+ - /* Define if Linux-style gethostbyname_r and gethostbyaddr_r are available */ - #undef HAVE_LINUX_GETHOSTBYNAME_R_6 - -diff --git a/configure.ac b/configure.ac -index 3071da61b62..cfe27460a96 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -450,2 +450,3 @@ AC_CHECK_HEADERS(\ - linux/filter.h \ -+ linux/futex.h \ - linux/hdreg.h \ -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index c6869b62b4b..6d69c643244 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -27,6 +27,9 @@ - #include - #include - #include -+#ifdef HAVE_LINUX_FUTEX_H -+# include -+#endif - #include - #include - #include --- -2.34.1 - -From 5726c4a62f9febce68a352d1e8a99a15325fe25c Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 6 Apr 2021 19:43:48 +0300 -Subject: [PATCH] ntdll: Simulate async file read and IO cancellation to - workaround AC:Odyssey out of order dialogues bug. - -CW-Bug-ID: #18881 ---- - dlls/ntdll/unix/file.c | 237 +++++++++++++++++++++++++++++++++++++++ - dlls/ntdll/unix/loader.c | 6 +- - 2 files changed, 242 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 3f60060bb38..850c70a6b2b 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -5295,6 +5295,230 @@ static NTSTATUS set_pending_write( HANDLE device ) - return status; - } - -+static pthread_mutex_t async_file_read_mutex = PTHREAD_MUTEX_INITIALIZER; -+static pthread_cond_t async_file_read_cond = PTHREAD_COND_INITIALIZER; -+ -+struct async_file_read_job -+{ -+ HANDLE handle; -+ int unix_handle; -+ int needs_close; -+ HANDLE event; -+ IO_STATUS_BLOCK *io; -+ void *buffer; -+ ULONG length; -+ LARGE_INTEGER offset; -+ DWORD thread_id; -+ LONG cancelled; -+ struct list queue_entry; -+ struct async_file_read_job *next; -+}; -+ -+ -+static struct list async_file_read_queue = LIST_INIT( async_file_read_queue ); -+static struct async_file_read_job *async_file_read_running, *async_file_read_free; -+ -+static void async_file_complete_io( struct async_file_read_job *job, NTSTATUS status, ULONG total ) -+{ -+ job->io->u.Status = status; -+ job->io->Information = total; -+ -+ if (job->event) NtSetEvent( job->event, NULL ); -+} -+ -+static void *async_file_read_thread(void *dummy) -+{ -+ struct async_file_read_job *job, *ptr; -+ ULONG buffer_length = 0; -+ void *buffer = NULL; -+ struct list *entry; -+ NTSTATUS status; -+ ULONG total; -+ int result; -+ -+ pthread_mutex_lock( &async_file_read_mutex ); -+ while (1) -+ { -+ while (!(entry = list_head( &async_file_read_queue ))) -+ { -+ pthread_cond_wait( &async_file_read_cond, &async_file_read_mutex ); -+ continue; -+ } -+ -+ job = LIST_ENTRY( entry, struct async_file_read_job, queue_entry ); -+ list_remove( entry ); -+ -+ total = 0; -+ -+ if ( job->cancelled ) -+ { -+ pthread_mutex_unlock( &async_file_read_mutex ); -+ status = STATUS_CANCELLED; -+ goto done; -+ } -+ -+ job->next = async_file_read_running; -+ async_file_read_running = job; -+ pthread_mutex_unlock( &async_file_read_mutex ); -+ -+ if (!buffer_length) -+ { -+ buffer = malloc(job->length); -+ buffer_length = job->length; -+ } -+ else if (buffer_length < job->length) -+ { -+ buffer = realloc(buffer, job->length); -+ buffer_length = job->length; -+ } -+ -+ while ((result = pread( job->unix_handle, buffer, job->length, job->offset.QuadPart )) == -1) -+ { -+ if (errno != EINTR) -+ { -+ status = errno_to_status( errno ); -+ goto done; -+ } -+ if (job->cancelled) -+ break; -+ } -+ -+ total = result; -+ status = (total || !job->length) ? STATUS_SUCCESS : STATUS_END_OF_FILE; -+done: -+ if (job->needs_close) close( job->unix_handle ); -+ -+ if (!InterlockedCompareExchange(&job->cancelled, 1, 0)) -+ { -+ if (status == STATUS_SUCCESS) -+ memcpy( job->buffer, buffer, total ); -+ -+ async_file_complete_io( job, status, total ); -+ } -+ -+ pthread_mutex_lock( &async_file_read_mutex ); -+ -+ if (status != STATUS_CANCELLED) -+ { -+ ptr = async_file_read_running; -+ if (job == ptr) -+ { -+ async_file_read_running = job->next; -+ } -+ else -+ { -+ while (ptr && ptr->next != job) -+ ptr = ptr->next; -+ -+ assert( ptr ); -+ ptr->next = job->next; -+ } -+ } -+ -+ job->next = async_file_read_free; -+ async_file_read_free = job; -+ } -+ -+ return NULL; -+} -+ -+static pthread_once_t async_file_read_once = PTHREAD_ONCE_INIT; -+ -+static void async_file_read_init(void) -+{ -+ pthread_t async_file_read_thread_id; -+ pthread_attr_t pthread_attr; -+ -+ ERR("HACK: AC Odyssey async read workaround.\n"); -+ -+ pthread_attr_init( &pthread_attr ); -+ pthread_attr_setscope( &pthread_attr, PTHREAD_SCOPE_SYSTEM ); -+ pthread_attr_setdetachstate( &pthread_attr, PTHREAD_CREATE_DETACHED ); -+ -+ pthread_create( &async_file_read_thread_id, &pthread_attr, (void * (*)(void *))async_file_read_thread, NULL); -+ pthread_attr_destroy( &pthread_attr ); -+} -+ -+static NTSTATUS queue_async_file_read( HANDLE handle, int unix_handle, int needs_close, HANDLE event, -+ IO_STATUS_BLOCK *io, void *buffer, ULONG length, LARGE_INTEGER *offset ) -+{ -+ struct async_file_read_job *job; -+ -+ pthread_once( &async_file_read_once, async_file_read_init ); -+ -+ NtResetEvent( event, NULL ); -+ -+ pthread_mutex_lock( &async_file_read_mutex ); -+ -+ if (async_file_read_free) -+ { -+ job = async_file_read_free; -+ async_file_read_free = async_file_read_free->next; -+ } -+ else -+ { -+ if (!(job = malloc( sizeof(*job) ))) -+ { -+ pthread_mutex_unlock( &async_file_read_mutex ); -+ return STATUS_NO_MEMORY; -+ } -+ } -+ -+ job->handle = handle; -+ job->unix_handle = unix_handle; -+ job->needs_close = needs_close; -+ job->event = event; -+ job->io = io; -+ job->buffer = buffer; -+ job->length = length; -+ job->offset = *offset; -+ job->thread_id = GetCurrentThreadId(); -+ job->cancelled = 0; -+ -+ list_add_tail( &async_file_read_queue, &job->queue_entry ); -+ -+ pthread_cond_signal( &async_file_read_cond ); -+ pthread_mutex_unlock( &async_file_read_mutex ); -+ -+ return STATUS_PENDING; -+} -+ -+static NTSTATUS cancel_async_file_read( HANDLE handle, IO_STATUS_BLOCK *io ) -+{ -+ DWORD thread_id = GetCurrentThreadId(); -+ struct async_file_read_job *job; -+ unsigned int count = 0; -+ -+ TRACE( "handle %p, io %p.\n", handle, io ); -+ -+ pthread_mutex_lock( &async_file_read_mutex ); -+ job = async_file_read_running; -+ while (job) -+ { -+ if (((io && job->io == io) -+ || (!io && job->handle == handle && job->thread_id == thread_id)) -+ && !InterlockedCompareExchange(&job->cancelled, 1, 0)) -+ { -+ async_file_complete_io( job, STATUS_CANCELLED, 0 ); -+ ++count; -+ } -+ job = job->next; -+ } -+ -+ LIST_FOR_EACH_ENTRY( job, &async_file_read_queue, struct async_file_read_job, queue_entry ) -+ { -+ if (((io && job->io == io) -+ || (!io && job->handle == handle && job->thread_id == thread_id)) -+ && !InterlockedCompareExchange(&job->cancelled, 1, 0)) -+ { -+ async_file_complete_io( job, STATUS_CANCELLED, 0 ); -+ ++count; -+ } -+ } -+ -+ pthread_mutex_unlock( &async_file_read_mutex ); -+ return count ? STATUS_SUCCESS : STATUS_NOT_FOUND; -+} - - /****************************************************************************** - * NtReadFile (NTDLL.@) -@@ -5336,6 +5560,13 @@ NTSTATUS WINAPI NtReadFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, vo - goto done; - } - -+ if (ac_odyssey && async_read && length && event && !apc) -+ { -+ status = queue_async_file_read( handle, unix_handle, needs_close, event, io, buffer, length, offset ); -+ needs_close = 0; -+ goto err; -+ } -+ - if (offset && offset->QuadPart != FILE_USE_FILE_POINTER_POSITION) - { - /* async I/O doesn't make sense on regular files */ -@@ -6118,6 +6349,9 @@ NTSTATUS WINAPI NtCancelIoFile( HANDLE handle, IO_STATUS_BLOCK *io_status ) - - TRACE( "%p %p\n", handle, io_status ); - -+ if (ac_odyssey && !cancel_async_file_read( handle, NULL )) -+ return (io_status->u.Status = STATUS_SUCCESS); -+ - SERVER_START_REQ( cancel_async ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -6143,6 +6377,9 @@ NTSTATUS WINAPI NtCancelIoFileEx( HANDLE handle, IO_STATUS_BLOCK *io, IO_STATUS_ - - TRACE( "%p %p %p\n", handle, io, io_status ); - -+ if (ac_odyssey && !cancel_async_file_read( handle, io )) -+ return (io_status->u.Status = STATUS_SUCCESS); -+ - SERVER_START_REQ( cancel_async ) - { - req->handle = wine_server_obj_handle( handle ); -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 7f3d7834a6c..0f3ec16c52f 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -2210,7 +2210,11 @@ static void hacks_init(void) - - if (!strcasecmp(cur_exe, ac_odyssey_exe)) - { -- ERR("HACK: AC Odyssey sync tweak on.\n"); -+ if (do_esync() || do_fsync()) -+ ERR("HACK: AC Odyssey sync tweak on.\n"); -+ else -+ ERR("Not enabling AC Odyssey sync tweak as esync and fsync are disabled.\n"); -+ - ac_odyssey = TRUE; - } - } -From c6bad6f294f1d15a7825df71585e695f73bc8561 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 3 Nov 2021 18:07:13 +0300 -Subject: [PATCH] ntdll: HACK: Enable WINESTEAMNOEXEC for Mafia II. - -CW-Bug-Id: #19605 ---- - dlls/ntdll/unix/loader.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 0f3ec16c52f..0a05fb3f10b 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -2201,6 +2201,7 @@ static void hacks_init(void) - static const char ac_odyssey_exe[] = "ACOdyssey.exe"; - char cur_exe[MAX_PATH]; - DWORD cur_exe_len; -+ const char *sgi; - int fd; - - fd = open("/proc/self/comm", O_RDONLY); -@@ -2216,7 +2217,12 @@ static void hacks_init(void) - ERR("Not enabling AC Odyssey sync tweak as esync and fsync are disabled.\n"); - - ac_odyssey = TRUE; -+ return; - } -+ -+ sgi = getenv("SteamGameId"); -+ if (sgi && !strcmp(sgi, "50130")) -+ setenv("WINESTEAMNOEXEC", "1", 0); - } - - /*********************************************************************** - -From 6f2c9858d6bb957b807411b28f8ffd77199eafd4 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 14 Feb 2022 22:40:40 +0300 -Subject: [PATCH] fixup! esync, fsync: Yield execution before alertable wait - for AC Odyssey. - -CW-Bug-Id: #18881 ---- - dlls/ntdll/unix/loader.c | 16 ++-------------- - 1 file changed, 2 insertions(+), 14 deletions(-) - -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 1d4160727e4..301a11c0419 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -2241,23 +2241,11 @@ BOOL ac_odyssey; - static void hacks_init(void) - { - static const char ac_odyssey_exe[] = "ACOdyssey.exe"; -- char cur_exe[MAX_PATH]; -- DWORD cur_exe_len; - const char *sgi; -- int fd; -- -- fd = open("/proc/self/comm", O_RDONLY); -- cur_exe_len = read(fd, cur_exe, sizeof(cur_exe)); -- close(fd); -- cur_exe[cur_exe_len - 1] = 0; - -- if (!strcasecmp(cur_exe, ac_odyssey_exe)) -+ if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe)) - { -- if (do_esync() || do_fsync()) -- ERR("HACK: AC Odyssey sync tweak on.\n"); -- else -- ERR("Not enabling AC Odyssey sync tweak as esync and fsync are disabled.\n"); -- -+ ERR("HACK: AC Odyssey sync tweak on.\n"); - ac_odyssey = TRUE; - return; - } -From d6a237166626d197b1d642f8f7a71900759df2b6 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 15 Feb 2022 17:20:40 +0300 -Subject: [PATCH] fsync: Add WINE_FSYNC_SIMULATE_SCHED_QUANTUM config option. - -And auto enable it for Uplay laucher. - -CW-Bug-Id: #20155 ---- - dlls/ntdll/unix/fsync.c | 20 +++++++++++++++++++- - dlls/ntdll/unix/loader.c | 15 ++++++++++++--- - dlls/ntdll/unix/unix_private.h | 1 + - 3 files changed, 32 insertions(+), 4 deletions(-) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index d468782667a..f42e30d0245 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -112,6 +112,18 @@ static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int v - waitv->__reserved = 0; - } - -+static void simulate_sched_quantum(void) -+{ -+ LARGE_INTEGER now; -+ ULONG64 wait_end; -+ -+ if (!fsync_simulate_sched_quantum) return; -+ -+ NtQuerySystemTime( &now ); -+ wait_end = (now.QuadPart / 10 + 499) / 500; -+ usleep( wait_end * 500 - (now.QuadPart / 10) ); -+} -+ - static inline int futex_wait_multiple( const struct futex_waitv *futexes, - int count, const ULONGLONG *end ) - { -@@ -756,8 +768,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - - struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; - struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; -+ BOOL msgwait = FALSE, waited = FALSE; - int has_fsync = 0, has_server = 0; -- BOOL msgwait = FALSE; - int dummy_futex = 0; - unsigned int spin; - LONGLONG timeleft; -@@ -879,6 +891,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) - { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); -+ if (waited) simulate_sched_quantum(); - return i; - } - small_pause(); -@@ -896,6 +909,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - mutex->count++; -+ if (waited) simulate_sched_quantum(); - return i; - } - -@@ -905,6 +919,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - { - TRACE("Woken up by handle %p [%d].\n", handles[i], i); - mutex->count = 1; -+ if (waited) simulate_sched_quantum(); - return i; - } - else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) -@@ -932,6 +947,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - usleep( 0 ); - - TRACE("Woken up by handle %p [%d].\n", handles[i], i); -+ if (waited) simulate_sched_quantum(); - return i; - } - small_pause(); -@@ -954,6 +970,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - usleep( 0 ); - - TRACE("Woken up by handle %p [%d].\n", handles[i], i); -+ if (waited) simulate_sched_quantum(); - return i; - } - small_pause(); -@@ -1008,6 +1025,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, - TRACE("Wait timed out.\n"); - return STATUS_TIMEOUT; - } -+ else waited = TRUE; - } /* while (1) */ - } - else -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 301a11c0419..f078a967be8 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -2237,11 +2237,13 @@ static struct unix_funcs unix_funcs = - }; - - BOOL ac_odyssey; -+BOOL fsync_simulate_sched_quantum; - - static void hacks_init(void) - { -+ static const char upc_exe[] = "Ubisoft Game Launcher\\upc.exe"; - static const char ac_odyssey_exe[] = "ACOdyssey.exe"; -- const char *sgi; -+ const char *env_str; - - if (main_argc > 1 && strstr(main_argv[1], ac_odyssey_exe)) - { -@@ -2249,9 +2251,16 @@ static void hacks_init(void) - ac_odyssey = TRUE; - return; - } -+ env_str = getenv("WINE_FSYNC_SIMULATE_SCHED_QUANTUM"); -+ if (env_str) -+ fsync_simulate_sched_quantum = !!atoi(env_str); -+ else if (main_argc > 1) -+ fsync_simulate_sched_quantum = !!strstr(main_argv[1], upc_exe); -+ if (fsync_simulate_sched_quantum) -+ ERR("HACK: Simulating sched quantum in fsync.\n"); - -- sgi = getenv("SteamGameId"); -- if (sgi && !strcmp(sgi, "50130")) -+ env_str = getenv("SteamGameId"); -+ if (env_str && !strcmp(env_str, "50130")) - setenv("WINESTEAMNOEXEC", "1", 0); - } - -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index d1840de8876..4bf0e7cb84e 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -148,6 +148,7 @@ extern struct ldt_copy __wine_ldt_copy DECLSPEC_HIDDEN; - #endif - - extern BOOL ac_odyssey DECLSPEC_HIDDEN; -+extern BOOL fsync_simulate_sched_quantum DECLSPEC_HIDDEN; - - extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; - extern void init_startup_info(void) DECLSPEC_HIDDEN; -From b3fb8a5543db15280952042152f5218ee994b011 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 15 Feb 2022 22:00:23 +0300 -Subject: [PATCH] fixup! fsync: Add WINE_FSYNC_SIMULATE_SCHED_QUANTUM config - option. - ---- - dlls/ntdll/unix/fsync.c | 11 ++++------- - 1 file changed, 4 insertions(+), 7 deletions(-) - -diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c -index f42e30d0245..0f19c63a5f2 100644 ---- a/dlls/ntdll/unix/fsync.c -+++ b/dlls/ntdll/unix/fsync.c -@@ -114,14 +114,11 @@ static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int v - - static void simulate_sched_quantum(void) - { -- LARGE_INTEGER now; -- ULONG64 wait_end; -- - if (!fsync_simulate_sched_quantum) return; -- -- NtQuerySystemTime( &now ); -- wait_end = (now.QuadPart / 10 + 499) / 500; -- usleep( wait_end * 500 - (now.QuadPart / 10) ); -+ /* futex wait is often very quick to resume a waiting thread when woken. -+ * That reveals synchonization bugs in some games which happen to work on -+ * Windows due to the waiting threads having some minimal delay to wake up. */ -+ usleep(0); - } - - static inline int futex_wait_multiple( const struct futex_waitv *futexes, diff --git a/patches/proton/58-proton-13_atiadlxx_builtin_for_gotg.patch b/patches/proton/58-proton-13_atiadlxx_builtin_for_gotg.patch deleted file mode 100644 index 167a2ba6e..000000000 --- a/patches/proton/58-proton-13_atiadlxx_builtin_for_gotg.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 3d757d9a2f8..799234e1837 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -6047,6 +6047,7 @@ HKCU,Software\Wine\AppDefaults\WRC10.exe\DllOverrides,"xinput1_3",,"native" - HKCU,Software\Wine\AppDefaults\Paradox Launcher.exe\DllOverrides,"libglesv2",,"disabled" - HKCU,Software\Wine\AppDefaults\Nickelodeon All-Star Brawl.exe\DllOverrides,"winusb",,"disabled" - HKCU,Software\Wine\AppDefaults\nw.exe\DllOverrides,"libglesv2",,"disabled" -+HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" diff --git a/patches/proton/59-proton-battleye_patches.patch b/patches/proton/59-proton-battleye_patches.patch deleted file mode 100644 index 81b3de6fe..000000000 --- a/patches/proton/59-proton-battleye_patches.patch +++ /dev/null @@ -1,737 +0,0 @@ -From f7b8a83d06870a54430481c85c764401d96e143c Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 26 Mar 2021 10:48:14 -0400 -Subject: [PATCH] ntdll: Try to load builtin DLLs from Battleye Runtime - directory. - -Signed-off-by: Derek Lesho - -CW-Bug-Id: #16650 ---- - dlls/ntdll/unix/loader.c | 23 ++++++++++++++++++++++- - 1 file changed, 22 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 0a05fb3f10b..711b7224bfc 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -526,11 +526,14 @@ static const char *get_pe_dir( WORD machine ) - - static void set_dll_path(void) - { -- char *p, *path = getenv( "WINEDLLPATH" ); -+ char *p, *path = getenv( "WINEDLLPATH" ), *be_runtime = getenv( "PROTON_BATTLEYE_RUNTIME" ); - int i, count = 0; - - if (path) for (p = path, count = 1; *p; p++) if (*p == ':') count++; - -+ if (be_runtime) -+ count += 2; -+ - dll_paths = malloc( (count + 2) * sizeof(*dll_paths) ); - count = 0; - -@@ -543,6 +546,24 @@ static void set_dll_path(void) - free( path ); - } - -+ if (be_runtime) -+ { -+ const char lib32[] = "/v1/lib/wine/"; -+ const char lib64[] = "/v1/lib64/wine/"; -+ -+ p = malloc( strlen(be_runtime) + strlen(lib32) + 1 ); -+ strcpy(p, be_runtime); -+ strcat(p, lib32); -+ -+ dll_paths[count++] = p; -+ -+ p = malloc( strlen(be_runtime) + strlen(lib64) + 1 ); -+ strcpy(p, be_runtime); -+ strcat(p, lib64); -+ -+ dll_paths[count++] = p; -+ } -+ - for (i = 0; i < count; i++) dll_path_maxlen = max( dll_path_maxlen, strlen(dll_paths[i]) ); - dll_paths[count] = NULL; - } -From 1e89f3ebc36d9a867b71b0f8f9aab516a6be90a1 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 30 Mar 2021 21:45:05 -0400 -Subject: [PATCH] kernelbase: Redirect BattlEye Launcher process creation to - game executable. - -Signed-off-by: Derek Lesho - -CW-Bug-Id: #16650 ---- - dlls/kernelbase/process.c | 200 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 200 insertions(+) - -diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c -index 08dad9cb646..b2a49a16177 100644 ---- a/dlls/kernelbase/process.c -+++ b/dlls/kernelbase/process.c -@@ -28,6 +28,7 @@ - #include "windef.h" - #include "winbase.h" - #include "winnls.h" -+#include "winver.h" - #include "wincontypes.h" - #include "winternl.h" - -@@ -486,6 +487,197 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char * - return ret; - } - -+static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, WCHAR **cmd_line) -+{ -+ WCHAR full_path[MAX_PATH], config_path[MAX_PATH]; -+ WCHAR *p; -+ DWORD size; -+ void *block; -+ DWORD *translation; -+ char buf[100]; -+ char *product_name; -+ int launcher_exe_len, game_exe_len, arg_len; -+ HANDLE launcher_cfg; -+ LARGE_INTEGER launcher_cfg_size; -+ char *configs, *config, *arch_32_exe = NULL, *arch_64_exe = NULL, *game_exe, *be_arg = NULL; -+ BOOL wow64; -+ WCHAR *new_cmd_line; -+ -+ if (!GetLongPathNameW( app_name, full_path, MAX_PATH )) lstrcpynW( full_path, app_name, MAX_PATH ); -+ if (!GetFullPathNameW( full_path, MAX_PATH, full_path, NULL )) lstrcpynW( full_path, app_name, MAX_PATH ); -+ -+ /* We detect the BattlEye launcher executable through the product name property, as the executable name varies */ -+ size = GetFileVersionInfoSizeExW(0, full_path, NULL); -+ if (!size) -+ return 0; -+ -+ block = HeapAlloc( GetProcessHeap(), 0, size ); -+ -+ if (!GetFileVersionInfoExW(0, full_path, 0, size, block)) -+ { -+ HeapFree( GetProcessHeap(), 0, block ); -+ return 0; -+ } -+ -+ if (!VerQueryValueA(block, "\\VarFileInfo\\Translation", (void **) &translation, &size) || size != 4) -+ { -+ HeapFree( GetProcessHeap(), 0, block ); -+ return 0; -+ } -+ -+ sprintf(buf, "\\StringFileInfo\\%08x\\ProductName", MAKELONG(HIWORD(*translation), LOWORD(*translation))); -+ -+ if (!VerQueryValueA(block, buf, (void **) &product_name, &size)) -+ { -+ HeapFree( GetProcessHeap(), 0, block ); -+ return 0; -+ } -+ -+ if (strcmp(product_name, "BattlEye Launcher")) -+ { -+ HeapFree( GetProcessHeap(), 0, block); -+ return 0; -+ } -+ -+ HeapFree( GetProcessHeap(), 0, block ); -+ -+ TRACE("Detected launch of a BattlEye Launcher, attempting to launch game executable instead.\n"); -+ -+ lstrcpynW(config_path, full_path, MAX_PATH); -+ -+ for (p = config_path + wcslen(config_path); p != config_path; --p) -+ if (*p == '\\') break; -+ -+ if (*p == '\\') -+ { -+ *p = 0; -+ launcher_exe_len = wcslen(p + 1); -+ } -+ else -+ launcher_exe_len = wcslen(full_path); -+ -+ lstrcatW(config_path, L"\\BattlEye\\BELauncher.ini"); -+ -+ launcher_cfg = CreateFileW(config_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -+ if (launcher_cfg == INVALID_HANDLE_VALUE) -+ return 0; -+ -+ if(!GetFileSizeEx(launcher_cfg, &launcher_cfg_size) || launcher_cfg_size.u.HighPart) -+ { -+ CloseHandle(launcher_cfg); -+ return 0; -+ } -+ -+ configs = HeapAlloc( GetProcessHeap(), 0, launcher_cfg_size.u.LowPart); -+ -+ if (!ReadFile(launcher_cfg, configs, launcher_cfg_size.u.LowPart, &size, NULL) || size != launcher_cfg_size.u.LowPart) -+ { -+ CloseHandle(launcher_cfg); -+ HeapFree( GetProcessHeap(), 0, configs ); -+ return 0; -+ } -+ -+ CloseHandle(launcher_cfg); -+ -+ config = configs; -+ do -+ { -+ if (!strncmp(config, "32BitExe=", 9)) -+ arch_32_exe = config + 9; -+ -+ if (!strncmp(config, "64BitExe=", 9)) -+ arch_64_exe = config + 9; -+ -+ if (!strncmp(config, "BEArg=", 6)) -+ be_arg = config + 6; -+ } -+ while ((config = strchr(config, '\n')) && *(config++)); -+ -+ if (arch_64_exe && (sizeof(void *) == 8 || (IsWow64Process(GetCurrentProcess(), &wow64) && wow64))) -+ game_exe = arch_64_exe; -+ else if (arch_32_exe) -+ game_exe = arch_32_exe; -+ else -+ { -+ HeapFree( GetProcessHeap(), 0, configs ); -+ WARN("Failed to find game executable name from BattlEye config.\n"); -+ return 0; -+ } -+ -+ if (strchr(game_exe, '\r')) -+ *(strchr(game_exe, '\r')) = 0; -+ if (strchr(game_exe, '\n')) -+ *(strchr(game_exe, '\n')) = 0; -+ game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1; -+ -+ if (be_arg) -+ { -+ if (strchr(be_arg, '\r')) -+ *(strchr(be_arg, '\r')) = 0; -+ if (strchr(be_arg, '\n')) -+ *(strchr(be_arg, '\n')) = 0; -+ arg_len = MultiByteToWideChar(CP_ACP, 0, be_arg, -1, NULL, 0) - 1; -+ } -+ -+ TRACE("Launching game executable %s for BattlEye.\n", game_exe); -+ -+ if ((wcslen(app_name) - launcher_exe_len) + game_exe_len + 1 > new_name_len) -+ { -+ HeapFree( GetProcessHeap(), 0, configs ); -+ WARN("Game executable path doesn't fit in buffer.\n"); -+ return 0; -+ } -+ -+ wcscpy(new_name, app_name); -+ p = new_name + wcslen(new_name) - launcher_exe_len; -+ MultiByteToWideChar(CP_ACP, 0, game_exe, -1, p, game_exe_len + 1); -+ -+ /* find and replace executable name in command line, and add BE argument */ -+ p = *cmd_line; -+ if (p[0] == '\"') -+ p++; -+ -+ if (!wcsncmp(p, app_name, wcslen(app_name))) -+ p += wcslen(app_name) - launcher_exe_len; -+ else -+ p = NULL; -+ -+ if (p || be_arg) -+ { -+ size = wcslen(*cmd_line) + 1; -+ if (p) -+ size += game_exe_len - launcher_exe_len; -+ if (be_arg) -+ size += 1 /* space */ + arg_len; -+ size *= sizeof(WCHAR); -+ -+ /* freed by parent function */ -+ new_cmd_line = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); -+ -+ if (p) -+ { -+ lstrcpynW(new_cmd_line, *cmd_line, p - *cmd_line); -+ MultiByteToWideChar(CP_ACP, 0, game_exe, -1, new_cmd_line + wcslen(new_cmd_line), game_exe_len + 1); -+ wcscat(new_cmd_line, p + launcher_exe_len); -+ } -+ else -+ { -+ wcscpy(new_cmd_line, *cmd_line); -+ } -+ -+ if (be_arg) -+ { -+ wcscat(new_cmd_line, L" "); -+ MultiByteToWideChar(CP_ACP, 0, be_arg, -1, new_cmd_line + wcslen(new_cmd_line), arg_len + 1); -+ } -+ -+ *cmd_line = new_cmd_line; -+ } -+ -+ HeapFree( GetProcessHeap(), 0, configs ); -+ return 1; -+} -+ - /********************************************************************** - * CreateProcessInternalW (kernelbase.@) - */ -@@ -550,6 +742,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - app_name = name; - } - -+ p = tidy_cmdline; -+ if (battleye_launcher_redirect_hack( app_name, name, ARRAY_SIZE(name), &tidy_cmdline )) -+ { -+ app_name = name; -+ if (p != tidy_cmdline && p != cmd_line) -+ HeapFree( GetProcessHeap(), 0, p ); -+ } -+ - /* Warn if unsupported features are used */ - - if (flags & (IDLE_PRIORITY_CLASS | HIGH_PRIORITY_CLASS | REALTIME_PRIORITY_CLASS | -From 66e87df57525a8421caa75aad573663f90534fb9 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Thu, 30 Sep 2021 14:38:33 +0200 -Subject: [PATCH] sechost: Fake presence of BEService service for ARK: Survival - Evolved. - -The game uses the presence and status of BEService to determine whether or not the game is running in BattlEye. Since with the Proton Bridge we don't have a dedicated background service, we can just pretend the service is always running. - -CW-Bug-Id: #16650 ---- - dlls/sechost/service.c | 30 ++++++++++++++++++++++++++++++ - 1 file changed, 30 insertions(+) - -diff --git a/dlls/sechost/service.c b/dlls/sechost/service.c -index e6f4eb75db0..d005b64ed19 100644 ---- a/dlls/sechost/service.c -+++ b/dlls/sechost/service.c -@@ -314,6 +314,8 @@ SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR - SC_RPC_HANDLE handle = NULL; - DWORD err; - -+ char str[64]; -+ - TRACE( "%p %s %#lx\n", manager, debugstr_w(name), access ); - - if (!manager) -@@ -322,6 +324,14 @@ SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR - return NULL; - } - -+ /* HACK for ARK: Survivial Evolved checking the status of BEService to determine whether BE is enabled. */ -+ if(GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) && !strcmp(str, "346110") && -+ !wcscmp(name, L"BEService")) -+ { -+ WARN("HACK: returning fake service handle for BEService.\n"); -+ return (void *)0xdeadbeef; -+ } -+ - __TRY - { - err = svcctl_OpenServiceW( manager, name, access, &handle ); -@@ -1106,6 +1116,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS - { - DWORD err; - -+ char str[64]; -+ - TRACE( "%p %d %p %ld %p\n", service, level, buffer, size, ret_size ); - - if (level != SC_STATUS_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL ); -@@ -1116,6 +1128,24 @@ BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS - return set_error( ERROR_INSUFFICIENT_BUFFER ); - } - -+ /* HACK for ARK: Survivial Evolved checking the status of BEService to determine whether BE is enabled. */ -+ if(GetEnvironmentVariableA("SteamGameId", str, sizeof(str)) && !strcmp(str, "346110") && -+ service == (void *)0xdeadbeef) -+ { -+ SERVICE_STATUS_PROCESS *status = (SERVICE_STATUS_PROCESS *)buffer; -+ WARN("HACK: returning fake data for BEService.\n"); -+ status->dwServiceType = SERVICE_WIN32_OWN_PROCESS; -+ status->dwCurrentState = SERVICE_RUNNING; -+ status->dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP; -+ status->dwWin32ExitCode = NO_ERROR; -+ status->dwServiceSpecificExitCode = 0; -+ status->dwCheckPoint = 0; -+ status->dwWaitHint = 0; -+ status->dwProcessId = 0xdeadbee0; -+ status->dwServiceFlags = 0; -+ return TRUE; -+ } -+ - __TRY - { - err = svcctl_QueryServiceStatusEx( service, level, buffer, size, ret_size ); -From c1d58f41052ae7ca24a83983bc9dd8ce4a395c72 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 21 Jan 2022 14:40:43 -0500 -Subject: [PATCH] battleye: Add launcher process instead of redirecting - CreateProcess call. - -Fixes Arma 3 Launcher CW-Bug-Id: #18934 ---- - configure.ac | 1 + - dlls/kernelbase/process.c | 134 ++++---------------------------- - programs/belauncher/Makefile.in | 7 ++ - programs/belauncher/main.c | 116 +++++++++++++++++++++++++++ - 4 files changed, 139 insertions(+), 119 deletions(-) - create mode 100644 programs/belauncher/Makefile.in - create mode 100644 programs/belauncher/main.c - -diff --git a/configure.ac b/configure.ac -index 8e4462b1d4c..bc4f47d9889 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3579,6 +3579,7 @@ WINE_CONFIG_MAKEFILE(po) - WINE_CONFIG_MAKEFILE(programs/arp) - WINE_CONFIG_MAKEFILE(programs/aspnet_regiis) - WINE_CONFIG_MAKEFILE(programs/attrib) -+WINE_CONFIG_MAKEFILE(programs/belauncher) - WINE_CONFIG_MAKEFILE(programs/cabarc) - WINE_CONFIG_MAKEFILE(programs/cacls) - WINE_CONFIG_MAKEFILE(programs/chcp.com) -diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c -index 22f9115011e..01f4ae08721 100644 ---- a/dlls/kernelbase/process.c -+++ b/dlls/kernelbase/process.c -@@ -489,18 +489,15 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalA( HANDLE token, const char * - - static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_name, DWORD new_name_len, WCHAR **cmd_line) - { -- WCHAR full_path[MAX_PATH], config_path[MAX_PATH]; -+ static const WCHAR belauncherW[] = L"c:\\windows\\system32\\belauncher.exe"; -+ -+ WCHAR full_path[MAX_PATH]; - WCHAR *p; - DWORD size; - void *block; - DWORD *translation; - char buf[100]; - char *product_name; -- int launcher_exe_len, game_exe_len, arg_len; -- HANDLE launcher_cfg; -- LARGE_INTEGER launcher_cfg_size; -- char *configs, *config, *arch_32_exe = NULL, *arch_64_exe = NULL, *game_exe, *be_arg = NULL; -- BOOL wow64; - WCHAR *new_cmd_line; - - if (!GetLongPathNameW( app_name, full_path, MAX_PATH )) lstrcpynW( full_path, app_name, MAX_PATH ); -@@ -541,96 +538,15 @@ static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_nam - - HeapFree( GetProcessHeap(), 0, block ); - -- TRACE("Detected launch of a BattlEye Launcher, attempting to launch game executable instead.\n"); -- -- lstrcpynW(config_path, full_path, MAX_PATH); -- -- for (p = config_path + wcslen(config_path); p != config_path; --p) -- if (*p == '\\') break; -- -- if (*p == '\\') -- { -- *p = 0; -- launcher_exe_len = wcslen(p + 1); -- } -- else -- launcher_exe_len = wcslen(full_path); -- -- lstrcatW(config_path, L"\\BattlEye\\BELauncher.ini"); -- -- launcher_cfg = CreateFileW(config_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -- if (launcher_cfg == INVALID_HANDLE_VALUE) -- return 0; -- -- if(!GetFileSizeEx(launcher_cfg, &launcher_cfg_size) || launcher_cfg_size.u.HighPart) -- { -- CloseHandle(launcher_cfg); -- return 0; -- } -- -- configs = HeapAlloc( GetProcessHeap(), 0, launcher_cfg_size.u.LowPart); -- -- if (!ReadFile(launcher_cfg, configs, launcher_cfg_size.u.LowPart, &size, NULL) || size != launcher_cfg_size.u.LowPart) -- { -- CloseHandle(launcher_cfg); -- HeapFree( GetProcessHeap(), 0, configs ); -- return 0; -- } -- -- CloseHandle(launcher_cfg); -- -- config = configs; -- do -- { -- if (!strncmp(config, "32BitExe=", 9)) -- arch_32_exe = config + 9; -- -- if (!strncmp(config, "64BitExe=", 9)) -- arch_64_exe = config + 9; -- -- if (!strncmp(config, "BEArg=", 6)) -- be_arg = config + 6; -- } -- while ((config = strchr(config, '\n')) && *(config++)); -- -- if (arch_64_exe && (sizeof(void *) == 8 || (IsWow64Process(GetCurrentProcess(), &wow64) && wow64))) -- game_exe = arch_64_exe; -- else if (arch_32_exe) -- game_exe = arch_32_exe; -- else -- { -- HeapFree( GetProcessHeap(), 0, configs ); -- WARN("Failed to find game executable name from BattlEye config.\n"); -- return 0; -- } -- -- if (strchr(game_exe, '\r')) -- *(strchr(game_exe, '\r')) = 0; -- if (strchr(game_exe, '\n')) -- *(strchr(game_exe, '\n')) = 0; -- game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1; -- -- if (be_arg) -- { -- if (strchr(be_arg, '\r')) -- *(strchr(be_arg, '\r')) = 0; -- if (strchr(be_arg, '\n')) -- *(strchr(be_arg, '\n')) = 0; -- arg_len = MultiByteToWideChar(CP_ACP, 0, be_arg, -1, NULL, 0) - 1; -- } -- -- TRACE("Launching game executable %s for BattlEye.\n", game_exe); -+ TRACE("Detected launch of a BattlEye Launcher, redirecting to Proton version.\n"); - -- if ((wcslen(app_name) - launcher_exe_len) + game_exe_len + 1 > new_name_len) -+ if (new_name_len < wcslen(belauncherW) + 1) - { -- HeapFree( GetProcessHeap(), 0, configs ); - WARN("Game executable path doesn't fit in buffer.\n"); - return 0; - } - -- wcscpy(new_name, app_name); -- p = new_name + wcslen(new_name) - launcher_exe_len; -- MultiByteToWideChar(CP_ACP, 0, game_exe, -1, p, game_exe_len + 1); -+ wcscpy(new_name, belauncherW); - - /* find and replace executable name in command line, and add BE argument */ - p = *cmd_line; -@@ -638,43 +554,23 @@ static int battleye_launcher_redirect_hack(const WCHAR *app_name, WCHAR *new_nam - p++; - - if (!wcsncmp(p, app_name, wcslen(app_name))) -- p += wcslen(app_name) - launcher_exe_len; -- else -- p = NULL; -- -- if (p || be_arg) - { -- size = wcslen(*cmd_line) + 1; -- if (p) -- size += game_exe_len - launcher_exe_len; -- if (be_arg) -- size += 1 /* space */ + arg_len; -- size *= sizeof(WCHAR); -+ new_cmd_line = HeapAlloc( GetProcessHeap(), 0, ( wcslen(*cmd_line) + wcslen(belauncherW) + 1 - wcslen(app_name) ) * sizeof(WCHAR) ); - -- /* freed by parent function */ -- new_cmd_line = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ); -+ wcscpy(new_cmd_line, *cmd_line); -+ p = new_cmd_line; -+ if (p[0] == '\"') -+ p++; - -- if (p) -- { -- lstrcpynW(new_cmd_line, *cmd_line, p - *cmd_line); -- MultiByteToWideChar(CP_ACP, 0, game_exe, -1, new_cmd_line + wcslen(new_cmd_line), game_exe_len + 1); -- wcscat(new_cmd_line, p + launcher_exe_len); -- } -- else -- { -- wcscpy(new_cmd_line, *cmd_line); -- } -+ memmove( p + wcslen(belauncherW), p + wcslen(app_name), (wcslen(p) - wcslen(belauncherW)) * sizeof(WCHAR) ); -+ memcpy( p, belauncherW, wcslen(belauncherW) * sizeof(WCHAR) ); - -- if (be_arg) -- { -- wcscat(new_cmd_line, L" "); -- MultiByteToWideChar(CP_ACP, 0, be_arg, -1, new_cmd_line + wcslen(new_cmd_line), arg_len + 1); -- } -+ TRACE("old command line %s.\n", debugstr_w(*cmd_line)); -+ TRACE("new command line %s.\n", debugstr_w(new_cmd_line)); - - *cmd_line = new_cmd_line; - } - -- HeapFree( GetProcessHeap(), 0, configs ); - return 1; - } - -diff --git a/programs/belauncher/Makefile.in b/programs/belauncher/Makefile.in -new file mode 100644 -index 00000000000..f2dc59b07ce ---- /dev/null -+++ b/programs/belauncher/Makefile.in -@@ -0,0 +1,7 @@ -+MODULE = belauncher.exe -+IMPORTS = -+ -+EXTRADLLFLAGS = -mwindows -municode -+ -+C_SRCS = \ -+ main.c \ -diff --git a/programs/belauncher/main.c b/programs/belauncher/main.c -new file mode 100644 -index 00000000000..0f727f3ca7d ---- /dev/null -+++ b/programs/belauncher/main.c -@@ -0,0 +1,116 @@ -+#define WIN32_LEAN_AND_MEAN -+#include -+ -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(belauncher); -+ -+int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cmdshow) -+{ -+ char *configs, *config, *arch_32_exe = NULL, *arch_64_exe = NULL, *game_exe, *be_arg = NULL; -+ LARGE_INTEGER launcher_cfg_size; -+ unsigned char battleye_status; -+ int game_exe_len, arg_len; -+ PROCESS_INFORMATION pi; -+ HANDLE launcher_cfg; -+ LPWSTR launch_cmd; -+ STARTUPINFOW si = {0}; -+ DWORD size; -+ BOOL wow64; -+ -+ battleye_status = 0x3; /* Starting */ -+ _write(1, &battleye_status, 1); -+ -+ launcher_cfg = CreateFileW(L"Battleye\\BELauncher.ini", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -+ if (launcher_cfg == INVALID_HANDLE_VALUE) -+ goto start_failed; -+ -+ if(!GetFileSizeEx(launcher_cfg, &launcher_cfg_size) || launcher_cfg_size.u.HighPart) -+ { -+ CloseHandle(launcher_cfg); -+ goto start_failed; -+ } -+ -+ configs = HeapAlloc( GetProcessHeap(), 0, launcher_cfg_size.u.LowPart); -+ -+ if (!ReadFile(launcher_cfg, configs, launcher_cfg_size.u.LowPart, &size, NULL) || size != launcher_cfg_size.u.LowPart) -+ { -+ CloseHandle(launcher_cfg); -+ HeapFree( GetProcessHeap(), 0, configs ); -+ goto start_failed; -+ } -+ -+ CloseHandle(launcher_cfg); -+ -+ config = configs; -+ do -+ { -+ if (!strncmp(config, "32BitExe=", 9)) -+ arch_32_exe = config + 9; -+ -+ if (!strncmp(config, "64BitExe=", 9)) -+ arch_64_exe = config + 9; -+ -+ if (!strncmp(config, "BEArg=", 6)) -+ be_arg = config + 6; -+ } -+ while ((config = strchr(config, '\n')) && *(config++)); -+ -+ if (arch_64_exe && (sizeof(void *) == 8 || (IsWow64Process(GetCurrentProcess(), &wow64) && wow64))) -+ game_exe = arch_64_exe; -+ else if (arch_32_exe) -+ game_exe = arch_32_exe; -+ else -+ { -+ HeapFree( GetProcessHeap(), 0, configs ); -+ WINE_WARN("Failed to find game executable name from BattlEye config.\n"); -+ goto start_failed; -+ } -+ -+ if (strchr(game_exe, '\r')) -+ *(strchr(game_exe, '\r')) = 0; -+ if (strchr(game_exe, '\n')) -+ *(strchr(game_exe, '\n')) = 0; -+ game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1; -+ -+ if (be_arg) -+ { -+ if (strchr(be_arg, '\r')) -+ *(strchr(be_arg, '\r')) = 0; -+ if (strchr(be_arg, '\n')) -+ *(strchr(be_arg, '\n')) = 0; -+ arg_len = MultiByteToWideChar(CP_ACP, 0, be_arg, -1, NULL, 0) - 1; -+ } -+ -+ WINE_TRACE("Launching game executable %s for BattlEye.\n", game_exe); -+ battleye_status = 0x9; /* Launching Game */ -+ _write(1, &battleye_status, 1); -+ -+ launch_cmd = HeapAlloc(GetProcessHeap(), 0, (game_exe_len + 1 + wcslen(cmdline) + 1 + arg_len + 1) * sizeof(WCHAR)); -+ MultiByteToWideChar(CP_ACP, 0, game_exe, -1, launch_cmd, game_exe_len + 1); -+ launch_cmd[game_exe_len] = ' '; -+ -+ wcscpy(launch_cmd + game_exe_len + 1, cmdline); -+ launch_cmd[game_exe_len + 1 + wcslen(cmdline)] = ' '; -+ -+ MultiByteToWideChar(CP_ACP, 0, be_arg, -1, launch_cmd + game_exe_len + 1 + wcslen(cmdline) + 1, arg_len + 1); -+ -+ if (!CreateProcessW(NULL, launch_cmd, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) -+ { -+ battleye_status = 0xA; /* Launch Failed */ -+ _write(1, &battleye_status, 1); -+ -+ HeapFree( GetProcessHeap(), 0, launch_cmd ); -+ return GetLastError(); -+ } -+ HeapFree( GetProcessHeap(), 0, launch_cmd ); -+ -+ WaitForSingleObject(pi.hProcess, INFINITE); -+ CloseHandle(pi.hProcess); -+ return 0; -+ -+start_failed: -+ battleye_status = 0x4; /* Start Failed */ -+ _write(1, &battleye_status, 1); -+ return 0; -+} -From 0de1a4cb50828f0867253d2fb3d6d679d4b8a39d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 15 Feb 2022 10:56:31 +0100 -Subject: [PATCH] fixup! battleye: Add launcher process instead of redirecting - CreateProcess call. - ---- - programs/belauncher/main.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/programs/belauncher/main.c b/programs/belauncher/main.c -index 0f727f3ca7d..86ec46ecee4 100644 ---- a/programs/belauncher/main.c -+++ b/programs/belauncher/main.c -@@ -73,7 +73,8 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR cmdline, int cm - *(strchr(game_exe, '\n')) = 0; - game_exe_len = MultiByteToWideChar(CP_ACP, 0, game_exe, -1, NULL, 0) - 1; - -- if (be_arg) -+ if (!be_arg) arg_len = 0; -+ else - { - if (strchr(be_arg, '\r')) - *(strchr(be_arg, '\r')) = 0; diff --git a/patches/proton/60-proton-14-msedgewebview-registry.patch b/patches/proton/60-proton-14-msedgewebview-registry.patch deleted file mode 100644 index f7cad6819..000000000 --- a/patches/proton/60-proton-14-msedgewebview-registry.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 422efcea69fe9a56c384e25074f135d6f5d78abe Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 10 Nov 2021 20:30:40 +0300 -Subject: [PATCH] wine.inf: HACK: Spoof Win81 for msedgewebview2.exe. - -A proper fix depends on other process window Vulkan rendering -and Direct Compositing implementation. - -CW-Bug-ID: #19618 - -For FH5. ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 3c927c207a8..09a0b1b3eaf 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4238,6 +4238,7 @@ HKCU,Software\Wine\AppDefaults\Paradox Launcher.exe\DllOverrides,"libglesv2",,"d - HKCU,Software\Wine\AppDefaults\Nickelodeon All-Star Brawl.exe\DllOverrides,"winusb",,"disabled" - HKCU,Software\Wine\AppDefaults\nw.exe\DllOverrides,"libglesv2",,"disabled" - HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\msedgewebview2.exe,"Version",,"win81" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" - diff --git a/patches/proton/61-proton-15-FH5-amd_ags_registry.patch b/patches/proton/61-proton-15-FH5-amd_ags_registry.patch deleted file mode 100644 index 3c6fac6fb..000000000 --- a/patches/proton/61-proton-15-FH5-amd_ags_registry.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 318e90ad39261891c323469e1920282bc0580248 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 10 Nov 2021 20:34:24 +0300 -Subject: [PATCH] wine.inf: Set amd_ags_x64 to built-in for FH5. - -CW-Bug-Id: #19618 ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 09a0b1b3eaf..c9371ee3882 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4239,6 +4239,7 @@ HKCU,Software\Wine\AppDefaults\Nickelodeon All-Star Brawl.exe\DllOverrides,"winu - HKCU,Software\Wine\AppDefaults\nw.exe\DllOverrides,"libglesv2",,"disabled" - HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\msedgewebview2.exe,"Version",,"win81" -+HKCU,Software\Wine\AppDefaults\ForzaHorizon5.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - HKCU,Software\Wine\DllOverrides,"atl100",0x2,"native,builtin" - HKCU,Software\Wine\DllOverrides,"msvcp100",0x2,"native,builtin" - diff --git a/patches/proton/62-proton-16-Age-of-Empires-IV-registry.patch b/patches/proton/62-proton-16-Age-of-Empires-IV-registry.patch deleted file mode 100644 index 2a110a65e..000000000 --- a/patches/proton/62-proton-16-Age-of-Empires-IV-registry.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 13d8c8c3aef01d194abf9c7c2c601e94b8d6732e Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 12 Nov 2021 14:21:08 -0600 -Subject: [PATCH] wine.inf: Use built-in atiadlxx for Age of Empires IV. - -CW-Bug-ID: #19602 - -Avoids the warning about too old drivers on start. ---- - loader/wine.inf.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index c9371ee3882..c54af68914b 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -4238,6 +4238,7 @@ HKCU,Software\Wine\AppDefaults\Paradox Launcher.exe\DllOverrides,"libglesv2",,"d - HKCU,Software\Wine\AppDefaults\Nickelodeon All-Star Brawl.exe\DllOverrides,"winusb",,"disabled" - HKCU,Software\Wine\AppDefaults\nw.exe\DllOverrides,"libglesv2",,"disabled" - HKCU,Software\Wine\AppDefaults\gotg.exe\DllOverrides,"atiadlxx",,"builtin" -+HKCU,Software\Wine\AppDefaults\RelicCardinal.exe\DllOverrides,"atiadlxx",,"builtin" - HKCU,Software\Wine\AppDefaults\msedgewebview2.exe,"Version",,"win81" - HKCU,Software\Wine\AppDefaults\ForzaHorizon5.exe\DllOverrides,"amd_ags_x64",0x2,"builtin" - ;;Likely want *80 and *90 too, but those require removing Wine's manifest files. - diff --git a/patches/proton/63-ntdll-Support-x86_64-syscall-emulation.patch b/patches/proton/63-ntdll-Support-x86_64-syscall-emulation.patch deleted file mode 100644 index b635ec46c..000000000 --- a/patches/proton/63-ntdll-Support-x86_64-syscall-emulation.patch +++ /dev/null @@ -1,230 +0,0 @@ -From d7be25a11e01c6f223b39df2fb45cc9f531f6c83 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 14 Jul 2020 15:00:34 +0300 -Subject: [PATCH] ntdll: Support x86_64 syscall emulation. - ---- - configure.ac | 1 + - dlls/ntdll/unix/signal_x86_64.c | 118 ++++++++++++++++++++++++++++++++ - include/config.h.in | 3 + - tools/winebuild/import.c | 3 +- - 5 files changed, 125 insertions(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 6202d68ee45..bcc37745576 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -448,6 +448,7 @@ AC_CHECK_HEADERS(\ - linux/ioctl.h \ - linux/major.h \ - linux/param.h \ -+ linux/seccomp.h \ - linux/serial.h \ - linux/types.h \ - linux/ucdrom.h \ -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 06d99545913..9a46b4a50b0 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -27,11 +27,13 @@ - #include "config.h" - - #include -+#include - #include - #include - #include - #include - #include -+#include - #include - #include - #include -@@ -65,6 +67,13 @@ - # include - #endif - -+#if defined(HAVE_LINUX_FILTER_H) && defined(HAVE_LINUX_SECCOMP_H) && defined(HAVE_SYS_PRCTL_H) -+#define HAVE_SECCOMP 1 -+# include -+# include -+# include -+#endif -+ - #define NONAMELESSUNION - #define NONAMELESSSTRUCT - #include "ntstatus.h" -@@ -2432,6 +2441,119 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) - return 0; - } - -+#ifdef HAVE_SECCOMP -+static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -+{ -+ ULONG64 *dispatcher_address = (ULONG64 *)((char *)user_shared_data + page_size); -+ ucontext_t *ctx = sigcontext; -+ void ***rsp; -+ -+ TRACE("SIGSYS, rax %#llx, rip %#llx.\n", ctx->uc_mcontext.gregs[REG_RAX], -+ ctx->uc_mcontext.gregs[REG_RIP]); -+ -+ rsp = (void ***)&ctx->uc_mcontext.gregs[REG_RSP]; -+ *rsp -= 1; -+ **rsp = (void *)(ctx->uc_mcontext.gregs[REG_RIP] + 0xb); -+ -+ ctx->uc_mcontext.gregs[REG_RIP] = *dispatcher_address; -+} -+#endif -+ -+#ifdef HAVE_SECCOMP -+static int sc_seccomp(unsigned int operation, unsigned int flags, void *args) -+{ -+#ifndef __NR_seccomp -+# define __NR_seccomp 317 -+#endif -+ return syscall(__NR_seccomp, operation, flags, args); -+} -+#endif -+ -+static void check_bpf_jit_enable(void) -+{ -+ char enabled; -+ int fd; -+ -+ fd = open("/proc/sys/net/core/bpf_jit_enable", O_RDONLY); -+ if (fd == -1) -+ { -+ WARN("Could not open /proc/sys/net/core/bpf_jit_enable.\n"); -+ return; -+ } -+ -+ if (read(fd, &enabled, sizeof(enabled)) == sizeof(enabled)) -+ { -+ TRACE("enabled %#x.\n", enabled); -+ -+ if (enabled != '1') -+ ERR("BPF JIT is not enabled in the kernel, enable it to reduce syscall emulation overhead.\n"); -+ } -+ else -+ { -+ WARN("Could not read /proc/sys/net/core/bpf_jit_enable.\n"); -+ } -+ close(fd); -+} -+ -+static void install_bpf(struct sigaction *sig_act) -+{ -+#ifdef HAVE_SECCOMP -+# ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW -+# define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) -+# endif -+ -+# ifndef SECCOMP_SET_MODE_FILTER -+# define SECCOMP_SET_MODE_FILTER 1 -+# endif -+ static const unsigned int flags = SECCOMP_FILTER_FLAG_SPEC_ALLOW; -+ static struct sock_filter filter[] = -+ { -+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, -+ (offsetof(struct seccomp_data, nr))), -+ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, 0xf000, 0, 1), -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_TRAP), -+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), -+ }; -+ struct syscall_frame *frame = amd64_thread_data()->syscall_frame; -+ struct sock_fprog prog; -+ NTSTATUS status; -+ -+ sig_act->sa_sigaction = sigsys_handler; -+ sigaction(SIGSYS, sig_act, NULL); -+ -+ frame->syscall_flags = syscall_flags; -+ frame->syscall_table = KeServiceDescriptorTable; -+ -+ if ((status = syscall(0xffff)) == STATUS_INVALID_PARAMETER) -+ { -+ TRACE("Seccomp filters already installed.\n"); -+ return; -+ } -+ if (status != -ENOSYS && (status != -1 || errno != ENOSYS)) -+ { -+ ERR("Unexpected status %#x, errno %d.\n", status, errno); -+ return; -+ } -+ -+ memset(&prog, 0, sizeof(prog)); -+ prog.len = ARRAY_SIZE(filter); -+ prog.filter = filter; -+ -+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) -+ { -+ ERR("prctl(PR_SET_NO_NEW_PRIVS, ...): %s.\n", strerror(errno)); -+ return; -+ } -+ if (sc_seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog)) -+ { -+ ERR("prctl(PR_SET_SECCOMP, ...): %s.\n", strerror(errno)); -+ return; -+ } -+ check_bpf_jit_enable(); -+#else -+ WARN("Built without seccomp.\n"); -+#endif -+} - - /*********************************************************************** - * handle_interrupt -@@ -2816,6 +2937,7 @@ void signal_init_process(void) - if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -+ install_bpf(&sig_act); - return; - - error: -@@ -3228,6 +3350,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, - "leaq 0x28(%rsp),%rsi\n\t" /* first argument */ - "movq %rcx,%rsp\n\t" - "movq 0x00(%rcx),%rax\n\t" -+ "subq $0xf000,%rax\n\t" - "movq 0x18(%rcx),%rdx\n\t" - "movl %eax,%ebx\n\t" - "shrl $8,%ebx\n\t" -diff --git a/include/config.h.in b/include/config.h.in -index cf3aaa17a5d..b602a292eea 100644 ---- a/include/config.h.in -+++ b/include/config.h.in -@@ -450,6 +450,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_LINUX_RTNETLINK_H - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_LINUX_SECCOMP_H -+ - /* Define to 1 if you have the header file. */ - #undef HAVE_LINUX_SERIAL_H - -diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c -index 720cf0589fd..9a7537451ae 100644 ---- a/tools/winebuild/import.c -+++ b/tools/winebuild/import.c -@@ -1366,7 +1366,6 @@ static int cmp_link_name( const void *e1, const void *e2 ) - return strcmp( odp1->link_name, odp2->link_name ); - } - -- - /* output the functions for system calls */ - void output_syscalls( DLLSPEC *spec ) - { -@@ -1424,7 +1423,7 @@ void output_syscalls( DLLSPEC *spec ) - * validate that instruction, we can just put a jmp there instead. */ - output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */ - output( "\t.byte 0xb8\n" ); /* movl $i,%eax */ -- output( "\t.long %u\n", id ); -+ output( "\t.long %u\n", 0xf000 + id ); - output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */ - output( "\t.byte 0x75,0x03\n" ); /* jne 1f */ - output( "\t.byte 0x0f,0x05\n" ); /* syscall */ --- -2.33.0 - diff --git a/patches/proton/64-ntdll-Do-a-device-check-before-returning-a-default-s.patch b/patches/proton/64-ntdll-Do-a-device-check-before-returning-a-default-s.patch deleted file mode 100644 index a73c3fb24..000000000 --- a/patches/proton/64-ntdll-Do-a-device-check-before-returning-a-default-s.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 6684c0f0f73c1664c923ba150e1cb663704d8991 Mon Sep 17 00:00:00 2001 -From: Alex Henrie -Date: Tue, 29 Dec 2015 00:48:02 -0700 -Subject: [PATCH] mountmgr.sys: Do a device check before returning a default - serial port name. - -Fixes https://bugs.winehq.org/show_bug.cgi?id=39793 ---- - dlls/mountmgr.sys/device.c | 2 +- - dlls/mountmgr.sys/unixlib.c | 22 ++++++++++++++++++++++ - dlls/mountmgr.sys/unixlib.h | 1 + - 3 files changed, 24 insertions(+), 1 deletion(-) - -diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c -index 8c2808bb643..57ae874b247 100644 ---- a/dlls/mountmgr.sys/device.c -+++ b/dlls/mountmgr.sys/device.c -@@ -1868,7 +1868,7 @@ static BOOL create_port_device( DRIVER_OBJECT *driver, int n, const char *unix_p - UNICODE_STRING nt_name, symlink_name, default_name; - DEVICE_OBJECT *dev_obj; - NTSTATUS status; -- struct set_dosdev_symlink_params params = { dosdevices_path, unix_path }; -+ struct set_dosdev_symlink_params params = { dosdevices_path, unix_path, driver == serial_driver }; - - /* create DOS device */ - if (MOUNTMGR_CALL( set_dosdev_symlink, ¶ms )) return FALSE; -diff --git a/dlls/mountmgr.sys/unixlib.c b/dlls/mountmgr.sys/unixlib.c -index 73735c22d13..f83f7104d82 100644 ---- a/dlls/mountmgr.sys/unixlib.c -+++ b/dlls/mountmgr.sys/unixlib.c -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - - #include "unixlib.h" - -@@ -268,6 +269,27 @@ static NTSTATUS set_dosdev_symlink( void *args ) - char *path; - NTSTATUS status = STATUS_SUCCESS; - -+#ifdef linux -+ /* Serial port device files almost always exist on Linux even if the corresponding serial -+ * ports don't exist. Do a basic functionality check before advertising a serial port. */ -+ if (params->serial) -+ { -+ struct termios tios; -+ int fd; -+ -+ if ((fd = open( params->dest, O_RDONLY )) == -1) -+ return FALSE; -+ -+ if (tcgetattr( fd, &tios ) == -1) -+ { -+ close( fd ); -+ return FALSE; -+ } -+ -+ close( fd ); -+ } -+#endif -+ - if (!(path = get_dosdevices_path( params->dev ))) return STATUS_NO_MEMORY; - - if (params->dest && params->dest[0]) -diff --git a/dlls/mountmgr.sys/unixlib.h b/dlls/mountmgr.sys/unixlib.h -index 188cf93b091..31f5e8a807e 100644 ---- a/dlls/mountmgr.sys/unixlib.h -+++ b/dlls/mountmgr.sys/unixlib.h -@@ -75,6 +75,7 @@ struct set_dosdev_symlink_params - { - const char *dev; - const char *dest; -+ BOOL serial; - }; - - struct get_volume_dos_devices_params --- -2.33.0 - diff --git a/patches/proton/66-proton-EAC-bridge.patch b/patches/proton/66-proton-EAC-bridge.patch deleted file mode 100644 index a0bef5177..000000000 --- a/patches/proton/66-proton-EAC-bridge.patch +++ /dev/null @@ -1,180 +0,0 @@ -From b39cb3bfe9dafd6affe74f7657cd7fe41b52137f Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Mon, 6 Dec 2021 15:13:40 +0100 -Subject: [PATCH] ntdll: Load EAC bridge files from PROTON_EAC_RUNTIME path. - ---- - dlls/ntdll/unix/loader.c | 23 ++++++++++++++++++++++- - 1 file changed, 22 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 711b7224bfc..1d4160727e4 100644 ---- a/dlls/ntdll/unix/loader.c -+++ b/dlls/ntdll/unix/loader.c -@@ -526,7 +526,7 @@ static const char *get_pe_dir( WORD machine ) - - static void set_dll_path(void) - { -- char *p, *path = getenv( "WINEDLLPATH" ), *be_runtime = getenv( "PROTON_BATTLEYE_RUNTIME" ); -+ char *p, *path = getenv( "WINEDLLPATH" ), *be_runtime = getenv( "PROTON_BATTLEYE_RUNTIME" ), *eac_runtime = getenv( "PROTON_EAC_RUNTIME" ); - int i, count = 0; - - if (path) for (p = path, count = 1; *p; p++) if (*p == ':') count++; -@@ -534,6 +534,9 @@ static void set_dll_path(void) - if (be_runtime) - count += 2; - -+ if (eac_runtime) -+ count += 2; -+ - dll_paths = malloc( (count + 2) * sizeof(*dll_paths) ); - count = 0; - -@@ -564,6 +567,24 @@ static void set_dll_path(void) - dll_paths[count++] = p; - } - -+ if (eac_runtime) -+ { -+ const char lib32[] = "/v2/lib32/"; -+ const char lib64[] = "/v2/lib64/"; -+ -+ p = malloc( strlen(eac_runtime) + strlen(lib32) + 1 ); -+ strcpy(p, eac_runtime); -+ strcat(p, lib32); -+ -+ dll_paths[count++] = p; -+ -+ p = malloc( strlen(eac_runtime) + strlen(lib64) + 1 ); -+ strcpy(p, eac_runtime); -+ strcat(p, lib64); -+ -+ dll_paths[count++] = p; -+ } -+ - for (i = 0; i < count; i++) dll_path_maxlen = max( dll_path_maxlen, strlen(dll_paths[i]) ); - dll_paths[count] = NULL; - } -From 240b2813a7a5e0fe1cda611961f78b2a9b0c99be Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Tue, 18 Jan 2022 17:16:15 -0500 -Subject: [PATCH] ntdll: Only load EAC bridge when Linux library is present. - ---- - dlls/ntdll/unix/loadorder.c | 39 +++++++++++++++++++++++++++++++++++++ - 1 file changed, 39 insertions(+) - -diff --git a/dlls/ntdll/unix/loadorder.c b/dlls/ntdll/unix/loadorder.c -index aa987a80186..be25b2213d9 100644 ---- a/dlls/ntdll/unix/loadorder.c -+++ b/dlls/ntdll/unix/loadorder.c -@@ -378,6 +378,10 @@ void set_load_order_app_name( const WCHAR *app_name ) - */ - enum loadorder get_load_order( const UNICODE_STRING *nt_name ) - { -+ static const WCHAR easyanticheat_x86W[] = {'e','a','s','y','a','n','t','i','c','h','e','a','t','_','x','8','6','.','d','l','l',0}; -+ static const WCHAR easyanticheat_x64W[] = {'e','a','s','y','a','n','t','i','c','h','e','a','t','_','x','6','4','.','d','l','l',0}; -+ static const WCHAR soW[] = {'s','o',0}; -+ - static const WCHAR prefixW[] = {'\\','?','?','\\'}; - enum loadorder ret = LO_INVALID; - const WCHAR *path = nt_name->Buffer; -@@ -391,6 +395,41 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name ) - - TRACE("looking for %s\n", debugstr_w(path)); - -+ /* HACK: special logic for easyanticheat bridge: only load the bridge (builtin) if there exists a native version of the library next to the windows version */ -+ basename = get_basename((WCHAR *)path); -+ if (!wcsicmp(basename, easyanticheat_x86W) || !wcsicmp(basename, easyanticheat_x64W)) -+ { -+ UNICODE_STRING eac_unix_name; -+ OBJECT_ATTRIBUTES attr; -+ char *unix_path = NULL; -+ NTSTATUS status; -+ -+ len = wcslen(nt_name->Buffer); -+ eac_unix_name.Buffer = malloc( (len + 1) * sizeof(WCHAR) ); -+ wcscpy(eac_unix_name.Buffer, nt_name->Buffer); -+ -+ basename = get_basename(eac_unix_name.Buffer); -+ wcscpy(&basename[18], soW); -+ eac_unix_name.Length = eac_unix_name.MaximumLength = wcslen(eac_unix_name.Buffer) * sizeof(WCHAR); -+ InitializeObjectAttributes(&attr, &eac_unix_name, 0, NULL, NULL); -+ -+ if (!(status = nt_to_unix_file_name(&attr, &unix_path, FILE_OPEN))) -+ { -+ free(unix_path); -+ free(eac_unix_name.Buffer); -+ ret = LO_BUILTIN; -+ TRACE( "got hardcoded %s for %s, as the eac unix library is present\n", debugstr_loadorder(ret), debugstr_w(path) ); -+ return ret; -+ } -+ else -+ { -+ ret = LO_NATIVE; -+ TRACE( "got hardcoded %s for %s, as the eac unix library (%s) is not present. status %x\n", debugstr_loadorder(ret), debugstr_w(path), debugstr_w(eac_unix_name.Buffer), status ); -+ free(eac_unix_name.Buffer); -+ return ret; -+ } -+ } -+ - /* Strip path information if the module resides in the system directory - */ - if (!wcsnicmp( system_dir + 4, path, wcslen(system_dir) - 4 )) - -From 9dce79072ef483dda3674345eaf2274fd06dac89 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 21 Jan 2022 14:42:12 -0500 -Subject: [PATCH] kernelbase: Add stub for GetConsoleSelectionInfo. - -Signed-off-by: Derek Lesho ---- - dlls/kernel32/kernel32.spec | 2 +- - dlls/kernelbase/console.c | 8 ++++++++ - dlls/kernelbase/kernelbase.spec | 1 + - 3 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec -index 1d89c7f3cc0..37f419116ad 100644 ---- a/dlls/kernel32/kernel32.spec -+++ b/dlls/kernel32/kernel32.spec -@@ -616,7 +616,7 @@ - @ stdcall -import GetConsoleProcessList(ptr long) - @ stdcall -import GetConsoleScreenBufferInfo(long ptr) - @ stdcall -import GetConsoleScreenBufferInfoEx(long ptr) --# @ stub GetConsoleSelectionInfo -+@ stdcall -import GetConsoleSelectionInfo(ptr) - @ stdcall -import GetConsoleTitleA(ptr long) - @ stdcall -import GetConsoleTitleW(ptr long) - @ stdcall -import GetConsoleWindow() -diff --git a/dlls/kernelbase/console.c b/dlls/kernelbase/console.c -index a7eeb439232..98f2483011b 100644 ---- a/dlls/kernelbase/console.c -+++ b/dlls/kernelbase/console.c -@@ -742,6 +742,14 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleScreenBufferInfoEx( HANDLE handle, - } - - -+BOOL WINAPI DECLSPEC_HOTPATCH GetConsoleSelectionInfo(CONSOLE_SELECTION_INFO *info) -+{ -+ FIXME("stub (%p)\n", info); -+ info->dwFlags = CONSOLE_NO_SELECTION; -+ return TRUE; -+} -+ -+ - /****************************************************************************** - * GetConsoleTitleW (kernelbase.@) - */ -diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec -index abbb137ef7f..b61c83e5ed9 100644 ---- a/dlls/kernelbase/kernelbase.spec -+++ b/dlls/kernelbase/kernelbase.spec -@@ -449,6 +449,7 @@ - @ stdcall GetConsoleProcessList(ptr long) - @ stdcall GetConsoleScreenBufferInfo(long ptr) - @ stdcall GetConsoleScreenBufferInfoEx(long ptr) -+@ stdcall GetConsoleSelectionInfo(ptr) - @ stdcall GetConsoleTitleA(ptr long) - @ stdcall GetConsoleTitleW(ptr long) - @ stdcall GetConsoleWindow() diff --git a/patches/proton/67-protonify-2.patch b/patches/proton/67-protonify-2.patch deleted file mode 100644 index 1019c8d69..000000000 --- a/patches/proton/67-protonify-2.patch +++ /dev/null @@ -1,5297 +0,0 @@ -From 40f9cbafbf1d7d5cfecf6d765e440ff03ce2376d Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 6 Jan 2022 14:00:35 +0300 -Subject: [PATCH] winhttp: HACK: Reuse threadpool for Monster Hunter Rise. - -CW-Bug-Id: #19484 ---- - dlls/winhttp/main.c | 6 ++++ - dlls/winhttp/request.c | 64 +++++++++++++++++++++++++++++++--- - dlls/winhttp/winhttp_private.h | 1 + - 3 files changed, 67 insertions(+), 4 deletions(-) - -diff --git a/dlls/winhttp/main.c b/dlls/winhttp/main.c -index 3b570fee6d5..c8de51fa85b 100644 ---- a/dlls/winhttp/main.c -+++ b/dlls/winhttp/main.c -@@ -42,9 +42,15 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) - switch(fdwReason) - { - case DLL_PROCESS_ATTACH: -+ { -+ char str[64]; -+ - winhttp_instance = hInstDLL; - DisableThreadLibraryCalls(hInstDLL); -+ if ((reuse_threadpool = GetEnvironmentVariableA( "SteamGameId", str, sizeof(str)) && !strcmp(str, "1446780" ))) -+ ERR( "HACK: setting reuse_threadpool.\n" ); - break; -+ } - case DLL_PROCESS_DETACH: - if (lpv) break; - netconn_unload(); -diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c -index a2a5774d74d..ee6e2eca847 100644 ---- a/dlls/winhttp/request.c -+++ b/dlls/winhttp/request.c -@@ -43,6 +43,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(winhttp); - - #define DEFAULT_KEEP_ALIVE_TIMEOUT 30000 - -+BOOL reuse_threadpool; -+ -+static struct -+{ -+ TP_POOL *pool; -+ LONG ref; -+} -+thread_pool_cache; -+ -+static CRITICAL_SECTION thread_pool_cache_cs; -+static CRITICAL_SECTION_DEBUG thread_pool_cache_debug = -+{ -+ 0, 0, &thread_pool_cache_cs, -+ { &thread_pool_cache_debug.ProcessLocksList, &thread_pool_cache_debug.ProcessLocksList }, -+ 0, 0, { (DWORD_PTR)(__FILE__ ": thread_pool_cache_cs") } -+}; -+static CRITICAL_SECTION thread_pool_cache_cs = { &thread_pool_cache_debug, -1, 0, 0, 0, 0 }; -+ - static const WCHAR *attribute_table[] = - { - L"Mime-Version", /* WINHTTP_QUERY_MIME_VERSION = 0 */ -@@ -122,13 +140,37 @@ static const WCHAR *attribute_table[] = - NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */ - }; - -+static TP_POOL *create_thread_pool(void) -+{ -+ TP_POOL *pool; -+ -+ if (!(pool = CreateThreadpool( NULL ))) return NULL; -+ SetThreadpoolThreadMinimum( pool, 1 ); -+ SetThreadpoolThreadMaximum( pool, 1 ); -+ -+ return pool; -+} -+ - static DWORD start_queue( struct queue *queue ) - { - if (queue->pool) return ERROR_SUCCESS; - -- if (!(queue->pool = CreateThreadpool( NULL ))) return GetLastError(); -- SetThreadpoolThreadMinimum( queue->pool, 1 ); -- SetThreadpoolThreadMaximum( queue->pool, 1 ); -+ if (reuse_threadpool) -+ { -+ EnterCriticalSection( &thread_pool_cache_cs ); -+ if (!thread_pool_cache.pool) -+ { -+ assert( !thread_pool_cache.ref ); -+ thread_pool_cache.pool = create_thread_pool(); -+ } -+ ++thread_pool_cache.ref; -+ queue->pool = thread_pool_cache.pool; -+ LeaveCriticalSection( &thread_pool_cache_cs ); -+ } -+ else -+ { -+ if (!(queue->pool = create_thread_pool())) return GetLastError(); -+ } - - memset( &queue->env, 0, sizeof(queue->env) ); - queue->env.Version = 1; -@@ -141,7 +183,21 @@ static DWORD start_queue( struct queue *queue ) - void stop_queue( struct queue *queue ) - { - if (!queue->pool) return; -- CloseThreadpool( queue->pool ); -+ if (reuse_threadpool) -+ { -+ EnterCriticalSection( &thread_pool_cache_cs ); -+ assert(thread_pool_cache.ref); -+ if (!--thread_pool_cache.ref) -+ { -+ CloseThreadpool( thread_pool_cache.pool ); -+ thread_pool_cache.pool = NULL; -+ } -+ LeaveCriticalSection( &thread_pool_cache_cs ); -+ } -+ else -+ { -+ CloseThreadpool( queue->pool ); -+ } - queue->pool = NULL; - TRACE("stopped %p\n", queue); - } -diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h -index 53c1f2e0122..93dffe8df32 100644 ---- a/dlls/winhttp/winhttp_private.h -+++ b/dlls/winhttp/winhttp_private.h -@@ -403,5 +403,6 @@ static inline char *strdupWA_sized( const WCHAR *src, DWORD size ) - } - - extern HINSTANCE winhttp_instance DECLSPEC_HIDDEN; -+extern BOOL reuse_threadpool DECLSPEC_HIDDEN; - - #endif /* _WINE_WINHTTP_PRIVATE_H_ */ -From 0262122fc328410e6b0b410837c35881b3aa85af Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 19 Apr 2021 15:29:39 +0300 -Subject: [PATCH] winevulkan: Don't hardcode performance frequency. - -For Forza Horizon 4. ---- - dlls/winevulkan/loader.c | 33 +++++++++++++++++++++++++++++++++ - dlls/winevulkan/make_vulkan | 2 +- - 2 files changed, 34 insertions(+), 1 deletion(-) - -diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c -index d3ac9f57763..fcb79983114 100644 ---- a/dlls/winevulkan/loader.c -+++ b/dlls/winevulkan/loader.c -@@ -442,6 +442,39 @@ void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev, - } - } - -+VkResult WINAPI vkGetCalibratedTimestampsEXT(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT *pTimestampInfos, uint64_t *pTimestamps, uint64_t *pMaxDeviation) -+{ -+ struct vkGetCalibratedTimestampsEXT_params params; -+ static LARGE_INTEGER freq; -+ VkResult res; -+ uint32_t i; -+ -+ if (!freq.QuadPart) -+ { -+ LARGE_INTEGER temp; -+ -+ QueryPerformanceFrequency(&temp); -+ InterlockedCompareExchange64(&freq.QuadPart, temp.QuadPart, 0); -+ } -+ -+ params.device = device; -+ params.timestampCount = timestampCount; -+ params.pTimestampInfos = pTimestampInfos; -+ params.pTimestamps = pTimestamps; -+ params.pMaxDeviation = pMaxDeviation; -+ res = vk_unix_call(unix_vkGetCalibratedTimestampsEXT, ¶ms); -+ if (res != VK_SUCCESS) -+ return res; -+ -+ for (i = 0; i < timestampCount; i++) -+ { -+ if (pTimestampInfos[i].timeDomain != VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT) continue; -+ pTimestamps[i] *= freq.QuadPart / 10000000; -+ } -+ -+ return VK_SUCCESS; -+} -+ - static BOOL WINAPI call_vulkan_debug_report_callback( struct wine_vk_debug_report_params *params, ULONG size ) - { - return params->user_callback(params->flags, params->object_type, params->object_handle, params->location, -diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan -index 516c817715f..a0287c1ff09 100755 ---- a/dlls/winevulkan/make_vulkan -+++ b/dlls/winevulkan/make_vulkan -@@ -254,7 +254,7 @@ FUNCTION_OVERRIDES = { - - # VK_EXT_calibrated_timestamps - "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, -- "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE}, -+ "vkGetCalibratedTimestampsEXT" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.NONE, "loader_thunk" : ThunkType.PRIVATE}, - - # VK_EXT_debug_utils - "vkCreateDebugUtilsMessengerEXT" : {"dispatch": True, "driver" : False, "thunk" : ThunkType.NONE}, -From 045a694d11b3acca3ef566f8ccba41b8376a9ce7 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 29 Oct 2019 09:16:37 -0500 -Subject: [PATCH] setupapi: Support DICGF_PRESENT when looking for devices - ---- - dlls/setupapi/devinst.c | 83 ++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 81 insertions(+), 2 deletions(-) - -diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c -index ecc0b58ca5c..aea0e605f1d 100644 ---- a/dlls/setupapi/devinst.c -+++ b/dlls/setupapi/devinst.c -@@ -103,6 +103,7 @@ static const WCHAR Linked[] = {'L','i','n','k','e','d',0}; - static const WCHAR dotInterfaces[] = {'.','I','n','t','e','r','f','a','c','e','s',0}; - static const WCHAR AddInterface[] = {'A','d','d','I','n','t','e','r','f','a','c','e',0}; - static const WCHAR backslashW[] = {'\\',0}; -+static const WCHAR hashW[] = {'#',0}; - static const WCHAR emptyW[] = {0}; - - #define SERVICE_CONTROL_REENUMERATE_ROOT_DEVICES 128 -@@ -318,7 +319,6 @@ static WCHAR *get_iface_key_path(struct device_iface *iface) - - static WCHAR *get_refstr_key_path(struct device_iface *iface) - { -- static const WCHAR hashW[] = {'#',0}; - static const WCHAR slashW[] = {'\\',0}; - WCHAR *path, *ptr; - size_t len = lstrlenW(DeviceClasses) + 1 + 38 + 1 + lstrlenW(iface->symlink) + 1 + 1; -@@ -2423,6 +2423,80 @@ static void SETUPDI_EnumerateInterfaces(HDEVINFO DeviceInfoSet, - } - } - -+ -+/* iterate over all interfaces supported by this device instance. if any of -+ * them are "linked", return TRUE */ -+static BOOL is_device_instance_linked(HKEY interfacesKey, const WCHAR *deviceInstance) -+{ -+ LONG l; -+ DWORD class_idx = 0, device_idx, len, type; -+ HKEY class_key, device_key, link_key; -+ WCHAR class_keyname[40], device_keyname[MAX_DEVICE_ID_LEN]; -+ WCHAR interface_devinstance[MAX_DEVICE_ID_LEN]; -+ -+ while (1) -+ { -+ len = ARRAY_SIZE(class_keyname); -+ l = RegEnumKeyExW(interfacesKey, class_idx++, class_keyname, &len, NULL, NULL, NULL, NULL); -+ if (l) -+ break; -+ -+ l = RegOpenKeyExW(interfacesKey, class_keyname, 0, KEY_READ, &class_key); -+ if (l) -+ continue; -+ -+ device_idx = 0; -+ while (1) -+ { -+ len = ARRAY_SIZE(device_keyname); -+ l = RegEnumKeyExW(class_key, device_idx++, device_keyname, &len, NULL, NULL, NULL, NULL); -+ if (l) -+ break; -+ -+ l = RegOpenKeyExW(class_key, device_keyname, 0, KEY_READ, &device_key); -+ if (l) -+ continue; -+ -+ len = ARRAY_SIZE(interface_devinstance); -+ l = RegQueryValueExW(device_key, DeviceInstance, NULL, &type, (BYTE *)interface_devinstance, &len); -+ if (l || type != REG_SZ) -+ { -+ RegCloseKey(device_key); -+ continue; -+ } -+ -+ if (lstrcmpiW(interface_devinstance, deviceInstance)) -+ { -+ /* not our device instance */ -+ RegCloseKey(device_key); -+ continue; -+ } -+ -+ l = RegOpenKeyExW(device_key, hashW, 0, KEY_READ, &link_key); -+ if (l) -+ { -+ RegCloseKey(device_key); -+ continue; -+ } -+ -+ if (is_linked(link_key)) -+ { -+ RegCloseKey(link_key); -+ RegCloseKey(device_key); -+ RegCloseKey(class_key); -+ return TRUE; -+ } -+ -+ RegCloseKey(link_key); -+ RegCloseKey(device_key); -+ } -+ -+ RegCloseKey(class_key); -+ } -+ -+ return FALSE; -+} -+ - static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, - LPCWSTR enumerator, LPCWSTR deviceName, HKEY deviceKey, - const GUID *class, DWORD flags) -@@ -2431,6 +2505,7 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, - DWORD i, len; - WCHAR deviceInstance[MAX_PATH]; - LONG l = ERROR_SUCCESS; -+ HKEY interfacesKey = SetupDiOpenClassRegKeyExW(NULL, KEY_READ, DIOCR_INTERFACE, NULL, NULL); - - TRACE("%s %s\n", debugstr_w(enumerator), debugstr_w(deviceName)); - -@@ -2467,7 +2542,9 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, - {'%','s','\\','%','s','\\','%','s',0}; - - if (swprintf(id, ARRAY_SIZE(id), fmt, enumerator, -- deviceName, deviceInstance) != -1) -+ deviceName, deviceInstance) != -1 && -+ (!(flags & DIGCF_PRESENT) || -+ is_device_instance_linked(interfacesKey, id))) - { - create_device(set, &deviceClass, id, FALSE); - } -@@ -2480,6 +2557,8 @@ static void SETUPDI_EnumerateMatchingDeviceInstances(struct DeviceInfoSet *set, - l = ERROR_SUCCESS; - } - } -+ -+ RegCloseKey(interfacesKey); - } - - static void SETUPDI_EnumerateMatchingDevices(HDEVINFO DeviceInfoSet, -From 16b32c4ff36fa8d8801fe0e1afb26be70ecc9b1c Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Mon, 18 Jun 2018 07:56:35 -0500 -Subject: [PATCH] ntdll: Notice THREADNAME_INFO exceptions and set thread name - on Linux - -Patch by Zeb. ---- - dlls/ntdll/unix/thread.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index 86811594d81..039bfeb0a86 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -57,6 +57,9 @@ - #ifdef HAVE_LIBPROCSTAT_H - #include - #endif -+#ifdef HAVE_PRCTL -+#include -+#endif - - #define NONAMELESSUNION - #define NONAMELESSSTRUCT -@@ -1440,6 +1443,16 @@ void wait_suspend( CONTEXT *context ) - } - - -+/* "How to: Set a Thread Name in Native Code" -+ * https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ -+typedef struct tagTHREADNAME_INFO -+{ -+ DWORD dwType; /* Must be 0x1000 */ -+ LPCSTR szName; /* Pointer to name - limited to 9 bytes (8 characters + terminator) */ -+ DWORD dwThreadID; /* Thread ID (-1 = caller thread) */ -+ DWORD dwFlags; /* Reserved for future use. Must be zero. */ -+} THREADNAME_INFO; -+ - /********************************************************************** - * send_debug_event - * -@@ -1461,6 +1474,21 @@ NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_c - for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++) - params[i] = rec->ExceptionInformation[i]; - -+ if (rec->ExceptionCode == 0x406d1388) -+ { -+ const THREADNAME_INFO *threadname = (const THREADNAME_INFO *)rec->ExceptionInformation; -+ -+ if (threadname->dwThreadID == -1) -+ { -+#ifdef HAVE_PRCTL -+#ifndef PR_SET_NAME -+# define PR_SET_NAME 15 -+#endif -+ prctl( PR_SET_NAME, threadname->szName ); -+#endif -+ } -+ } -+ - SERVER_START_REQ( queue_exception_event ) - { - req->first = first_chance; -From 0e5c03061868da894886f5dc940e1c24a9209fba Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 2 Nov 2020 13:21:49 +0100 -Subject: [PATCH] wine/server: Add traces for client requests. - ---- - include/wine/server.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/wine/server.h b/include/wine/server.h -index 57bcdbbb00d..5b533b48714 100644 ---- a/include/wine/server.h -+++ b/include/wine/server.h -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - - /* client communication functions */ - -@@ -123,6 +124,8 @@ static inline void *wine_server_get_ptr( client_ptr_t ptr ) - - #define SERVER_START_REQ(type) \ - do { \ -+ WINE_DECLARE_DEBUG_CHANNEL(client); \ -+ static const char *const __req_name = #type; \ - struct __server_request_info __req; \ - struct type##_request * const req = &__req.u.req.type##_request; \ - const struct type##_reply * const reply = &__req.u.reply.type##_reply; \ -@@ -130,10 +133,12 @@ static inline void *wine_server_get_ptr( client_ptr_t ptr ) - __req.u.req.request_header.req = REQ_##type; \ - __req.data_count = 0; \ - (void)reply; \ -+ TRACE_(client)("%s start\n", __req_name); \ - do - - #define SERVER_END_REQ \ - while(0); \ -+ TRACE_(client)("%s end\n", __req_name); \ - } while(0) - - -From c9dd827b315ba9394020ec65c161096ce3e968e8 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 2 Nov 2020 13:32:07 +0100 -Subject: [PATCH] ntdll: Add +microsecs channel for precise timestamps. - ---- - dlls/ntdll/thread.c | 10 +++++++++- - dlls/ntdll/unix/debug.c | 10 +++++++++- - dlls/winecrt0/debug.c | 12 +++++++++++- - 3 files changed, 29 insertions(+), 3 deletions(-) - -diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c -index fc9055ca09f..5fc956b1dc4 100644 ---- a/dlls/ntdll/thread.c -+++ b/dlls/ntdll/thread.c -@@ -36,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(thread); - WINE_DECLARE_DEBUG_CHANNEL(relay); - WINE_DECLARE_DEBUG_CHANNEL(pid); - WINE_DECLARE_DEBUG_CHANNEL(timestamp); -+WINE_DECLARE_DEBUG_CHANNEL(microsecs); - - struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; - -@@ -143,7 +144,14 @@ int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_ - /* only print header if we are at the beginning of the line */ - if (info->out_pos) return 0; - -- if (TRACE_ON(timestamp)) -+ if (TRACE_ON(microsecs)) -+ { -+ LARGE_INTEGER counter, frequency, microsecs; -+ NtQueryPerformanceCounter(&counter, &frequency); -+ microsecs.QuadPart = counter.QuadPart * 1000000 / frequency.QuadPart; -+ pos += sprintf( pos, "%3u.%06u:", (unsigned int)(microsecs.QuadPart / 1000000), (unsigned int)(microsecs.QuadPart % 1000000) ); -+ } -+ else if (TRACE_ON(timestamp)) - { - ULONG ticks = NtGetTickCount(); - pos += sprintf( pos, "%3u.%03u:", ticks / 1000, ticks % 1000 ); -diff --git a/dlls/ntdll/unix/debug.c b/dlls/ntdll/unix/debug.c -index 250c2d19c8e..66bdb3ca2e3 100644 ---- a/dlls/ntdll/unix/debug.c -+++ b/dlls/ntdll/unix/debug.c -@@ -44,6 +44,7 @@ - - WINE_DECLARE_DEBUG_CHANNEL(pid); - WINE_DECLARE_DEBUG_CHANNEL(timestamp); -+WINE_DECLARE_DEBUG_CHANNEL(microsecs); - WINE_DEFAULT_DEBUG_CHANNEL(ntdll); - - struct debug_info -@@ -297,7 +298,14 @@ int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_ - - if (init_done) - { -- if (TRACE_ON(timestamp)) -+ if (TRACE_ON(microsecs)) -+ { -+ LARGE_INTEGER counter, frequency, microsecs; -+ NtQueryPerformanceCounter(&counter, &frequency); -+ microsecs.QuadPart = counter.QuadPart * 1000000 / frequency.QuadPart; -+ pos += sprintf( pos, "%3u.%06u:", (unsigned int)(microsecs.QuadPart / 1000000), (unsigned int)(microsecs.QuadPart % 1000000) ); -+ } -+ else if (TRACE_ON(timestamp)) - { - ULONG ticks = NtGetTickCount(); - pos += sprintf( pos, "%3u.%03u:", ticks / 1000, ticks % 1000 ); -diff --git a/dlls/winecrt0/debug.c b/dlls/winecrt0/debug.c -index 14f3d2d3773..0ac5caa4b9c 100644 ---- a/dlls/winecrt0/debug.c -+++ b/dlls/winecrt0/debug.c -@@ -30,6 +30,7 @@ - - WINE_DECLARE_DEBUG_CHANNEL(pid); - WINE_DECLARE_DEBUG_CHANNEL(timestamp); -+WINE_DECLARE_DEBUG_CHANNEL(microsecs); - - static const char * (__cdecl *p__wine_dbg_strdup)( const char *str ); - static int (__cdecl *p__wine_dbg_output)( const char *str ); -@@ -189,7 +190,16 @@ static int __cdecl fallback__wine_dbg_header( enum __wine_debug_class cls, - /* skip header if partial line and no other thread came in between */ - if (partial_line_tid == GetCurrentThreadId()) return 0; - -- if (TRACE_ON(timestamp)) -+ if (TRACE_ON(microsecs)) -+ { -+ static LARGE_INTEGER frequency; -+ LARGE_INTEGER counter, microsecs; -+ if (!frequency.QuadPart) QueryPerformanceFrequency(&frequency); -+ QueryPerformanceCounter(&counter); -+ microsecs.QuadPart = counter.QuadPart * 1000000 / frequency.QuadPart; -+ pos += sprintf( pos, "%3u.%06u:", (unsigned int)(microsecs.QuadPart / 1000000), (unsigned int)(microsecs.QuadPart % 1000000) ); -+ } -+ else if (TRACE_ON(timestamp)) - { - ULONG ticks = GetTickCount(); - pos += sprintf( pos, "%3u.%03u:", ticks / 1000, ticks % 1000 ); -From eac035c702984574a3d8920acb102a0be71b72a4 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Fri, 11 Sep 2020 17:55:59 +1000 -Subject: [PATCH] include: Remove interfaces already define in msxml6.idl - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/msxml3/factory.c | 1 + - dlls/msxml3/tests/saxreader.c | 1 + - dlls/msxml3/tests/schema.c | 5 ++ - dlls/msxml3/uuid.c | 11 ++++ - include/msxml2.idl | 109 ---------------------------------- - include/msxml6.idl | 24 ++++---- - 6 files changed, 30 insertions(+), 121 deletions(-) - -diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c -index b8c8281063a..34aa3bc4e23 100644 ---- a/dlls/msxml3/factory.c -+++ b/dlls/msxml3/factory.c -@@ -31,6 +31,7 @@ - #include "ole2.h" - #include "msxml.h" - #include "msxml2.h" -+#include "msxml6.h" - #include "xmlparser.h" - - /* undef the #define in msxml2 so that we can access the v.2 version -diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c -index 20c5e07443b..d998a0805d7 100644 ---- a/dlls/msxml3/tests/saxreader.c -+++ b/dlls/msxml3/tests/saxreader.c -@@ -29,6 +29,7 @@ - #include "windows.h" - #include "ole2.h" - #include "msxml2.h" -+#include "msxml6.h" - #include "msxml2did.h" - #include "ocidl.h" - #include "dispex.h" -diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c -index 4cdfedf9c29..219d7144ddb 100644 ---- a/dlls/msxml3/tests/schema.c -+++ b/dlls/msxml3/tests/schema.c -@@ -32,6 +32,11 @@ - #include "dispex.h" - #include "cguid.h" - -+DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+ - #include "wine/test.h" - - #define EXPECT_HR(hr,hr_exp) \ -diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c -index 4abbe5e4763..333d4f3d3c7 100644 ---- a/dlls/msxml3/uuid.c -+++ b/dlls/msxml3/uuid.c -@@ -41,6 +41,17 @@ - #include "initguid.h" - #include "msxml2.h" - -+/* Cannot include msxml6 here since we will get a duplicate LIBID_MSXML2 error. */ -+DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_MXNamespaceManager60, 0x88d96a11, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_ServerXMLHTTP60, 0x88d96a0b, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_XMLHTTP60, 0x88d96a0a, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_XSLTemplate60, 0x88d96a08, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+ - /* - * Note that because of a #define in msxml2.h, we end up initializing - * CLSID_DOMDocument2 to be the v.3 version independent DOMDocument -diff --git a/include/msxml2.idl b/include/msxml2.idl -index 916e0e8ab3d..1d1ba7a5248 100644 ---- a/include/msxml2.idl -+++ b/include/msxml2.idl -@@ -1612,15 +1612,6 @@ coclass FreeThreadedDOMDocument40 - [default, source] dispinterface XMLDOMDocumentEvents; - } - --[ -- uuid(88d96a06-f192-11d4-a65f-0040963251e5), --] --coclass FreeThreadedDOMDocument60 --{ -- [default] interface IXMLDOMDocument3; -- [default, source] dispinterface XMLDOMDocumentEvents; --} -- - [ - helpstring("Free threaded XML DOM Document"), - progid("Msxml2.FreeThreadedDOMDocument"), -@@ -1662,14 +1653,6 @@ coclass XMLHTTP40 - [default] interface IXMLHTTPRequest; - } - --[ -- uuid(88d96a0a-f192-11d4-a65f-0040963251e5) --] --coclass XMLHTTP60 --{ -- [default] interface IXMLHTTPRequest; --} -- - [ - helpstring("XML HTTP"), - progid("Msxml2.XMLHTTP"), -@@ -1702,14 +1685,6 @@ coclass ServerXMLHTTP40 - [default] interface IServerXMLHTTPRequest2; - } - --[ -- uuid(88d96a0b-f192-11d4-a65f-0040963251e5) --] --coclass ServerXMLHTTP60 --{ -- [default] interface IServerXMLHTTPRequest2; --} -- - [ - helpstring("Server XML HTTP"), - progid("Msxml2.ServerXMLHTTP"), -@@ -1750,14 +1725,6 @@ coclass XMLSchemaCache40 - [default] interface IXMLDOMSchemaCollection2; - } - --[ -- uuid(88d96a07-f192-11d4-a65f-0040963251e5) --] --coclass XMLSchemaCache60 --{ -- [default] interface IXMLDOMSchemaCollection2; --} -- - [ - helpstring("XML Schema Cache"), - progid("Msxml2.XMLSchemaCache"), -@@ -1798,14 +1765,6 @@ coclass XSLTemplate40 - [default] interface IXSLTemplate; - } - --[ -- uuid(88d96a08-f192-11d4-a65f-0040963251e5) --] --coclass XSLTemplate60 --{ -- [default] interface IXSLTemplate; --} -- - [ - helpstring("XSL Template"), - progid("Msxml2.XSLTemplate"), -@@ -3297,15 +3256,6 @@ coclass SAXXMLReader40 - interface ISAXXMLReader; - } - --[ -- uuid(88d96a0c-f192-11d4-a65f-0040963251e5) --] --coclass SAXXMLReader60 --{ -- [default] interface IVBSAXXMLReader; -- interface ISAXXMLReader; --} -- - [ - helpstring("SAX XML Reader"), - progid("Msxml2.SAXXMLReader"), -@@ -3380,26 +3330,6 @@ coclass MXHTMLWriter40 - interface IVBSAXLexicalHandler; - } - --[ -- uuid(88d96a10-f192-11d4-a65f-0040963251e5) --] --coclass MXHTMLWriter60 --{ -- [default] interface IMXWriter; -- -- interface ISAXContentHandler; -- interface ISAXDeclHandler; -- interface ISAXDTDHandler; -- interface ISAXErrorHandler; -- interface ISAXLexicalHandler; -- -- interface IVBSAXContentHandler; -- interface IVBSAXDeclHandler; -- interface IVBSAXDTDHandler; -- interface IVBSAXErrorHandler; -- interface IVBSAXLexicalHandler; --} -- - [ - helpstring("MXXMLWriter 3.0"), - progid("Msxml2.MXXMLWriter.3.0"), -@@ -3444,26 +3374,6 @@ coclass MXXMLWriter40 - interface IVBSAXLexicalHandler; - } - --[ -- uuid(88d96a0f-f192-11d4-a65f-0040963251e5) --] --coclass MXXMLWriter60 --{ -- [default] interface IMXWriter; -- -- interface ISAXContentHandler; -- interface ISAXDeclHandler; -- interface ISAXDTDHandler; -- interface ISAXErrorHandler; -- interface ISAXLexicalHandler; -- -- interface IVBSAXContentHandler; -- interface IVBSAXDeclHandler; -- interface IVBSAXDTDHandler; -- interface IVBSAXErrorHandler; -- interface IVBSAXLexicalHandler; --} -- - [ - helpstring("MXXMLWriter"), - progid("Msxml2.MXXMLWriter"), -@@ -3506,15 +3416,6 @@ coclass MXNamespaceManager40 - interface IMXNamespaceManager; - } - --[ -- uuid(88d96a11-f192-11d4-a65f-0040963251e5) --] --coclass MXNamespaceManager60 --{ -- [default] interface IVBMXNamespaceManager; -- interface IMXNamespaceManager; --} -- - [ - helpstring("SAXAttributes 3.0"), - progid("Msxml2.SAXAttributes.3.0"), -@@ -3539,16 +3440,6 @@ coclass SAXAttributes40 - interface ISAXAttributes; - } - --[ -- uuid(88d96a0e-f192-11d4-a65f-0040963251e5) --] --coclass SAXAttributes60 --{ -- [default] interface IMXAttributes; -- interface IVBSAXAttributes; -- interface ISAXAttributes; --} -- - [ - helpstring("SAXAttributes"), - progid("Msxml2.SAXAttributes"), -diff --git a/include/msxml6.idl b/include/msxml6.idl -index 4948de39f1f..e6a0a5feda5 100644 ---- a/include/msxml6.idl -+++ b/include/msxml6.idl -@@ -3048,18 +3048,6 @@ coclass DOMDocument60 - [default, source] dispinterface XMLDOMDocumentEvents; - } - --[ -- helpstring("Free threaded XML DOM Document 6.0"), -- progid("Msxml2.FreeThreadedDOMDocument.6.0"), -- threading(both), -- uuid(88d96a06-f192-11d4-a65f-0040963251e5), --] --coclass FreeThreadedDOMDocument60 --{ -- [default] interface IXMLDOMDocument3; -- [default, source] dispinterface XMLDOMDocumentEvents; --} -- - [ - helpstring("SAX XML Reader 6.0"), - progid("Msxml2.SAXXMLReader.6.0"), -@@ -3165,6 +3153,18 @@ coclass XSLTemplate60 - [default] interface IXSLTemplate; - } - -+[ -+ helpstring("Free threaded XML DOM Document 6.0"), -+ progid("Msxml2.FreeThreadedDOMDocument.6.0"), -+ threading(both), -+ uuid(88d96a06-f192-11d4-a65f-0040963251e5), -+] -+coclass FreeThreadedDOMDocument60 -+{ -+ [default] interface IXMLDOMDocument3; -+ [default, source] dispinterface XMLDOMDocumentEvents; -+} -+ - [ - helpstring("XML HTTP 6.0"), - progid("Msxml2.XMLHTTP.6.0"), -From 847b319c121eb100b163bc314e905a3570656739 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 8 Sep 2020 18:43:52 +0200 -Subject: [PATCH] msxml3: Implement FreeThreadedXMLHTTP60. - -Update from Gijs Vermeulen ---- - dlls/msxml3/Makefile.in | 2 +- - dlls/msxml3/factory.c | 5 + - dlls/msxml3/httprequest.c | 496 +++++++++++++++++++++++++++++++++++- - dlls/msxml3/msxml_private.h | 1 + - dlls/msxml3/tests/httpreq.c | 395 +++++++++++++++++++++++++++- - dlls/msxml3/tests/schema.c | 6 + - dlls/msxml3/uuid.c | 5 + - 7 files changed, 905 insertions(+), 5 deletions(-) - -diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in -index 2bf789732da..e2d737599b1 100644 ---- a/dlls/msxml3/Makefile.in -+++ b/dlls/msxml3/Makefile.in -@@ -1,5 +1,5 @@ - MODULE = msxml3.dll --IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 -+IMPORTS = $(XSLT_PE_LIBS) $(XML2_PE_LIBS) uuid urlmon shlwapi oleaut32 ole32 user32 advapi32 rtworkq - EXTRAINCL = $(XSLT_PE_CFLAGS) $(XML2_PE_CFLAGS) - - C_SRCS = \ -diff --git a/dlls/msxml3/factory.c b/dlls/msxml3/factory.c -index 34aa3bc4e23..651a6b8e9df 100644 ---- a/dlls/msxml3/factory.c -+++ b/dlls/msxml3/factory.c -@@ -277,6 +277,7 @@ static HRESULT DOMClassFactory_Create(const GUID *clsid, REFIID riid, void **ppv - - static ClassFactory xmldoccf = { { &ClassFactoryVtbl }, XMLDocument_create }; - static ClassFactory httpreqcf = { { &ClassFactoryVtbl }, XMLHTTPRequest_create }; -+static ClassFactory httpreqcf2 = { { &ClassFactoryVtbl }, XMLHTTPRequest2_create }; - static ClassFactory serverhttp = { { &ClassFactoryVtbl }, ServerXMLHTTP_create }; - static ClassFactory xsltemplatecf = { { &ClassFactoryVtbl }, XSLTemplate_create }; - static ClassFactory mxnsmanagercf = { {&ClassFactoryVtbl }, MXNamespaceManager_create }; -@@ -338,6 +339,10 @@ HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void **ppv ) - { - cf = &httpreqcf.IClassFactory_iface; - } -+ else if( IsEqualCLSID( rclsid, &CLSID_FreeThreadedXMLHTTP60 )) -+ { -+ cf = &httpreqcf2.IClassFactory_iface; -+ } - else if( IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP ) || - IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP30 ) || - IsEqualCLSID( rclsid, &CLSID_ServerXMLHTTP40 ) || -diff --git a/dlls/msxml3/httprequest.c b/dlls/msxml3/httprequest.c -index 934d580064f..65232bbc8af 100644 ---- a/dlls/msxml3/httprequest.c -+++ b/dlls/msxml3/httprequest.c -@@ -38,10 +38,12 @@ - #include "shlwapi.h" - - #include "msxml_dispex.h" -+#include "initguid.h" -+#include "rtworkq.h" - - #include "wine/debug.h" - --WINE_DEFAULT_DEBUG_CHANNEL(msxml); -+WINE_DEFAULT_DEBUG_CHANNEL(xmlhttp); - - static const WCHAR colspaceW[] = {':',' ',0}; - static const WCHAR crlfW[] = {'\r','\n',0}; -@@ -2074,6 +2076,468 @@ static const struct IServerXMLHTTPRequestVtbl ServerXMLHTTPRequestVtbl = - ServerXMLHTTPRequest_setOption - }; - -+static DWORD xhr2_work_queue; -+ -+struct xml_http_request_2 -+{ -+ httprequest req; -+ IXMLHTTPRequest3 IXMLHTTPRequest3_iface; -+ IRtwqAsyncCallback IRtwqAsyncCallback_iface; -+ IDispatch IDispatch_iface; -+ -+ IXMLHTTPRequest2Callback *callback; -+ IXMLHTTPRequest3Callback *callback3; -+ ISequentialStream *response_body; -+ ISequentialStream *request_body; -+ ULONGLONG request_body_size; -+}; -+ -+static inline struct xml_http_request_2 *impl_from_IXMLHTTPRequest3(IXMLHTTPRequest3 *iface) -+{ -+ return CONTAINING_RECORD(iface, struct xml_http_request_2, IXMLHTTPRequest3_iface); -+} -+ -+static inline struct xml_http_request_2 *xml_http_request_2_from_IRtwqAsyncCallback(IRtwqAsyncCallback *iface) -+{ -+ return CONTAINING_RECORD(iface, struct xml_http_request_2, IRtwqAsyncCallback_iface); -+} -+ -+static inline struct xml_http_request_2 *xml_http_request_2_from_IDispatch(IDispatch *iface) -+{ -+ return CONTAINING_RECORD(iface, struct xml_http_request_2, IDispatch_iface); -+} -+ -+static HRESULT WINAPI xml_http_request_2_QueryInterface(IXMLHTTPRequest3 *iface, REFIID riid, void **obj) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ -+ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); -+ -+ if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2) -+ || IsEqualGUID(riid, &IID_IUnknown)) -+ { -+ *obj = iface; -+ IUnknown_AddRef((IUnknown*)*obj); -+ return S_OK; -+ } -+ -+ FIXME("Unsupported interface %s\n", debugstr_guid(riid)); -+ *obj = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI xml_http_request_2_AddRef(IXMLHTTPRequest3 *iface) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ ULONG ref = InterlockedIncrement(&This->req.ref); -+ TRACE("(%p)->(%u)\n", This, ref); -+ return ref; -+} -+ -+static ULONG WINAPI xml_http_request_2_Release(IXMLHTTPRequest3 *iface) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ ULONG ref = InterlockedDecrement(&This->req.ref); -+ -+ TRACE("(%p)->(%u)\n", This, ref); -+ -+ if (ref == 0) -+ { -+ /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ -+ This->req.sink = NULL; -+ if (This->response_body) ISequentialStream_Release(This->response_body); -+ if (This->request_body) ISequentialStream_Release(This->request_body); -+ if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); -+ if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); -+ heap_free(This); -+ RtwqShutdown(); -+ } -+ -+ return ref; -+} -+ -+static HRESULT WINAPI xml_http_request_2_Open(IXMLHTTPRequest3 *iface, const WCHAR *method, -+ const WCHAR *url, IXMLHTTPRequest2Callback *callback, -+ const WCHAR *username, const WCHAR *password, -+ const WCHAR *proxy_username, const WCHAR *proxy_password) -+{ -+ static const WCHAR accept_encoding[] = {'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0}; -+ static const WCHAR empty = 0; -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ VARIANT async_v, username_v, password_v; -+ HRESULT hr; -+ -+ TRACE("(%p)->(%s %s %p %s %s %s %s)\n", This, debugstr_w(method), debugstr_w(url), callback, -+ debugstr_w(username), debugstr_w(password), debugstr_w(proxy_username), debugstr_w(proxy_password)); -+ -+ if (This->callback) IXMLHTTPRequest2Callback_Release(This->callback); -+ if (This->callback3) IXMLHTTPRequest3Callback_Release(This->callback3); -+ IXMLHTTPRequest2Callback_AddRef(callback); -+ This->callback = callback; -+ if (FAILED(IXMLHTTPRequest2Callback_QueryInterface(callback, &IID_IXMLHTTPRequest3Callback, (void **)&This->callback3))) -+ This->callback3 = NULL; -+ -+ if (proxy_username || proxy_password) FIXME("proxy credentials not implemented\n"); -+ -+ VariantInit(&async_v); -+ V_VT(&async_v) = VT_BOOL; -+ V_BOOL(&async_v) = FALSE; /* FIXME: TRUE needs a RTWQ_WINDOW_WORKQUEUE */ -+ -+ VariantInit(&username_v); -+ V_VT(&username_v) = VT_BSTR; -+ if (username) V_BSTR(&username_v) = SysAllocString(username); -+ else V_BSTR(&username_v) = SysAllocString(&empty); -+ -+ VariantInit(&password_v); -+ V_VT(&password_v) = VT_BSTR; -+ if (password) V_BSTR(&password_v) = SysAllocString(password); -+ else V_BSTR(&password_v) = SysAllocString(&empty); -+ -+ if (FAILED(hr = httprequest_open(&This->req, (BSTR)method, (BSTR)url, async_v, username_v, password_v))) -+ return hr; -+ return httprequest_setRequestHeader(&This->req, (BSTR)accept_encoding, (BSTR)&empty); -+} -+ -+static HRESULT WINAPI xml_http_request_2_Send(IXMLHTTPRequest3 *iface, ISequentialStream *body, ULONGLONG body_size) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ IRtwqAsyncResult *result; -+ HRESULT hr; -+ -+ TRACE("(%p)->(%p %s)\n", This, body, wine_dbgstr_longlong( body_size )); -+ -+ if (body_size) -+ { -+ ISequentialStream_AddRef(body); -+ This->request_body = body; -+ This->request_body_size = body_size; -+ } -+ -+ if (FAILED(hr = RtwqCreateAsyncResult(NULL, &This->IRtwqAsyncCallback_iface, NULL, &result))) -+ return hr; -+ // IRtwqAsyncCallback_Invoke(&This->IRtwqAsyncCallback_iface, result); -+ hr = RtwqPutWorkItem(xhr2_work_queue, 0, result); -+ if (result) IRtwqAsyncResult_Release(result); -+ -+ return hr; -+} -+ -+static HRESULT WINAPI xml_http_request_2_Abort(IXMLHTTPRequest3 *iface) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ TRACE("(%p) stub!\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI xml_http_request_2_SetCookie(IXMLHTTPRequest3 *iface, const XHR_COOKIE *cookie, DWORD *state) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ FIXME("(%p)->(%p %p) stub!\n", This, cookie, state); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI xml_http_request_2_SetCustomResponseStream(IXMLHTTPRequest3 *iface, ISequentialStream *stream) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ FIXME("(%p)->(%p) stub!\n", This, stream); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI xml_http_request_2_SetProperty(IXMLHTTPRequest3 *iface, XHR_PROPERTY property, ULONGLONG value) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ FIXME("(%p)->(%#x %s) stub!\n", This, property, wine_dbgstr_longlong( value )); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI xml_http_request_2_SetRequestHeader(IXMLHTTPRequest3 *iface, -+ const WCHAR *header, const WCHAR *value) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ TRACE("(%p)->(%s %s)\n", This, debugstr_w(header), debugstr_w(value)); -+ return httprequest_setRequestHeader(&This->req, (BSTR)header, (BSTR)value); -+} -+ -+static HRESULT WINAPI xml_http_request_2_GetAllResponseHeaders(IXMLHTTPRequest3 *iface, WCHAR **headers) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ FIXME("(%p)->(%p) stub!\n", This, headers); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI xml_http_request_2_GetCookie(IXMLHTTPRequest3 *iface, const WCHAR *url, -+ const WCHAR *name, DWORD flags, -+ ULONG *cookies_count, XHR_COOKIE **cookies) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ FIXME("(%p)->(%s %s %d %p %p) stub!\n", This, debugstr_w(url), debugstr_w(name), flags, cookies_count, cookies); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI xml_http_request_2_GetResponseHeader(IXMLHTTPRequest3 *iface, -+ const WCHAR *header, WCHAR **value) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ HRESULT hr; -+ -+ TRACE("(%p)->(%s %p)\n", This, debugstr_w(header), value); -+ -+ if (FAILED(hr = httprequest_getResponseHeader(&This->req, (BSTR)header, value))) -+ return hr; -+ -+#define E_FILE_NOT_FOUND _HRESULT_TYPEDEF_(0x80070002) -+ -+ if (hr == S_FALSE) -+ { -+ *value = NULL; -+ return E_FILE_NOT_FOUND; -+ } -+ -+ return hr; -+} -+ -+static HRESULT WINAPI xml_http_request_3_SetClientCertificate(IXMLHTTPRequest3 *iface, DWORD count, const BYTE *hashes, const WCHAR *pin) -+{ -+ struct xml_http_request_2 *This = impl_from_IXMLHTTPRequest3(iface); -+ FIXME("(%p)->(%d %p %s) stub!\n", This, count, hashes, debugstr_w(pin)); -+ return E_NOTIMPL; -+} -+ -+static const struct IXMLHTTPRequest3Vtbl XMLHTTPRequest3Vtbl = { -+ /* IUnknown methods */ -+ xml_http_request_2_QueryInterface, -+ xml_http_request_2_AddRef, -+ xml_http_request_2_Release, -+ /* IXMLHTTPRequest2 methods */ -+ xml_http_request_2_Open, -+ xml_http_request_2_Send, -+ xml_http_request_2_Abort, -+ xml_http_request_2_SetCookie, -+ xml_http_request_2_SetCustomResponseStream, -+ xml_http_request_2_SetProperty, -+ xml_http_request_2_SetRequestHeader, -+ xml_http_request_2_GetAllResponseHeaders, -+ xml_http_request_2_GetCookie, -+ xml_http_request_2_GetResponseHeader, -+ /* IXMLHTTPRequest3 methods */ -+ xml_http_request_3_SetClientCertificate, -+}; -+ -+static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_QueryInterface(IRtwqAsyncCallback *iface, REFIID riid, void **obj) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); -+ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); -+ -+ if (IsEqualGUID(riid, &IID_IRtwqAsyncCallback) || IsEqualGUID(riid, &IID_IUnknown)) -+ { -+ IRtwqAsyncCallback_AddRef(iface); -+ *obj = iface; -+ return S_OK; -+ } -+ -+ FIXME("Unsupported interface %s\n", debugstr_guid(riid)); -+ *obj = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_AddRef(IRtwqAsyncCallback *iface) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); -+ TRACE("(%p)\n", This); -+ return xml_http_request_2_AddRef(&This->IXMLHTTPRequest3_iface); -+} -+ -+static ULONG WINAPI xml_http_request_2_IRtwqAsyncCallback_Release(IRtwqAsyncCallback *iface) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); -+ TRACE("(%p)\n", This); -+ return xml_http_request_2_Release(&This->IXMLHTTPRequest3_iface); -+} -+ -+static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_GetParameters(IRtwqAsyncCallback *iface, -+ DWORD *flags, DWORD *queue) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); -+ -+ TRACE("(%p)->(%p %p)\n", This, flags, queue); -+ -+ *flags = 0; -+ *queue = xhr2_work_queue; -+ return S_OK; -+} -+ -+static HRESULT WINAPI xml_http_request_2_IRtwqAsyncCallback_Invoke(IRtwqAsyncCallback *iface, -+ IRtwqAsyncResult *result) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IRtwqAsyncCallback(iface); -+ VARIANT body_v; -+ HRESULT hr; -+ ULONG read; -+ -+ TRACE("(%p)->(%p)\n", This, result); -+ -+ VariantInit(&body_v); -+ -+ if (This->request_body) -+ { -+ V_VT(&body_v) = VT_BSTR; -+ V_BSTR(&body_v) = CoTaskMemAlloc(This->request_body_size); -+ -+ if (FAILED(hr = ISequentialStream_Read(This->request_body, V_BSTR(&body_v), This->request_body_size, &read)) || -+ read < This->request_body_size) -+ { -+ ERR("Failed to allocate request body memory, hr %#x\n", hr); -+ CoTaskMemFree(V_BSTR(&body_v)); -+ goto done; -+ } -+ -+ ISequentialStream_Release(This->request_body); -+ This->request_body = NULL; -+ } -+ -+ hr = httprequest_send(&This->req, body_v); -+ -+done: -+ return IRtwqAsyncResult_SetStatus(result, hr); -+} -+ -+static const struct IRtwqAsyncCallbackVtbl xml_http_request_2_IRtwqAsyncCallbackVtbl = { -+ /* IUnknown methods */ -+ xml_http_request_2_IRtwqAsyncCallback_QueryInterface, -+ xml_http_request_2_IRtwqAsyncCallback_AddRef, -+ xml_http_request_2_IRtwqAsyncCallback_Release, -+ /* IRtwqAsyncCallback methods */ -+ xml_http_request_2_IRtwqAsyncCallback_GetParameters, -+ xml_http_request_2_IRtwqAsyncCallback_Invoke, -+}; -+ -+static HRESULT WINAPI xml_http_request_2_IDispatch_QueryInterface(IDispatch *iface, REFIID riid, void **obj) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); -+ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); -+ -+ if (IsEqualGUID(riid, &IID_IDispatch) || IsEqualGUID(riid, &IID_IUnknown)) -+ { -+ IDispatch_AddRef(iface); -+ *obj = iface; -+ return S_OK; -+ } -+ -+ FIXME("Unsupported interface %s\n", debugstr_guid(riid)); -+ *obj = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI xml_http_request_2_IDispatch_AddRef(IDispatch *iface) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); -+ TRACE("(%p)\n", This); -+ return xml_http_request_2_AddRef(&This->IXMLHTTPRequest3_iface); -+} -+ -+static ULONG WINAPI xml_http_request_2_IDispatch_Release(IDispatch *iface) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); -+ TRACE("(%p)\n", This); -+ return xml_http_request_2_Release(&This->IXMLHTTPRequest3_iface); -+} -+ -+static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfoCount(IDispatch *iface, UINT *value) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); -+ FIXME("(%p)->(%p) stub!\n", This, value); -+ *value = 0; -+ return S_OK; -+} -+ -+static HRESULT WINAPI xml_http_request_2_IDispatch_GetTypeInfo(IDispatch *iface, UINT index, -+ LCID lcid, ITypeInfo **value) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); -+ FIXME("(%p)->(%d %u %p) stub!\n", This, index, lcid, value); -+ *value = NULL; -+ return S_OK; -+} -+ -+static HRESULT WINAPI xml_http_request_2_IDispatch_GetIDsOfNames(IDispatch *iface, REFIID riid, -+ OLECHAR **names, UINT names_count, -+ LCID lcid, DISPID *disp_ids) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); -+ FIXME("(%p)->(%s %p %d %u %p) stub!\n", This, debugstr_guid(riid), names, names_count, lcid, disp_ids); -+ return S_OK; -+} -+ -+static HRESULT WINAPI xml_http_request_2_IDispatch_Invoke(IDispatch *iface, DISPID id, REFIID riid, -+ LCID lcid, WORD flags, DISPPARAMS *params, -+ VARIANT *result, EXCEPINFO *exception, UINT *arg_err) -+{ -+ struct xml_http_request_2 *This = xml_http_request_2_from_IDispatch(iface); -+ IXMLHTTPRequest2 *xhr2_iface = (IXMLHTTPRequest2*)&This->IXMLHTTPRequest3_iface; -+ HRESULT hr; -+ LONG status; -+ BSTR status_str = NULL; -+ -+ TRACE("(%p)->(%d %s %u %d %p %p %p %p) stub!\n", This, id, debugstr_guid(riid), lcid, flags, -+ params, result, exception, arg_err); -+ -+ if (This->req.state == READYSTATE_COMPLETE) -+ { -+ VARIANT body_v; -+ VariantInit(&body_v); -+ -+ IXMLHTTPRequest2Callback_AddRef(This->callback); -+ if (This->callback3) -+ { -+ IXMLHTTPRequest3Callback_AddRef(This->callback3); -+ IXMLHTTPRequest3Callback_OnServerCertificateReceived(This->callback3, (IXMLHTTPRequest3 *)xhr2_iface, 0, 1, NULL); -+ IXMLHTTPRequest3Callback_Release(This->callback3); -+ } -+ -+ if (FAILED(hr = httprequest_get_status(&This->req, &status)) || -+ FAILED(hr = httprequest_get_statusText(&This->req, &status_str))) -+ { -+ WARN("failed to get response status, error %#x\n", hr); -+ IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); -+ IXMLHTTPRequest2Callback_Release(This->callback); -+ return S_OK; -+ } -+ -+ IXMLHTTPRequest2Callback_OnHeadersAvailable(This->callback, xhr2_iface, status, status_str); -+ SysFreeString(status_str); -+ -+ if (This->response_body) ISequentialStream_Release(This->response_body); -+ This->response_body = NULL; -+ -+ if (FAILED(hr = httprequest_get_responseStream(&This->req, &body_v)) || -+ FAILED(hr = IUnknown_QueryInterface(V_UNKNOWN(&body_v), &IID_ISequentialStream, (void **)&This->response_body))) -+ { -+ WARN("failed to get response stream, error %#x\n", hr); -+ IXMLHTTPRequest2Callback_OnError(This->callback, xhr2_iface, hr); -+ IXMLHTTPRequest2Callback_Release(This->callback); -+ return S_OK; -+ } -+ -+ IXMLHTTPRequest2Callback_OnDataAvailable(This->callback, xhr2_iface, This->response_body); -+ IXMLHTTPRequest2Callback_OnResponseReceived(This->callback, xhr2_iface, This->response_body); -+ IXMLHTTPRequest2Callback_Release(This->callback); -+ } -+ -+ return S_OK; -+} -+ -+static const struct IDispatchVtbl xml_http_request_2_IDispatchVtbl = { -+ /* IUnknown methods */ -+ xml_http_request_2_IDispatch_QueryInterface, -+ xml_http_request_2_IDispatch_AddRef, -+ xml_http_request_2_IDispatch_Release, -+ /* IDispatch methods */ -+ xml_http_request_2_IDispatch_GetTypeInfoCount, -+ xml_http_request_2_IDispatch_GetTypeInfo, -+ xml_http_request_2_IDispatch_GetIDsOfNames, -+ xml_http_request_2_IDispatch_Invoke, -+}; -+ - static void init_httprequest(httprequest *req) - { - req->IXMLHTTPRequest_iface.lpVtbl = &XMLHTTPRequestVtbl; -@@ -2123,6 +2587,35 @@ HRESULT XMLHTTPRequest_create(void **obj) - return S_OK; - } - -+HRESULT XMLHTTPRequest2_create(void **obj) -+{ -+ struct xml_http_request_2 *xhr2; -+ TRACE("(%p)\n", obj); -+ -+ if (!(xhr2 = heap_alloc(sizeof(*xhr2)))) return E_OUTOFMEMORY; -+ -+ init_httprequest(&xhr2->req); -+ xhr2->IXMLHTTPRequest3_iface.lpVtbl = &XMLHTTPRequest3Vtbl; -+ xhr2->IRtwqAsyncCallback_iface.lpVtbl = &xml_http_request_2_IRtwqAsyncCallbackVtbl; -+ xhr2->IDispatch_iface.lpVtbl = &xml_http_request_2_IDispatchVtbl; -+ -+ /* do not call httprequest_put_onreadystatechange to avoid ref cycle */ -+ xhr2->req.sink = &xhr2->IDispatch_iface; -+ -+ xhr2->callback = NULL; -+ xhr2->callback3 = NULL; -+ xhr2->request_body = NULL; -+ xhr2->response_body = NULL; -+ -+ /* for async http requests we need window message queue */ -+ RtwqStartup(); -+ if (!xhr2_work_queue) RtwqAllocateWorkQueue(RTWQ_MULTITHREADED_WORKQUEUE, &xhr2_work_queue); -+ -+ *obj = &xhr2->IXMLHTTPRequest3_iface; -+ TRACE("returning iface %p\n", *obj); -+ return S_OK; -+} -+ - HRESULT ServerXMLHTTP_create(void **obj) - { - serverhttp *req; -@@ -2142,3 +2635,4 @@ HRESULT ServerXMLHTTP_create(void **obj) - - return S_OK; - } -+ -diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h -index 8003c1a9650..59b8c29845d 100644 ---- a/dlls/msxml3/msxml_private.h -+++ b/dlls/msxml3/msxml_private.h -@@ -367,6 +367,7 @@ extern HRESULT XMLDocument_create(void**) DECLSPEC_HIDDEN; - extern HRESULT SAXXMLReader_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; - extern HRESULT SAXAttributes_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; - extern HRESULT XMLHTTPRequest_create(void **) DECLSPEC_HIDDEN; -+extern HRESULT XMLHTTPRequest2_create(void **) DECLSPEC_HIDDEN; - extern HRESULT ServerXMLHTTP_create(void **) DECLSPEC_HIDDEN; - extern HRESULT XSLTemplate_create(void**) DECLSPEC_HIDDEN; - extern HRESULT MXWriter_create(MSXML_VERSION, void**) DECLSPEC_HIDDEN; -diff --git a/dlls/msxml3/tests/httpreq.c b/dlls/msxml3/tests/httpreq.c -index 2491e499638..511c2b26763 100644 ---- a/dlls/msxml3/tests/httpreq.c -+++ b/dlls/msxml3/tests/httpreq.c -@@ -26,9 +26,9 @@ - #include - - #include "windows.h" -- - #include "msxml2.h" --#include "msxml2did.h" -+#include "msxml6.h" -+#include "msxml6did.h" - #include "dispex.h" - - #include "initguid.h" -@@ -1348,6 +1348,17 @@ static IXMLHttpRequest *create_xhr(void) - return SUCCEEDED(hr) ? ret : NULL; - } - -+static IXMLHTTPRequest2 *create_xhr2(void) -+{ -+ IXMLHTTPRequest2 *ret; -+ HRESULT hr; -+ -+ hr = CoCreateInstance(&CLSID_FreeThreadedXMLHTTP60, NULL, CLSCTX_INPROC_SERVER, -+ &IID_IXMLHTTPRequest2, (void**)&ret); -+ -+ return SUCCEEDED(hr) ? ret : NULL; -+} -+ - static IServerXMLHTTPRequest *create_server_xhr(void) - { - IServerXMLHTTPRequest *ret; -@@ -1908,11 +1919,388 @@ static void test_supporterrorinfo(void) - IServerXMLHTTPRequest_Release(server_xhr); - } - -+struct xhr3_callback -+{ -+ IXMLHTTPRequest3Callback IXMLHTTPRequest3Callback_iface; -+ LONG ref; -+ HANDLE event; -+}; -+ -+static inline struct xhr3_callback *xhr3_callback_from_IXMLHTTPRequest3Callback(IXMLHTTPRequest3Callback *iface) -+{ -+ return CONTAINING_RECORD(iface, struct xhr3_callback, IXMLHTTPRequest3Callback_iface); -+} -+ -+static HRESULT WINAPI xhr3_callback_QueryInterface(IXMLHTTPRequest3Callback *iface, REFIID riid, void **obj) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); -+ -+ if (IsEqualGUID(riid, &IID_IXMLHTTPRequest3Callback) || IsEqualGUID(riid, &IID_IXMLHTTPRequest2Callback) || IsEqualGUID(riid, &IID_IUnknown)) -+ { -+ IXMLHTTPRequest3Callback_AddRef(iface); -+ *obj = iface; -+ return S_OK; -+ } -+ -+ ok(0, "unexpected interface %s\n", debugstr_guid(riid)); -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI xhr3_callback_AddRef(IXMLHTTPRequest3Callback *iface) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ ULONG ref = InterlockedIncrement(&This->ref); -+ trace("(%p)->(%u)\n", This, ref); -+ return ref; -+} -+ -+static ULONG WINAPI xhr3_callback_Release(IXMLHTTPRequest3Callback *iface) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ ULONG ref = InterlockedDecrement(&This->ref); -+ trace("(%p)->(%u)\n", This, ref); -+ if (ref == 0) HeapFree(GetProcessHeap(), 0, This); -+ return ref; -+} -+ -+static HRESULT WINAPI xhr3_callback_OnRedirect(IXMLHTTPRequest3Callback *iface, -+ IXMLHTTPRequest2 *request, const WCHAR* redirect_url) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ trace("(%p)->(%p %s)\n", This, request, debugstr_w(redirect_url)); -+ return S_OK; -+} -+ -+static HRESULT WINAPI xhr3_callback_OnHeadersAvailable(IXMLHTTPRequest3Callback *iface, -+ IXMLHTTPRequest2 *request, DWORD status, const WCHAR *status_str) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ WCHAR *header = NULL; -+ HRESULT hr; -+ -+ trace("(%p)->(%p %d %s)\n", This, request, status, debugstr_w(status_str)); -+ -+ header = (void *)0xdeadbeef; -+ hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Length", &header); -+ trace("Content-Length: %p (%s), hr %#x\n", header, debugstr_w(header), hr); -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI xhr3_callback_OnDataAvailable(IXMLHTTPRequest3Callback *iface, -+ IXMLHTTPRequest2 *request, ISequentialStream *response) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ trace("(%p)->(%p %p)\n", This, request, response); -+ return S_OK; -+} -+ -+static HRESULT WINAPI xhr3_callback_OnResponseReceived(IXMLHTTPRequest3Callback *iface, -+ IXMLHTTPRequest2 *request, ISequentialStream *response) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ WCHAR *header = NULL; -+ char *buffer = HeapAlloc( GetProcessHeap(), 0, 256 ); -+ ULONG read_size = 0; -+ HRESULT hr; -+ -+ memset(buffer, '?', 256); -+ buffer[255] = 0; -+ -+ trace("(%p)->(%p %p)\n", This, request, response); -+ -+ header = (void *)0xdeadbeef; -+ hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Cache-Control", &header); -+ trace("Cache-Control: %p (%s), hr %#x\n", header, debugstr_w(header), hr); -+ -+ header = (void *)0xdeadbeef; -+ hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Expires", &header); -+ trace("Expires: %p (%s), hr %#x\n", header, debugstr_w(header), hr); -+ -+ header = (void *)0xdeadbeef; -+ hr = IXMLHTTPRequest2_GetResponseHeader(request, L"Content-Type", &header); -+ trace("Content-Type: %p (%s), hr %#x\n", header, debugstr_w(header), hr); -+ -+ read_size = 0xdeadbeef; -+ hr = ISequentialStream_Read(response, buffer, 214, &read_size); -+ trace("Response: (%d) %s, hr %#x\n", read_size, debugstr_a(buffer), hr); -+ -+ read_size = 0xdeadbeef; -+ hr = ISequentialStream_Read(response, buffer, 1, &read_size); -+ trace("Response: (%d) %s, hr %#x\n", read_size, debugstr_a(buffer), hr); -+ -+ HeapFree( GetProcessHeap(), 0, buffer ); -+ SetEvent(This->event); -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI xhr3_callback_OnError(IXMLHTTPRequest3Callback *iface, -+ IXMLHTTPRequest2 *request, HRESULT error) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ trace("(%p)->(%p %#x)\n", This, request, error); -+ SetEvent(This->event); -+ return S_OK; -+} -+ -+static HRESULT WINAPI xhr3_callback_OnServerCertificateReceived(IXMLHTTPRequest3Callback *iface, -+ IXMLHTTPRequest3 *request, DWORD errors, DWORD chain_size, const XHR_CERT *chain) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ trace("(%p)->(%p %u %u %p)\n", This, request, errors, chain_size, chain); -+ return S_OK; -+} -+ -+static HRESULT WINAPI xhr3_callback_OnClientCertificateRequested(IXMLHTTPRequest3Callback *iface, -+ IXMLHTTPRequest3 *request, DWORD issuers_size, const WCHAR **issuers) -+{ -+ struct xhr3_callback *This = xhr3_callback_from_IXMLHTTPRequest3Callback(iface); -+ trace("(%p)->(%p %u %p)\n", This, request, issuers_size, issuers); -+ return S_OK; -+} -+ -+static const IXMLHTTPRequest3CallbackVtbl xhr3_callback_vtbl = -+{ -+ xhr3_callback_QueryInterface, -+ xhr3_callback_AddRef, -+ xhr3_callback_Release, -+ /* IXMLHTTPRequest2Callback methods */ -+ xhr3_callback_OnRedirect, -+ xhr3_callback_OnHeadersAvailable, -+ xhr3_callback_OnDataAvailable, -+ xhr3_callback_OnResponseReceived, -+ xhr3_callback_OnError, -+ /* IXMLHTTPRequest3Callback methods */ -+ xhr3_callback_OnServerCertificateReceived, -+ xhr3_callback_OnClientCertificateRequested, -+}; -+ -+static IXMLHTTPRequest2Callback* xhr3_callback_create(HANDLE event) -+{ -+ struct xhr3_callback *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); -+ ok(This != NULL, "failed to allocate object\n"); -+ if (!This) return NULL; -+ -+ This->IXMLHTTPRequest3Callback_iface.lpVtbl = &xhr3_callback_vtbl; -+ This->ref = 1; -+ This->event = event; -+ -+ return (IXMLHTTPRequest2Callback*)&This->IXMLHTTPRequest3Callback_iface; -+} -+ -+struct xhr2_stream -+{ -+ IStream IStream_iface; -+ LONG ref; -+ IStream *stream; -+}; -+ -+static inline struct xhr2_stream *xhr2_stream_from_IStream(IStream *iface) -+{ -+ return CONTAINING_RECORD(iface, struct xhr2_stream, IStream_iface); -+} -+ -+static HRESULT WINAPI xhr2_stream_QueryInterface(IStream *iface, REFIID riid, void **obj) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%s %p)\n", This, debugstr_guid(riid), obj); -+ -+ if (IsEqualGUID(riid, &IID_IStream) || IsEqualGUID(riid, &IID_ISequentialStream) || IsEqualGUID(riid, &IID_IUnknown)) -+ { -+ IStream_AddRef(iface); -+ *obj = iface; -+ return S_OK; -+ } -+ -+ ok(0, "unexpected interface %s\n", debugstr_guid(riid)); -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI xhr2_stream_AddRef(IStream *iface) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ ULONG ref = InterlockedIncrement(&This->ref); -+ trace("(%p)->(%u)\n", This, ref); -+ return ref; -+} -+ -+static ULONG WINAPI xhr2_stream_Release(IStream *iface) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ ULONG ref = InterlockedDecrement(&This->ref); -+ trace("(%p)->(%u)\n", This, ref); -+ if (ref == 0) -+ { -+ IStream_Release(This->stream); -+ HeapFree(GetProcessHeap(), 0, This); -+ } -+ return ref; -+} -+ -+static HRESULT WINAPI xhr2_stream_Read(IStream *iface, void *pv, ULONG cb, -+ ULONG *pcbRead) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%p %u %p)\n", This, pv, cb, pcbRead); -+ return IStream_Read(This->stream, pv, cb, pcbRead); -+} -+ -+static HRESULT WINAPI xhr2_stream_Write(IStream *iface, const void *pv, -+ ULONG cb, ULONG *pcbWritten) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%p %u %p)\n", This, pv, cb, pcbWritten); -+ return IStream_Write(This->stream, pv, cb, pcbWritten); -+} -+ -+static HRESULT WINAPI xhr2_stream_Seek(IStream *iface, LARGE_INTEGER dlibMove, -+ DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%lu, %u %p)\n", This, dlibMove.QuadPart, dwOrigin, plibNewPosition); -+ return IStream_Seek(This->stream, dlibMove, dwOrigin, plibNewPosition); -+} -+ -+static HRESULT WINAPI xhr2_stream_SetSize(IStream *iface, ULARGE_INTEGER libNewSize) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%lu)\n", This, libNewSize.QuadPart); -+ return IStream_SetSize(This->stream, libNewSize); -+} -+ -+static HRESULT WINAPI xhr2_stream_CopyTo(IStream *iface, IStream *pstm, -+ ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%p %lu %p %p)\n", This, pstm, cb.QuadPart, pcbRead, pcbWritten); -+ return IStream_CopyTo(This->stream, pstm, cb, pcbRead, pcbWritten); -+} -+ -+static HRESULT WINAPI xhr2_stream_Commit(IStream *iface, DWORD grfCommitFlags) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%#x)\n", This, grfCommitFlags); -+ return IStream_Commit(This->stream, grfCommitFlags); -+} -+ -+static HRESULT WINAPI xhr2_stream_Revert(IStream *iface) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->()\n", This); -+ return IStream_Revert(This->stream); -+} -+ -+static HRESULT WINAPI xhr2_stream_LockRegion(IStream *iface, ULARGE_INTEGER libOffset, -+ ULARGE_INTEGER cb, DWORD dwLockType) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%lu %lu %u)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); -+ return IStream_LockRegion(This->stream, libOffset, cb, dwLockType); -+} -+ -+static HRESULT WINAPI xhr2_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER libOffset, -+ ULARGE_INTEGER cb, DWORD dwLockType) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%lu %lu %u)\n", This, libOffset.QuadPart, cb.QuadPart, dwLockType); -+ return IStream_UnlockRegion(This->stream, libOffset, cb, dwLockType); -+} -+ -+static HRESULT WINAPI xhr2_stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD grfStatFlag) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%p %#x)\n", This, pstatstg, grfStatFlag); -+ return IStream_Stat(This->stream, pstatstg, grfStatFlag); -+} -+ -+static HRESULT WINAPI xhr2_stream_Clone(IStream *iface, IStream **ppstm) -+{ -+ struct xhr2_stream *This = xhr2_stream_from_IStream(iface); -+ trace("(%p)->(%p)\n", This, ppstm); -+ return IStream_Clone(This->stream, ppstm); -+} -+ -+static const IStreamVtbl xhr2_stream_vtbl = -+{ -+ xhr2_stream_QueryInterface, -+ xhr2_stream_AddRef, -+ xhr2_stream_Release, -+ /* IStream methods */ -+ xhr2_stream_Read, -+ xhr2_stream_Write, -+ xhr2_stream_Seek, -+ xhr2_stream_SetSize, -+ xhr2_stream_CopyTo, -+ xhr2_stream_Commit, -+ xhr2_stream_Revert, -+ xhr2_stream_LockRegion, -+ xhr2_stream_UnlockRegion, -+ xhr2_stream_Stat, -+ xhr2_stream_Clone -+}; -+ -+static ISequentialStream *xhr2_stream_create(void) -+{ -+ struct xhr2_stream *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); -+ ok(This != NULL, "failed to allocate object\n"); -+ if (!This) return NULL; -+ -+ This->IStream_iface.lpVtbl = &xhr2_stream_vtbl; -+ This->ref = 1; -+ CreateStreamOnHGlobal(NULL, TRUE, &This->stream); -+ -+ return (ISequentialStream*)&This->IStream_iface; -+} -+ -+static void test_IXMLHTTPRequest2(void) -+{ -+ IXMLHTTPRequest2 *xhr2[16]; -+ IXMLHTTPRequest2Callback *xhr3_callback; -+ ISequentialStream *stream; -+ HANDLE events[16]; -+ HRESULT hr; -+ int i = 0; -+ -+ if (!(xhr2[i] = create_xhr2())) -+ { -+ win_skip("IXMLHTTPRequest2 is not available\n"); -+ return; -+ } -+ -+ events[i] = CreateEventW(NULL, FALSE, FALSE, NULL); -+ if (!(xhr3_callback = xhr3_callback_create(events[i]))) -+ return; -+ -+ trace("IXMLHTTPRequest2_Open (%p)->(L\"GET\", L\"http://test.winehq.org/\", xhr3_callback, NULL, NULL, NULL, NULL)\n", GetCurrentThreadId(), xhr2[i]); -+ hr = IXMLHTTPRequest2_Open(xhr2[i], L"GET", L"http://test.winehq.org/", xhr3_callback, NULL, NULL, NULL, NULL); -+ ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#x\n", hr); -+ -+ if ((stream = xhr2_stream_create())) -+ { -+ trace("IXMLHTTPRequest2_Send (%p)->(%p 0)\n", GetCurrentThreadId(), xhr2[i], stream); -+ hr = IXMLHTTPRequest2_Send(xhr2[i], stream, 0); -+ ok(SUCCEEDED(hr), "IXMLHTTPRequest2_Send failed %#x\n", hr); -+ -+ ISequentialStream_Release(stream); -+ } -+ -+ IXMLHTTPRequest2Callback_Release(xhr3_callback); -+ i++; -+ -+ while (i--) -+ { -+ WaitForSingleObject(events[i], INFINITE); -+ IXMLHTTPRequest2_Release(xhr2[i]); -+ } -+} -+ - START_TEST(httpreq) - { - IXMLHttpRequest *xhr; - -- CoInitialize(NULL); -+ CoInitializeEx(NULL, COINIT_MULTITHREADED); - - if (!(xhr = create_xhr())) - { -@@ -1927,6 +2315,7 @@ START_TEST(httpreq) - test_server_xhr(); - test_safe_httpreq(); - test_supporterrorinfo(); -+ test_IXMLHTTPRequest2(); - - CoUninitialize(); - } -diff --git a/dlls/msxml3/tests/schema.c b/dlls/msxml3/tests/schema.c -index 219d7144ddb..7ef033237a1 100644 ---- a/dlls/msxml3/tests/schema.c -+++ b/dlls/msxml3/tests/schema.c -@@ -32,10 +32,16 @@ - #include "dispex.h" - #include "cguid.h" - -+DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_FreeThreadedXMLHTTP60, 0x88d96a09, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_SAXXMLReader60, 0x88d96a0c, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(IID_IXMLHTTPRequest2, 0xe5d37dc0, 0x552a, 0x4d52, 0x9c,0xc0, 0xa1,0x4d,0x54,0x6f,0xbd,0x04); -+DEFINE_GUID(IID_IXMLHTTPRequest3, 0xa1c9feee, 0x0617, 0x4f23, 0x9d,0x58, 0x89,0x61,0xea,0x43,0x56,0x7c); -+DEFINE_GUID(IID_IXMLHTTPRequest2Callback, 0xa44a9299, 0xe321, 0x40de, 0x88,0x66, 0x34,0x1b,0x41,0x66,0x91,0x62); -+DEFINE_GUID(IID_IXMLHTTPRequest3Callback, 0xb9e57830, 0x8c6c, 0x4a6f, 0x9c,0x13, 0x47,0x77,0x2b,0xb0,0x47,0xbb); - - #include "wine/test.h" - -diff --git a/dlls/msxml3/uuid.c b/dlls/msxml3/uuid.c -index 333d4f3d3c7..1b4f0452c5f 100644 ---- a/dlls/msxml3/uuid.c -+++ b/dlls/msxml3/uuid.c -@@ -43,6 +43,7 @@ - - /* Cannot include msxml6 here since we will get a duplicate LIBID_MSXML2 error. */ - DEFINE_GUID(CLSID_FreeThreadedDOMDocument60, 0x88d96a06, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(CLSID_FreeThreadedXMLHTTP60, 0x88d96a09, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_MXNamespaceManager60, 0x88d96a11, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_MXXMLWriter60, 0x88d96a0f, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_SAXAttributes60, 0x88d96a0e, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -@@ -51,6 +52,10 @@ DEFINE_GUID(CLSID_ServerXMLHTTP60, 0x88d96a0b, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0 - DEFINE_GUID(CLSID_XMLHTTP60, 0x88d96a0a, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_XMLSchemaCache60, 0x88d96a07, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); - DEFINE_GUID(CLSID_XSLTemplate60, 0x88d96a08, 0xf192, 0x11d4, 0xa6,0x5f, 0x00,0x40,0x96,0x32,0x51,0xe5); -+DEFINE_GUID(IID_IXMLHTTPRequest2, 0xe5d37dc0, 0x552a, 0x4d52, 0x9c,0xc0, 0xa1,0x4d,0x54,0x6f,0xbd,0x04); -+DEFINE_GUID(IID_IXMLHTTPRequest3, 0xa1c9feee, 0x0617, 0x4f23, 0x9d,0x58, 0x89,0x61,0xea,0x43,0x56,0x7c); -+DEFINE_GUID(IID_IXMLHTTPRequest2Callback, 0xa44a9299, 0xe321, 0x40de, 0x88,0x66, 0x34,0x1b,0x41,0x66,0x91,0x62); -+DEFINE_GUID(IID_IXMLHTTPRequest3Callback, 0xb9e57830, 0x8c6c, 0x4a6f, 0x9c,0x13, 0x47,0x77,0x2b,0xb0,0x47,0xbb); - - /* - * Note that because of a #define in msxml2.h, we end up initializing -From bc9e13e8843b3417b4398c2036ab8bacbcc8d664 Mon Sep 17 00:00:00 2001 -From: Zhiyi Zhang -Date: Mon, 11 Oct 2021 11:01:33 +0200 -Subject: [PATCH] msctf: Use list to keep thread managers. - -Thread managers were stored in thread local storage, -which have a major flaw that they can't not be released -by another thread. - -Signed-off-by: Zhiyi Zhang ---- - dlls/msctf/msctf.c | 46 +++++++---------------- - dlls/msctf/msctf_internal.h | 1 - - dlls/msctf/threadmgr.c | 73 ++++++++++++++++++++++++++++++++----- - 3 files changed, 76 insertions(+), 44 deletions(-) - -diff --git a/dlls/msctf/msctf.c b/dlls/msctf/msctf.c -index 4ae9e16d453..ee4fe84b8c9 100644 ---- a/dlls/msctf/msctf.c -+++ b/dlls/msctf/msctf.c -@@ -67,7 +67,6 @@ static UINT array_size; - static struct list AtsList = LIST_INIT(AtsList); - static UINT activated = 0; - --DWORD tlsIndex = 0; - TfClientId processId = 0; - ITfCompartmentMgr *globalCompartmentMgr = NULL; - -@@ -395,23 +394,19 @@ HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) - ActivatedTextService *actsvr; - ITfCategoryMgr *catmgr; - AtsEntry *entry; -- ITfThreadMgrEx *tm = TlsGetValue(tlsIndex); -+ ITfThreadMgr *tm; - ITfClientId *clientid; - -- if (!tm) return E_UNEXPECTED; -+ if (FAILED(TF_GetThreadMgr(&tm))) return E_UNEXPECTED; - - actsvr = HeapAlloc(GetProcessHeap(),0,sizeof(ActivatedTextService)); -- if (!actsvr) return E_OUTOFMEMORY; -+ if (!actsvr) goto fail; - -- ITfThreadMgrEx_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); -+ ITfThreadMgr_QueryInterface(tm, &IID_ITfClientId, (void **)&clientid); - ITfClientId_GetClientId(clientid, &lp->clsid, &actsvr->tid); - ITfClientId_Release(clientid); - -- if (!actsvr->tid) -- { -- HeapFree(GetProcessHeap(),0,actsvr); -- return E_OUTOFMEMORY; -- } -+ if (!actsvr->tid) goto fail; - - actsvr->pITfTextInputProcessor = NULL; - actsvr->LanguageProfile = *lp; -@@ -438,20 +433,21 @@ HRESULT add_active_textservice(TF_LANGUAGEPROFILE *lp) - deactivate_remove_conflicting_ts(&actsvr->LanguageProfile.catid); - - if (activated > 0) -- activate_given_ts(actsvr, tm); -+ activate_given_ts(actsvr, (ITfThreadMgrEx *)tm); - - entry = HeapAlloc(GetProcessHeap(),0,sizeof(AtsEntry)); -- -- if (!entry) -- { -- HeapFree(GetProcessHeap(),0,actsvr); -- return E_OUTOFMEMORY; -- } -+ if (!entry) goto fail; - - entry->ats = actsvr; - list_add_head(&AtsList, &entry->entry); - -+ ITfThreadMgr_Release(tm); - return S_OK; -+ -+fail: -+ ITfThreadMgr_Release(tm); -+ HeapFree(GetProcessHeap(), 0, actsvr); -+ return E_OUTOFMEMORY; - } - - BOOL get_active_textservice(REFCLSID rclsid, TF_LANGUAGEPROFILE *profile) -@@ -555,11 +551,9 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD fdwReason, LPVOID fImpLoad) - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: -- tlsIndex = TlsAlloc(); - break; - case DLL_PROCESS_DETACH: - if (fImpLoad) break; -- TlsFree(tlsIndex); - break; - } - return TRUE; -@@ -593,20 +587,6 @@ HRESULT WINAPI TF_CreateThreadMgr(ITfThreadMgr **pptim) - return ThreadMgr_Constructor(NULL,(IUnknown**)pptim); - } - --/*********************************************************************** -- * TF_GetThreadMgr (MSCTF.@) -- */ --HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) --{ -- TRACE("\n"); -- *pptim = TlsGetValue(tlsIndex); -- -- if (*pptim) -- ITfThreadMgr_AddRef(*pptim); -- -- return S_OK; --} -- - /*********************************************************************** - * SetInputScope(MSCTF.@) - */ -diff --git a/dlls/msctf/msctf_internal.h b/dlls/msctf/msctf_internal.h -index 45a39806c22..84f8ebf81c2 100644 ---- a/dlls/msctf/msctf_internal.h -+++ b/dlls/msctf/msctf_internal.h -@@ -36,7 +36,6 @@ - #define COOKIE_MAGIC_INPUTPROCESSORPROFILEACTIVATIONSINK 0x00b0 - #define COOKIE_MAGIC_ACTIVELANGSINK 0x00c0 - --extern DWORD tlsIndex DECLSPEC_HIDDEN; - extern TfClientId processId DECLSPEC_HIDDEN; - extern ITfCompartmentMgr *globalCompartmentMgr DECLSPEC_HIDDEN; - -diff --git a/dlls/msctf/threadmgr.c b/dlls/msctf/threadmgr.c -index 0e054d4e654..23bf24fb118 100644 ---- a/dlls/msctf/threadmgr.c -+++ b/dlls/msctf/threadmgr.c -@@ -37,6 +37,17 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(msctf); - -+static CRITICAL_SECTION ThreadMgrCs; -+static CRITICAL_SECTION_DEBUG ThreadMgrCsDebug = -+{ -+ 0, 0, &ThreadMgrCs, -+ {&ThreadMgrCsDebug.ProcessLocksList, -+ &ThreadMgrCsDebug.ProcessLocksList }, -+ 0, 0, {(DWORD_PTR)(__FILE__ ": ThreadMgrCs")} -+}; -+static CRITICAL_SECTION ThreadMgrCs = {&ThreadMgrCsDebug, -1, 0, 0, 0, 0}; -+struct list ThreadMgrList = LIST_INIT(ThreadMgrList); -+ - typedef struct tagPreservedKey - { - struct list entry; -@@ -98,6 +109,9 @@ typedef struct tagACLMulti { - struct list ThreadMgrEventSink; - struct list UIElementSink; - struct list InputProcessorProfileActivationSink; -+ -+ DWORD threadId; -+ struct list entry; - } ThreadMgr; - - typedef struct tagEnumTfDocumentMgr { -@@ -110,6 +124,11 @@ typedef struct tagEnumTfDocumentMgr { - - static HRESULT EnumTfDocumentMgr_Constructor(struct list* head, IEnumTfDocumentMgrs **ppOut); - -+static inline ThreadMgr *impl_from_ITfThreadMgr(ITfThreadMgr *iface) -+{ -+ return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); -+} -+ - static inline ThreadMgr *impl_from_ITfThreadMgrEx(ITfThreadMgrEx *iface) - { - return CONTAINING_RECORD(iface, ThreadMgr, ITfThreadMgrEx_iface); -@@ -155,6 +174,35 @@ static inline EnumTfDocumentMgr *impl_from_IEnumTfDocumentMgrs(IEnumTfDocumentMg - return CONTAINING_RECORD(iface, EnumTfDocumentMgr, IEnumTfDocumentMgrs_iface); - } - -+/*********************************************************************** -+ * TF_GetThreadMgr (MSCTF.@) -+ */ -+HRESULT WINAPI TF_GetThreadMgr(ITfThreadMgr **pptim) -+{ -+ DWORD id = GetCurrentThreadId(); -+ ThreadMgr *cursor; -+ -+ TRACE("%p\n", pptim); -+ -+ if (!pptim) -+ return E_INVALIDARG; -+ -+ EnterCriticalSection(&ThreadMgrCs); -+ LIST_FOR_EACH_ENTRY(cursor, &ThreadMgrList, ThreadMgr, entry) -+ { -+ if (cursor->threadId == id) -+ { -+ ITfThreadMgrEx_AddRef(&cursor->ITfThreadMgrEx_iface); -+ *pptim = (ITfThreadMgr *)&cursor->ITfThreadMgrEx_iface; -+ LeaveCriticalSection(&ThreadMgrCs); -+ return S_OK; -+ } -+ } -+ LeaveCriticalSection(&ThreadMgrCs); -+ *pptim = NULL; -+ return E_FAIL; -+} -+ - static void ThreadMgr_Destructor(ThreadMgr *This) - { - struct list *cursor, *cursor2; -@@ -163,7 +211,9 @@ static void ThreadMgr_Destructor(ThreadMgr *This) - if (This->focusHook) - UnhookWindowsHookEx(This->focusHook); - -- TlsSetValue(tlsIndex,NULL); -+ EnterCriticalSection(&ThreadMgrCs); -+ list_remove(&This->entry); -+ LeaveCriticalSection(&ThreadMgrCs); - TRACE("destroying %p\n", This); - if (This->focus) - ITfDocumentMgr_Release(This->focus); -@@ -386,17 +436,20 @@ static HRESULT WINAPI ThreadMgr_SetFocus(ITfThreadMgrEx *iface, ITfDocumentMgr * - - static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lParam) - { -+ ITfThreadMgr *ThreadMgr_iface; - ThreadMgr *This; - -- This = TlsGetValue(tlsIndex); -- if (!This) -+ if (FAILED(TF_GetThreadMgr(&ThreadMgr_iface))) - { - ERR("Hook proc but no ThreadMgr for this thread. Serious Error\n"); - return 0; - } -+ -+ This = impl_from_ITfThreadMgr(ThreadMgr_iface); - if (!This->focusHook) - { - ERR("Hook proc but no ThreadMgr focus Hook. Serious Error\n"); -+ ITfThreadMgr_Release(ThreadMgr_iface); - return 0; - } - -@@ -417,6 +470,7 @@ static LRESULT CALLBACK ThreadFocusHookProc(int nCode, WPARAM wParam, LPARAM lPa - } - } - -+ ITfThreadMgr_Release(ThreadMgr_iface); - return CallNextHookEx(This->focusHook, nCode, wParam, lParam); - } - -@@ -1346,13 +1400,8 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) - return CLASS_E_NOAGGREGATION; - - /* Only 1 ThreadMgr is created per thread */ -- This = TlsGetValue(tlsIndex); -- if (This) -- { -- ThreadMgr_AddRef(&This->ITfThreadMgrEx_iface); -- *ppOut = (IUnknown*)&This->ITfThreadMgrEx_iface; -+ if (SUCCEEDED(TF_GetThreadMgr((ITfThreadMgr **)ppOut))) - return S_OK; -- } - - This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ThreadMgr)); - if (This == NULL) -@@ -1367,7 +1416,6 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) - This->ITfUIElementMgr_iface.lpVtbl = &ThreadMgrUIElementMgrVtbl; - This->ITfSourceSingle_iface.lpVtbl = &SourceSingleVtbl; - This->refCount = 1; -- TlsSetValue(tlsIndex,This); - - CompartmentMgr_Constructor((IUnknown*)&This->ITfThreadMgrEx_iface, &IID_IUnknown, (IUnknown**)&This->CompartmentMgr); - -@@ -1384,6 +1432,11 @@ HRESULT ThreadMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut) - list_init(&This->UIElementSink); - list_init(&This->InputProcessorProfileActivationSink); - -+ This->threadId = GetCurrentThreadId(); -+ EnterCriticalSection(&ThreadMgrCs); -+ list_add_tail(&ThreadMgrList, &This->entry); -+ LeaveCriticalSection(&ThreadMgrCs); -+ - TRACE("returning %p\n", This); - *ppOut = (IUnknown *)&This->ITfThreadMgrEx_iface; - return S_OK; -From 9bb551b8351ec76729565220bab9509a156b615e Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 4 Nov 2020 18:08:21 +0300 -Subject: [PATCH] ws2_32: HACK Fail 'download-alt.easyanticheat.net' DNS name - resolution. - -CW-Bug-Id: #16695 ---- - dlls/ws2_32/protocol.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c -index 867e9513ca2..134624ad1f3 100644 ---- a/dlls/ws2_32/protocol.c -+++ b/dlls/ws2_32/protocol.c -@@ -169,6 +169,13 @@ int WINAPI getaddrinfo( const char *node, const char *service, - - if (node) - { -+ if (!strcmp(node, "download-alt.easyanticheat.net")) -+ { -+ ERR("HACK: failing download-alt.easyanticheat.net resolution.\n"); -+ SetLastError(WSAHOST_NOT_FOUND); -+ return WSAHOST_NOT_FOUND; -+ } -+ - if (!node[0]) - { - if (!(fqdn = get_fqdn())) return WSA_NOT_ENOUGH_MEMORY; -@@ -926,6 +933,13 @@ struct hostent * WINAPI gethostbyname( const char *name ) - return NULL; - } - -+ if (name && !strcmp(name, "download-alt.easyanticheat.net")) -+ { -+ ERR("HACK: failing download-alt.easyanticheat.net resolution.\n"); -+ SetLastError( WSAHOST_NOT_FOUND ); -+ return NULL; -+ } -+ - if ((ret = WS_CALL( gethostname, ¶ms ))) - { - SetLastError( ret ); -From b9a6702e81339766285365197f894f38e7c62ed3 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 26 Jun 2020 15:26:53 +0300 -Subject: [PATCH] Avoid undefined result in ntdll_wcstoumbs() in case of error. - -CW-Bug-Id: #17864 - -Undefined result is due to RtlUnicodeToUTF8N() not setting output -length on error which is a correct behaviour according to -existing tests. - -'Planet Zoo' is affected which passes NULL object name buffer to -NtCreateFile(). - -Signed-off-by: Paul Gofman ---- - dlls/ntdll/unix/env.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c -index 6130ad23c15..fe14b48420d 100644 ---- a/dlls/ntdll/unix/env.c -+++ b/dlls/ntdll/unix/env.c -@@ -658,7 +658,7 @@ DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen ) - */ - int ntdll_wcstoumbs( const WCHAR *src, DWORD srclen, char *dst, DWORD dstlen, BOOL strict ) - { -- DWORD i, reslen; -+ DWORD i, reslen = 0; - - if (unix_cp.data) - { -From 4b3272d0e6a072fa63d668679294e8be7fafa38e Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Sat, 22 May 2021 01:23:33 +0300 -Subject: [PATCH] server: Update system regs from set_thread_context handler - only. - -CW-Bug-Id: #18957 ---- - server/thread.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/server/thread.c b/server/thread.c -index 4ee25f178ff..6300fda0396 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -1855,8 +1855,6 @@ DECL_HANDLER(select) - if (ctx->regs[CTX_NATIVE].flags || ctx->regs[CTX_WOW].flags) - { - data_size_t size = (ctx->regs[CTX_WOW].flags ? 2 : 1) * sizeof(context_t); -- unsigned int flags = system_flags & ctx->regs[CTX_NATIVE].flags; -- if (flags) set_thread_context( current, &ctx->regs[CTX_NATIVE], flags ); - set_reply_data( ctx->regs, min( size, get_reply_max_size() )); - } - release_object( ctx ); -@@ -2095,7 +2093,7 @@ DECL_HANDLER(set_thread_context) - unsigned int native_flags = always_native_flags & context->flags; - - if (thread != current) stop_thread( thread ); -- else if (flags) set_thread_context( thread, context, flags ); -+ if (system_flags) set_thread_context( thread, context, system_flags ); - if (thread->context && !get_error()) - { - if (ctx_count == 2) -From ee874587e97ef62a9ac2f4b17ea2c2ffc1d39f10 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 24 May 2021 14:37:35 +0300 -Subject: [PATCH] ntdll: Update cached debug registers in call_init_thunk(). - -CW-Bug-Id: #18957 ---- - dlls/ntdll/unix/signal_i386.c | 14 +++++++++++++- - dlls/ntdll/unix/signal_x86_64.c | 14 +++++++++++++- - 2 files changed, 26 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c -index 4f471ffb03b..1ad9f86d659 100644 ---- a/dlls/ntdll/unix/signal_i386.c -+++ b/dlls/ntdll/unix/signal_i386.c -@@ -2390,7 +2390,19 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B - ((XSAVE_FORMAT *)context.ExtendedRegisters)->MxCsr = 0x1f80; - if ((ctx = get_cpu_area( IMAGE_FILE_MACHINE_I386 ))) *ctx = context; - -- if (suspend) wait_suspend( &context ); -+ if (suspend) -+ { -+ wait_suspend( &context ); -+ if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386) -+ { -+ x86_thread_data()->dr0 = context.Dr0; -+ x86_thread_data()->dr1 = context.Dr1; -+ x86_thread_data()->dr2 = context.Dr2; -+ x86_thread_data()->dr3 = context.Dr3; -+ x86_thread_data()->dr6 = context.Dr6; -+ x86_thread_data()->dr7 = context.Dr7; -+ } -+ } - - ctx = (CONTEXT *)((ULONG_PTR)context.Esp & ~3) - 1; - *ctx = context; -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 09465d028c6..03e9b5c007d 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -3294,7 +3294,19 @@ void DECLSPEC_HIDDEN call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, B - *(XSAVE_FORMAT *)wow_context->ExtendedRegisters = context.u.FltSave; - } - -- if (suspend) wait_suspend( &context ); -+ if (suspend) -+ { -+ wait_suspend( &context ); -+ if (context.ContextFlags & CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64) -+ { -+ amd64_thread_data()->dr0 = context.Dr0; -+ amd64_thread_data()->dr1 = context.Dr1; -+ amd64_thread_data()->dr2 = context.Dr2; -+ amd64_thread_data()->dr3 = context.Dr3; -+ amd64_thread_data()->dr6 = context.Dr6; -+ amd64_thread_data()->dr7 = context.Dr7; -+ } -+ } - - ctx = (CONTEXT *)((ULONG_PTR)context.Rsp & ~15) - 1; - *ctx = context; -From 3bc7d74cb44dfdb3b0311b823723cfd0ff746f21 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Sat, 22 May 2021 03:08:55 +0300 -Subject: [PATCH] ntdll: Use cached debug registers in NtGetContextThread() if - hw debug breakpoints are disabled. - -CW-Bug-Id: #18957 ---- - dlls/ntdll/unix/signal_i386.c | 37 ++++++++++++++++++++++++--------- - dlls/ntdll/unix/signal_x86_64.c | 37 ++++++++++++++++++++++++--------- - 2 files changed, 54 insertions(+), 20 deletions(-) - -diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c -index 1ad9f86d659..9edd425ac3d 100644 ---- a/dlls/ntdll/unix/signal_i386.c -+++ b/dlls/ntdll/unix/signal_i386.c -@@ -990,10 +990,15 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) - struct syscall_frame *frame = x86_thread_data()->syscall_frame; - DWORD needed_flags = context->ContextFlags & ~CONTEXT_i386; - BOOL self = (handle == GetCurrentThread()); -+ BOOL use_cached_debug_regs = FALSE; - NTSTATUS ret; - -- /* debug registers require a server call */ -- if (needed_flags & CONTEXT_DEBUG_REGISTERS) self = FALSE; -+ if (self && needed_flags & CONTEXT_DEBUG_REGISTERS) -+ { -+ /* debug registers require a server call if hw breakpoints are enabled */ -+ if (x86_thread_data()->dr7 & 0xff) self = FALSE; -+ else use_cached_debug_regs = TRUE; -+ } - - if (!self) - { -@@ -1101,15 +1106,27 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) - xstate->YmmContext = frame->xstate.YmmContext; - } - } -- /* update the cached version of the debug registers */ -- if (needed_flags & CONTEXT_DEBUG_REGISTERS) -+ if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) - { -- x86_thread_data()->dr0 = context->Dr0; -- x86_thread_data()->dr1 = context->Dr1; -- x86_thread_data()->dr2 = context->Dr2; -- x86_thread_data()->dr3 = context->Dr3; -- x86_thread_data()->dr6 = context->Dr6; -- x86_thread_data()->dr7 = context->Dr7; -+ if (use_cached_debug_regs) -+ { -+ context->Dr0 = x86_thread_data()->dr0; -+ context->Dr1 = x86_thread_data()->dr1; -+ context->Dr2 = x86_thread_data()->dr2; -+ context->Dr3 = x86_thread_data()->dr3; -+ context->Dr6 = x86_thread_data()->dr6; -+ context->Dr7 = x86_thread_data()->dr7; -+ } -+ else -+ { -+ /* update the cached version of the debug registers */ -+ x86_thread_data()->dr0 = context->Dr0; -+ x86_thread_data()->dr1 = context->Dr1; -+ x86_thread_data()->dr2 = context->Dr2; -+ x86_thread_data()->dr3 = context->Dr3; -+ x86_thread_data()->dr6 = context->Dr6; -+ x86_thread_data()->dr7 = context->Dr7; -+ } - } - } - -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 03e9b5c007d..e67907309d0 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -1803,10 +1803,15 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) - { - struct syscall_frame *frame = amd64_thread_data()->syscall_frame; - DWORD needed_flags = context->ContextFlags & ~CONTEXT_AMD64; -+ BOOL use_cached_debug_regs = FALSE; - BOOL self = (handle == GetCurrentThread()); - -- /* debug registers require a server call */ -- if (needed_flags & CONTEXT_DEBUG_REGISTERS) self = FALSE; -+ if (self && needed_flags & CONTEXT_DEBUG_REGISTERS) -+ { -+ /* debug registers require a server call if hw breakpoints are enabled */ -+ if (amd64_thread_data()->dr7 & 0xff) self = FALSE; -+ else use_cached_debug_regs = TRUE; -+ } - - if (!self) - { -@@ -1905,15 +1910,27 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) - memcpy( &xstate->YmmContext, &frame->xstate.YmmContext, sizeof(xstate->YmmContext) ); - } - } -- /* update the cached version of the debug registers */ -- if (needed_flags & CONTEXT_DEBUG_REGISTERS) -+ if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64)) - { -- amd64_thread_data()->dr0 = context->Dr0; -- amd64_thread_data()->dr1 = context->Dr1; -- amd64_thread_data()->dr2 = context->Dr2; -- amd64_thread_data()->dr3 = context->Dr3; -- amd64_thread_data()->dr6 = context->Dr6; -- amd64_thread_data()->dr7 = context->Dr7; -+ if (use_cached_debug_regs) -+ { -+ context->Dr0 = amd64_thread_data()->dr0; -+ context->Dr1 = amd64_thread_data()->dr1; -+ context->Dr2 = amd64_thread_data()->dr2; -+ context->Dr3 = amd64_thread_data()->dr3; -+ context->Dr6 = amd64_thread_data()->dr6; -+ context->Dr7 = amd64_thread_data()->dr7; -+ } -+ else -+ { -+ /* update the cached version of the debug registers */ -+ amd64_thread_data()->dr0 = context->Dr0; -+ amd64_thread_data()->dr1 = context->Dr1; -+ amd64_thread_data()->dr2 = context->Dr2; -+ amd64_thread_data()->dr3 = context->Dr3; -+ amd64_thread_data()->dr6 = context->Dr6; -+ amd64_thread_data()->dr7 = context->Dr7; -+ } - } - return STATUS_SUCCESS; - } -From dcc7655978f00ec4aa6a643b3988e7b1f5b4605d Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 21 May 2021 15:10:07 +0300 -Subject: [PATCH] ntdll: Read process memory on the client side in - NtReadVirtualMemory(). - -CW-Bug-Id: 18957 ---- - dlls/ntdll/unix/server.c | 2 +- - dlls/ntdll/unix/virtual.c | 46 +++++++++++++++++++++++++++++++++++++++ - server/process.c | 2 ++ - server/protocol.def | 1 + - 4 files changed, 50 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c -index b7873c2955b..6b3fa8e7a11 100644 ---- a/dlls/ntdll/unix/server.c -+++ b/dlls/ntdll/unix/server.c -@@ -1480,7 +1480,7 @@ size_t server_init_process(void) - (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" ); - #if defined(__linux__) && defined(HAVE_PRCTL) - /* work around Ubuntu's ptrace breakage */ -- if (server_pid != -1) prctl( 0x59616d61 /* PR_SET_PTRACER */, server_pid ); -+ if (server_pid != -1) prctl( 0x59616d61 /* PR_SET_PTRACER */, PR_SET_PTRACER_ANY ); - #endif - - /* ignore SIGPIPE so that we get an EPIPE error instead */ -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index a2452943ceb..e7b23e3dcd4 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -64,6 +64,8 @@ - # include - #endif - -+#include -+ - #include "ntstatus.h" - #define WIN32_NO_STATUS - #include "windef.h" -@@ -4843,7 +4845,50 @@ NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buf - SIZE_T size, SIZE_T *bytes_read ) - { - NTSTATUS status; -+#ifdef linux -+ struct iovec local, remote; -+ int unix_pid; -+ ssize_t ret; -+ -+ SERVER_START_REQ( read_process_memory ) -+ { -+ req->handle = wine_server_obj_handle( process ); -+ status = wine_server_call( req ); -+ unix_pid = reply->unix_pid; -+ } -+ SERVER_END_REQ; -+ -+ if (status) -+ { -+ WARN( "Could not get unix_pid for process %p, status %#x.\n", process, status ); -+ size = 0; -+ goto done; -+ } -+ -+ local.iov_base = buffer; -+ local.iov_len = size; - -+ remote.iov_base = (void *)addr; -+ remote.iov_len = size; -+ -+ if ((ret = process_vm_readv( unix_pid, &local, 1, &remote, 1, 0 )) != size) -+ { -+ WARN( "Error reading memory from process %p, addr %p, size %p, buffer %p, ret %p, errno %d.\n", -+ process, addr, (void *)size, buffer, (void *)ret, errno ); -+ -+ if (ret == -1) -+ { -+ status = errno == ESRCH ? STATUS_PARTIAL_COPY : errno_to_status( errno ); -+ size = 0; -+ } -+ else -+ { -+ status = STATUS_PARTIAL_COPY; -+ size = ret; -+ } -+ } -+done: -+#else - if (virtual_check_buffer_for_write( buffer, size )) - { - SERVER_START_REQ( read_process_memory ) -@@ -4860,6 +4905,7 @@ NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buf - status = STATUS_ACCESS_VIOLATION; - size = 0; - } -+#endif - if (bytes_read) *bytes_read = size; - return status; - } -diff --git a/server/process.c b/server/process.c -index 3b7261ada23..88092d664ec 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -1702,6 +1702,8 @@ DECL_HANDLER(read_process_memory) - - if (!(process = get_process_from_handle( req->handle, PROCESS_VM_READ ))) return; - -+ reply->unix_pid = process->unix_pid; -+ - if (len) - { - char *buffer = mem_alloc( len ); -diff --git a/server/protocol.def b/server/protocol.def -index e3f2b6857e5..586122a9928 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -1683,6 +1683,7 @@ struct process_info - obj_handle_t handle; /* process handle */ - client_ptr_t addr; /* addr to read from */ - @REPLY -+ int unix_pid; /* Unix pid of new process */ - VARARG(data,bytes); /* result data */ - @END - -From 157c6cbeb57355384b7ac53558cb96101d3ede10 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 26 Oct 2021 19:07:26 +0300 -Subject: [PATCH] ntdll: Don't use Wine frames during exception processing on - x64. - -CW-Bug-ID: #19570 ---- - dlls/ntdll/signal_x86_64.c | 65 +++++++++++++++++++++++++++----------- - 1 file changed, 46 insertions(+), 19 deletions(-) - -diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c -index 7e77329363c..5299877baa8 100644 ---- a/dlls/ntdll/signal_x86_64.c -+++ b/dlls/ntdll/signal_x86_64.c -@@ -346,15 +346,32 @@ __ASM_GLOBAL_FUNC( RtlCaptureContext, - "fxsave 0x100(%rcx)\n\t" /* context->FltSave */ - "ret" ); - --static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, -+DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, - CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) - { -+ TRACE( "exception flags %#x.\n", rec->ExceptionFlags ); -+ - if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))) -- rec->ExceptionFlags |= EH_NESTED_CALL; -+ return ExceptionNestedException; - - return ExceptionContinueSearch; - } - -+/*********************************************************************** -+ * exception_handler_call_wrapper -+ */ -+DWORD exception_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame, -+ CONTEXT *context, DISPATCHER_CONTEXT *dispatch ); -+__ASM_GLOBAL_FUNC( exception_handler_call_wrapper, -+ __ASM_SEH(".seh_endprologue\n\t") -+ "subq $0x28, %rsp\n\t" -+ __ASM_SEH(".seh_stackalloc 0x28\n\t") -+ __ASM_SEH(".seh_handler nested_exception_handler, @except\n\t") -+ "callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */ -+ "nop\n\t" -+ "addq $0x28, %rsp\n\t" -+ "ret" ); -+ - /********************************************************************** - * call_handler - * -@@ -363,19 +380,19 @@ static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_ - */ - static DWORD call_handler( EXCEPTION_RECORD *rec, CONTEXT *context, DISPATCHER_CONTEXT *dispatch ) - { -- EXCEPTION_REGISTRATION_RECORD frame; - DWORD res; - -- frame.Handler = nested_exception_handler; -- __wine_push_frame( &frame ); -- - TRACE_(seh)( "calling handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n", - dispatch->LanguageHandler, rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); -- res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, context, dispatch ); -+ res = exception_handler_call_wrapper( rec, (void *)dispatch->EstablisherFrame, context, dispatch ); - TRACE_(seh)( "handler at %p returned %u\n", dispatch->LanguageHandler, res ); - - rec->ExceptionFlags &= EH_NONCONTINUABLE; -- __wine_pop_frame( &frame ); -+ if (res == ExceptionNestedException) -+ { -+ rec->ExceptionFlags |= EH_NESTED_CALL; -+ res = ExceptionContinueSearch; -+ } - return res; - } - -@@ -974,7 +991,8 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc, - - struct unwind_exception_frame - { -- EXCEPTION_REGISTRATION_RECORD frame; -+ BYTE dummy[0x28]; -+ void *rip; - DISPATCHER_CONTEXT *dispatch; - }; - -@@ -983,7 +1001,7 @@ struct unwind_exception_frame - * - * Handler for exceptions happening while calling an unwind handler. - */ --static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, -+DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, - CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) - { - struct unwind_exception_frame *unwind_frame = (struct unwind_exception_frame *)frame; -@@ -1003,27 +1021,36 @@ static DWORD __cdecl unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_ - return ExceptionCollidedUnwind; - } - -+/*********************************************************************** -+ * exception_handler_call_wrapper -+ */ -+DWORD unwind_handler_call_wrapper( EXCEPTION_RECORD *rec, void *frame, -+ CONTEXT *context, DISPATCHER_CONTEXT *dispatch ); -+__ASM_GLOBAL_FUNC( unwind_handler_call_wrapper, -+ __ASM_SEH(".seh_endprologue\n\t") -+ "movq %r9, 0x8(%rsp)\n\t" -+ "subq $0x28, %rsp\n\t" -+ __ASM_SEH(".seh_stackalloc 0x28\n\t") -+ __ASM_SEH(".seh_handler unwind_exception_handler, @except, @unwind\n\t") -+ "callq *0x30(%r9)\n\t" /* dispatch->LanguageHandler */ -+ "nop\n\t" -+ "addq $0x28, %rsp\n\t" -+ "ret" ); -+ - /********************************************************************** - * call_unwind_handler - * - * Call a single unwind handler. - */ --static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch ) -+DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch ) - { -- struct unwind_exception_frame frame; - DWORD res; - -- frame.frame.Handler = unwind_exception_handler; -- frame.dispatch = dispatch; -- __wine_push_frame( &frame.frame ); -- - TRACE( "calling handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n", - dispatch->LanguageHandler, rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); -- res = dispatch->LanguageHandler( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); -+ res = unwind_handler_call_wrapper( rec, (void *)dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch ); - TRACE( "handler %p returned %x\n", dispatch->LanguageHandler, res ); - -- __wine_pop_frame( &frame.frame ); -- - switch (res) - { - case ExceptionContinueSearch: -From de668f7cc3095e57a4d6ba3017b68c2e426c84da Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 31 Mar 2020 20:07:49 +0300 -Subject: [PATCH] winex11.drv: Remove active client window from window data - before deleting it. - -CW-Bug-ID: #19216 - -Fixes a crash with BadDrawable X error which happens when client window is used -in windows.c:sync_client_position() after the GL drawable has been deleted. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49649 ---- - dlls/winex11.drv/opengl.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 91119e8d393..f4f4063f9a0 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -251,6 +251,7 @@ enum dc_gl_type - struct gl_drawable - { - LONG ref; /* reference count */ -+ HWND hwnd; - enum dc_gl_type type; /* type of GL surface */ - GLXDrawable drawable; /* drawable for rendering with GL */ - Window window; /* window if drawable is a GLXWindow */ -@@ -1296,10 +1297,23 @@ static void release_gl_drawable( struct gl_drawable *gl ) - { - case DC_GL_WINDOW: - case DC_GL_CHILD_WIN: -+ { -+ struct x11drv_win_data *data = get_win_data( gl->hwnd ); -+ - TRACE( "destroying %lx drawable %lx\n", gl->window, gl->drawable ); -+ if (data) -+ { -+ if (data->client_window == gl->window) -+ { -+ XDeleteContext( data->display, data->client_window, winContext ); -+ data->client_window = 0; -+ } -+ release_win_data( data ); -+ } - pglXDestroyWindow( gdi_display, gl->drawable ); - XDestroyWindow( gdi_display, gl->window ); - break; -+ } - case DC_GL_PIXMAP_WIN: - TRACE( "destroying pixmap %lx drawable %lx\n", gl->pixmap, gl->drawable ); - pglXDestroyPixmap( gdi_display, gl->drawable ); -@@ -1456,6 +1470,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel - /* Default GLX and WGL swap interval is 1, but in case of glXSwapIntervalSGI - * there is no way to query it, so we have to store it here. - */ -+ gl->hwnd = hwnd; - gl->swap_interval = 1; - gl->refresh_swap_interval = TRUE; - gl->format = format; -From 30b6fff2c0571c145d8e8343886a6da1c7510b38 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 8 May 2020 14:32:09 +0300 -Subject: [PATCH] ntdll: Use kernel soft dirty flags for write watches support. - -Requires kernel patches to have effect. ---- - dlls/kernel32/tests/virtual.c | 52 ++++++++++++- - dlls/ntdll/unix/virtual.c | 141 +++++++++++++++++++++++++++++++--- - 2 files changed, 179 insertions(+), 14 deletions(-) - -diff --git a/dlls/kernel32/tests/virtual.c b/dlls/kernel32/tests/virtual.c -index a3b2d365c33..0632f72d3b2 100644 ---- a/dlls/kernel32/tests/virtual.c -+++ b/dlls/kernel32/tests/virtual.c -@@ -2149,15 +2149,61 @@ static void test_write_watch(void) - ok( count == 1, "wrong count %lu\n", count ); - ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); - -+ ret = pResetWriteWatch( base, size ); -+ ok( !ret, "pResetWriteWatch failed %u\n", GetLastError() ); -+ -+ ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot ); -+ ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); -+ ok( old_prot == PAGE_NOACCESS, "wrong old prot %x\n", old_prot ); -+ -+ base[3*pagesize + 200] = 3; -+ base[5*pagesize + 200] = 3; -+ - ret = VirtualFree( base, size, MEM_DECOMMIT ); - ok( ret, "VirtualFree failed %u\n", GetLastError() ); - - count = 64; - ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); - ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); -- ok( count == 1 || broken(count == 0), /* win98 */ -- "wrong count %lu\n", count ); -- if (count) ok( results[0] == base + 5*pagesize, "wrong result %p\n", results[0] ); -+ ok( !count, "wrong count %lu\n", count ); -+ -+ base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_READWRITE ); -+ ok(!!base, "VirtualAlloc failed.\n"); -+ -+ count = 64; -+ ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); -+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); -+ ok( !count, "wrong count %lu\n", count ); -+ -+ base[3*pagesize + 200] = 3; -+ ret = VirtualProtect( base, 6*pagesize, PAGE_READWRITE, &old_prot ); -+ ok( ret, "VirtualProtect failed error %u\n", GetLastError() ); -+ ok( old_prot == PAGE_READWRITE, "wrong old prot %x\n", old_prot ); -+ -+ base[5*pagesize + 200] = 3; -+ count = 64; -+ ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); -+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); -+ ok( count == 2, "wrong count %lu\n", count ); -+ ok( results[0] == base + 3*pagesize && results[1] == base + 5*pagesize, "wrong result %p\n", results[0] ); -+ -+ ret = VirtualFree( base, size, MEM_DECOMMIT ); -+ ok( ret, "VirtualFree failed %u\n", GetLastError() ); -+ -+ count = 64; -+ ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); -+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); -+ todo_wine ok( count == 1, "wrong count %lu\n", count ); -+ ok( results[0] == base + 3*pagesize, "wrong result %p\n", results[0] ); -+ -+ base = VirtualAlloc( base, size, MEM_COMMIT, PAGE_READWRITE ); -+ ok(!!base, "VirtualAlloc failed.\n"); -+ -+ count = 64; -+ ret = pGetWriteWatch( 0, base, size, results, &count, &pagesize ); -+ ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); -+ todo_wine ok( count == 1, "wrong count %lu\n", count ); -+ ok( results[0] == base + 3*pagesize, "wrong result %p\n", results[0] ); - - VirtualFree( base, 0, MEM_RELEASE ); - } -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index e7b23e3dcd4..1317c3bed59 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -202,6 +202,13 @@ static BYTE **pages_vprot; - static BYTE *pages_vprot; - #endif - -+static BOOL use_kernel_writewatch; -+static int pagemap_fd, pagemap_reset_fd, clear_refs_fd; -+#define PAGE_FLAGS_BUFFER_LENGTH 1024 -+#define PM_SOFT_DIRTY_PAGE (1ull << 57) -+ -+static void reset_write_watches( void *base, SIZE_T size ); -+ - static struct file_view *view_block_start, *view_block_end, *next_free_view; - static const size_t view_block_size = 0x100000; - static void *preload_reserve_start; -@@ -1138,7 +1138,7 @@ static int get_unix_prot( BYTE vprot ) - /* FIXME: Architecture needs implementation of signal_init_early. */ - if (vprot & VPROT_WRITECOPY) prot |= PROT_WRITE | PROT_READ; - #endif -- if (vprot & VPROT_WRITEWATCH) prot &= ~PROT_WRITE; -+ if (vprot & VPROT_WRITEWATCH && !use_kernel_writewatch) prot &= ~PROT_WRITE; - } - if (!prot) prot = PROT_NONE; - return prot; -@@ -1591,6 +1598,10 @@ static NTSTATUS create_view( struct file_view **view_ret, void *base, size_t siz - TRACE( "forcing exec permission on %p-%p\n", base, (char *)base + size - 1 ); - mprotect( base, size, unix_prot | PROT_EXEC ); - } -+ -+ if (vprot & VPROT_WRITEWATCH && use_kernel_writewatch) -+ reset_write_watches( view->base, view->size ); -+ - return STATUS_SUCCESS; - } - -@@ -1714,7 +1725,7 @@ static BOOL set_vprot( struct file_view *view, void *base, size_t size, BYTE vpr - { - int unix_prot = get_unix_prot(vprot); - -- if (view->protect & VPROT_WRITEWATCH) -+ if (!use_kernel_writewatch && view->protect & VPROT_WRITEWATCH) - { - /* each page may need different protections depending on write watch flag */ - set_page_vprot_bits( base, size, vprot & ~VPROT_WRITEWATCH, ~vprot & ~VPROT_WRITEWATCH ); -@@ -1773,8 +1784,24 @@ static void update_write_watches( void *base, size_t size, size_t accessed_size - */ - static void reset_write_watches( void *base, SIZE_T size ) - { -- set_page_vprot_bits( base, size, VPROT_WRITEWATCH, 0 ); -- mprotect_range( base, size, 0, 0 ); -+ if (use_kernel_writewatch) -+ { -+ char buffer[17]; -+ ssize_t ret; -+ -+ memset(buffer, 0, sizeof(buffer)); -+ buffer[0] = '6'; -+ *(void **)&buffer[1] = base; -+ *(void **)&buffer[1 + 8] = (char *)base + size; -+ -+ if ((ret = write(clear_refs_fd, buffer, sizeof(buffer))) != sizeof(buffer)) -+ ERR("Could not clear soft dirty bits, ret %zd, error %s.\n", ret, strerror(errno)); -+ } -+ else -+ { -+ set_page_vprot_bits( base, size, VPROT_WRITEWATCH, 0 ); -+ mprotect_range( base, size, 0, 0 ); -+ } - } - - -@@ -2660,12 +2687,31 @@ void virtual_init(void) - size_t size; - int i; - pthread_mutexattr_t attr; -+ const char *env_var; - - pthread_mutexattr_init( &attr ); - pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); - pthread_mutex_init( &virtual_mutex, &attr ); - pthread_mutexattr_destroy( &attr ); - -+ if (!((env_var = getenv("WINE_DISABLE_KERNEL_WRITEWATCH")) && atoi(env_var)) -+ && (pagemap_reset_fd = open("/proc/self/pagemap_reset", O_RDONLY)) != -1) -+ { -+ use_kernel_writewatch = TRUE; -+ if ((pagemap_fd = open("/proc/self/pagemap", O_RDONLY)) == -1) -+ { -+ ERR("Could not open pagemap file, error %s.\n", strerror(errno)); -+ exit(-1); -+ } -+ if ((clear_refs_fd = open("/proc/self/clear_refs", O_WRONLY)) == -1) -+ { -+ ERR("Could not open clear_refs file, error %s.\n", strerror(errno)); -+ exit(-1); -+ } -+ if (ERR_ON(virtual)) -+ MESSAGE("wine: using kernel write watches (experimental).\n"); -+ } -+ - if (preload_info && *preload_info) - for (i = 0; (*preload_info)[i].size; i++) - mmap_add_reserved_area( (*preload_info)[i].addr, (*preload_info)[i].size ); -@@ -3283,7 +3329,7 @@ NTSTATUS virtual_handle_fault( void *addr, DWORD err, void *stack ) - } - else ret = grow_thread_stack( page, &stack_info ); - } -- else if (err & EXCEPTION_WRITE_FAULT) -+ else if (!use_kernel_writewatch && err & EXCEPTION_WRITE_FAULT) - { - if (vprot & VPROT_WRITEWATCH) - { -@@ -3650,7 +3650,7 @@ static NTSTATUS check_write_access( void *base, size_t size, BOOL *has_write_wat - for (i = 0; i < size; i += page_size) - { - BYTE vprot = get_page_vprot( addr + i ); -- if (vprot & VPROT_WRITEWATCH) *has_write_watch = TRUE; -+ if (!use_kernel_writewatch && vprot & VPROT_WRITEWATCH) *has_write_watch = TRUE; - if (vprot & VPROT_WRITECOPY) - { - vprot = (vprot & ~VPROT_WRITECOPY) | VPROT_WRITE; -@@ -3659,7 +3659,7 @@ static NTSTATUS check_write_access( void *base, size_t size, BOOL *has_write_wat - if (!(get_unix_prot( vprot & ~VPROT_WRITEWATCH ) & PROT_WRITE)) - return STATUS_INVALID_USER_BUFFER; - } -- if (*has_write_watch) -+ if (!use_kernel_writewatch && *has_write_watch) - mprotect_range( addr, size, VPROT_WRITE, VPROT_WRITEWATCH | VPROT_WRITECOPY ); /* temporarily enable write access */ - return STATUS_SUCCESS; - } -@@ -4793,17 +4839,90 @@ NTSTATUS WINAPI NtGetWriteWatch( HANDLE process, ULONG flags, PVOID base, SIZE_T - char *addr = base; - char *end = addr + size; - -- while (pos < *count && addr < end) -+ if (use_kernel_writewatch) -+ { -+ static UINT64 buffer[PAGE_FLAGS_BUFFER_LENGTH]; -+ unsigned int i, length; -+ ssize_t read_length; -+ -+ if (flags & WRITE_WATCH_FLAG_RESET) -+ { -+ if (is_win64) -+ { -+ addresses[0] = end; -+ if ((read_length = pread(pagemap_reset_fd, addresses, *count * sizeof(*addresses), -+ ((ULONG_PTR)addr >> page_shift) * sizeof(*addresses))) == -1) -+ { -+ ERR("Error reading page flags, read_length %zd, error %s.\n", read_length, strerror(errno)); -+ status = STATUS_INVALID_ADDRESS; -+ goto done; -+ } -+ *count = read_length / sizeof(*addresses); -+ *granularity = page_size; -+ goto done; -+ } -+ -+ while (pos < *count && addr < end) -+ { -+ length = min(PAGE_FLAGS_BUFFER_LENGTH, *count - pos); -+ -+ buffer[0] = (ULONG_PTR)end; -+ if ((read_length = pread(pagemap_reset_fd, buffer, length * sizeof(*buffer), -+ ((ULONG_PTR)addr >> page_shift) * sizeof(*buffer))) == -1) -+ { -+ ERR("Error reading page flags, read_length %zd, error %s.\n", read_length, strerror(errno)); -+ status = STATUS_INVALID_ADDRESS; -+ goto done; -+ } -+ read_length /= sizeof(*buffer); -+ for (i = 0; i < read_length; ++i) -+ { -+ assert(pos < *count); -+ addresses[pos++] = (void *)(ULONG_PTR)buffer[i]; -+ } -+ if (read_length < length) -+ break; -+ addr = (char *)(ULONG_PTR)buffer[read_length - 1] + page_size; -+ } -+ } -+ else -+ { -+ while (pos < *count && addr < end) -+ { -+ length = min(PAGE_FLAGS_BUFFER_LENGTH, (end - addr) >> page_shift); -+ -+ if ((read_length = pread(pagemap_fd, buffer, length * sizeof(*buffer), -+ ((ULONG_PTR)addr >> page_shift) * sizeof(*buffer))) != length * sizeof(*buffer)) -+ { -+ ERR("Error reading page flags, read_length %zd, error %s.\n", read_length, strerror(errno)); -+ status = STATUS_INVALID_ADDRESS; -+ goto done; -+ } -+ for (i = 0; i < length && pos < *count; ++i) -+ { -+ if (buffer[i] & PM_SOFT_DIRTY_PAGE) -+ addresses[pos++] = addr; -+ -+ addr += page_size; -+ } -+ } -+ } -+ } -+ else - { -- if (!(get_page_vprot( addr ) & VPROT_WRITEWATCH)) addresses[pos++] = addr; -- addr += page_size; -+ while (pos < *count && addr < end) -+ { -+ if (!(get_page_vprot( addr ) & VPROT_WRITEWATCH)) addresses[pos++] = addr; -+ addr += page_size; -+ } -+ if (flags & WRITE_WATCH_FLAG_RESET) reset_write_watches( base, addr - (char *)base ); - } -- if (flags & WRITE_WATCH_FLAG_RESET) reset_write_watches( base, addr - (char *)base ); - *count = pos; - *granularity = page_size; - } - else status = STATUS_INVALID_PARAMETER; - -+done: - server_leave_uninterrupted_section( &virtual_mutex, &sigset ); - return status; - } -From cd792ea3219c7fb5d29a9e3f1b0344de2f93017b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Tue, 30 Nov 2021 16:32:34 +0300 -Subject: [PATCH] ntdll: Implement opening files through nt device paths. - -CW-Bug-Id: #19697 - -For Eternal Return. ---- - dlls/ntdll/unix/file.c | 138 ++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 136 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 3795eb1dd0d..58bee431168 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -3345,7 +3345,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char - - - /****************************************************************************** -- * nt_to_unix_file_name -+ * nt_to_unix_file_name_internal - * - * Convert a file name from NT namespace to Unix namespace. - * -@@ -3353,7 +3353,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char - * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is - * returned, but the unix name is still filled in properly. - */ --NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition ) -+NTSTATUS nt_to_unix_file_name_internal( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition ) - { - enum server_fd_type type; - int old_cwd, root_fd, needs_close; -@@ -3414,6 +3414,140 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U - } - - -+/* read the contents of an NT symlink object */ -+static NTSTATUS read_nt_symlink( HANDLE root, UNICODE_STRING *name, WCHAR *target, size_t length ) -+{ -+ OBJECT_ATTRIBUTES attr; -+ UNICODE_STRING targetW; -+ NTSTATUS status; -+ HANDLE handle; -+ -+ attr.Length = sizeof(attr); -+ attr.RootDirectory = root; -+ attr.Attributes = OBJ_CASE_INSENSITIVE; -+ attr.ObjectName = name; -+ attr.SecurityDescriptor = NULL; -+ attr.SecurityQualityOfService = NULL; -+ -+ if (!(status = NtOpenSymbolicLinkObject( &handle, SYMBOLIC_LINK_QUERY, &attr ))) -+ { -+ targetW.Buffer = target; -+ targetW.MaximumLength = (length - 1) * sizeof(WCHAR); -+ status = NtQuerySymbolicLinkObject( handle, &targetW, NULL ); -+ NtClose( handle ); -+ } -+ -+ return status; -+} -+ -+/* try to find dos device based on nt device name */ -+static NTSTATUS nt_to_dos_device( WCHAR *name, size_t length, WCHAR *device_ret ) -+{ -+ static const WCHAR dosdevicesW[] = {'\\','D','o','s','D','e','v','i','c','e','s',0}; -+ UNICODE_STRING dosdevW = { sizeof(dosdevicesW) - sizeof(WCHAR), sizeof(dosdevicesW), (WCHAR *)dosdevicesW }; -+ WCHAR symlinkW[MAX_DIR_ENTRY_LEN]; -+ OBJECT_ATTRIBUTES attr; -+ NTSTATUS status; -+ char data[1024]; -+ HANDLE handle; -+ ULONG ctx = 0; -+ -+ DIRECTORY_BASIC_INFORMATION *info = (DIRECTORY_BASIC_INFORMATION *)data; -+ -+ attr.Length = sizeof(attr); -+ attr.RootDirectory = 0; -+ attr.ObjectName = &dosdevW; -+ attr.Attributes = OBJ_CASE_INSENSITIVE; -+ attr.SecurityDescriptor = NULL; -+ attr.SecurityQualityOfService = NULL; -+ -+ status = NtOpenDirectoryObject( &handle, FILE_LIST_DIRECTORY, &attr ); -+ if (status) return STATUS_BAD_DEVICE_TYPE; -+ -+ while (!NtQueryDirectoryObject( handle, info, sizeof(data), TRUE, FALSE, &ctx, NULL )) -+ { -+ if (read_nt_symlink( handle, &info->ObjectName, symlinkW, MAX_DIR_ENTRY_LEN )) continue; -+ if (wcsnicmp( symlinkW, name, length )) continue; -+ if (info->ObjectName.Length != 2 * sizeof(WCHAR) || info->ObjectName.Buffer[1] != ':') continue; -+ -+ *device_ret = info->ObjectName.Buffer[0]; -+ NtClose( handle ); -+ return STATUS_SUCCESS; -+ } -+ -+ NtClose( handle ); -+ return STATUS_BAD_DEVICE_TYPE; -+} -+ -+/****************************************************************************** -+ * nt_to_unix_file_name -+ * -+ * Convert a file name from NT namespace to Unix namespace. -+ * -+ * If disposition is not FILE_OPEN or FILE_OVERWRITE, the last path -+ * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is -+ * returned, but the unix name is still filled in properly. -+ */ -+ -+/*( const UNICODE_STRING *nameW, char **unix_name_ret, -+ UNICODE_STRING *nt_name, UINT disposition ) -+*/ -+ -+NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition ) -+{ -+ static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0}; -+ static const WCHAR dosprefixW[] = {'\\','?','?','\\'}; -+ static const WCHAR deviceW[] = {'\\','D','e','v','i','c','e','\\',0}; -+ WCHAR *name, *ptr, *prefix, buffer[3] = {'c',':',0}; -+ UNICODE_STRING dospathW, *nameW; -+ OBJECT_ATTRIBUTES attr_copy; -+ size_t offset, name_len; -+ NTSTATUS status; -+ -+ if (attr->RootDirectory) return nt_to_unix_file_name_internal( attr, name_ret, disposition ); -+ -+ nameW = attr->ObjectName; -+ -+ if (nameW->Length >= sizeof(deviceW) - sizeof(WCHAR) -+ && !wcsnicmp( nameW->Buffer, deviceW, ARRAY_SIZE(deviceW) - 1 )) -+ { -+ offset = sizeof(deviceW) / sizeof(WCHAR); -+ while (offset * sizeof(WCHAR) < nameW->Length && nameW->Buffer[ offset ] != '\\') offset++; -+ if ((status = nt_to_dos_device( nameW->Buffer, offset, buffer ))) return status; -+ prefix = buffer; -+ } -+ else if (nameW->Length >= sizeof(systemrootW) - sizeof(WCHAR) && -+ !wcsnicmp( nameW->Buffer, systemrootW, ARRAY_SIZE(systemrootW) - 1 )) -+ { -+ offset = (sizeof(systemrootW) - 1) / sizeof(WCHAR); -+ prefix = user_shared_data->NtSystemRoot; -+ } -+ else -+ return nt_to_unix_file_name_internal( attr, name_ret, disposition ); -+ -+ name_len = sizeof(dosprefixW) + wcslen(prefix) * sizeof(WCHAR) + -+ nameW->Length - offset * sizeof(WCHAR) + sizeof(WCHAR); -+ if (!(name = malloc( name_len ))) -+ return STATUS_NO_MEMORY; -+ -+ ptr = name; -+ memcpy( ptr, dosprefixW, sizeof(dosprefixW) ); -+ ptr += sizeof(dosprefixW) / sizeof(WCHAR); -+ wcscpy( ptr, prefix ); -+ ptr += wcslen(ptr); -+ memcpy( ptr, nameW->Buffer + offset, nameW->Length - offset * sizeof(WCHAR) ); -+ ptr[ nameW->Length / sizeof(WCHAR) - offset ] = 0; -+ -+ dospathW.Buffer = name; -+ dospathW.Length = wcslen( name ) * sizeof(WCHAR); -+ attr_copy = *attr; -+ attr_copy.ObjectName = &dospathW; -+ status = nt_to_unix_file_name_internal( &attr_copy, name_ret, disposition ); -+ -+ free( name ); -+ return status; -+} -+ - /****************************************************************************** - * wine_nt_to_unix_file_name - * -From 026d6a997e628295b0e860601dfc0863ae439f8a Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 7 Dec 2021 11:16:40 +0300 -Subject: [PATCH] server: Split waitable object off completion port. - -CW-Bug-Id: #19621 ---- - server/completion.c | 120 +++++++++++++++++++++++++++++++++++--------- - 1 file changed, 96 insertions(+), 24 deletions(-) - -diff --git a/server/completion.c b/server/completion.c -index 33266c596da..915a083e642 100644 ---- a/server/completion.c -+++ b/server/completion.c -@@ -56,15 +56,52 @@ struct type_descr completion_type = - }, - }; - --struct completion -+struct completion_wait - { - struct object obj; - struct list queue; - unsigned int depth; - }; - -+struct completion -+{ -+ struct object obj; -+ struct completion_wait *wait; -+}; -+ -+static void completion_wait_dump( struct object*, int ); -+static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static void completion_wait_destroy( struct object * ); -+ -+static const struct object_ops completion_wait_ops = -+{ -+ sizeof(struct completion_wait), /* size */ -+ &no_type, /* type */ -+ completion_wait_dump, /* dump */ -+ add_queue, /* add_queue */ -+ remove_queue, /* remove_queue */ -+ completion_wait_signaled, /* signaled */ -+ NULL, /* get_esync_fd */ -+ NULL, /* get_fsync_idx */ -+ no_satisfied, /* satisfied */ -+ no_signal, /* signal */ -+ no_get_fd, /* get_fd */ -+ default_map_access, /* map_access */ -+ default_get_sd, /* get_sd */ -+ default_set_sd, /* set_sd */ -+ no_get_full_name, /* get_full_name */ -+ no_lookup_name, /* lookup_name */ -+ no_link_name, /* link_name */ -+ NULL, /* unlink_name */ -+ no_open_file, /* open_file */ -+ no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_close_handle, /* close_handle */ -+ completion_wait_destroy /* destroy */ -+}; -+ - static void completion_dump( struct object*, int ); --static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static int completion_add_queue( struct object *obj, struct wait_queue_entry *entry ); -+static void completion_remove_queue( struct object *obj, struct wait_queue_entry *entry ); - static void completion_destroy( struct object * ); - - static const struct object_ops completion_ops = -@@ -72,9 +109,9 @@ static const struct object_ops completion_ops = - sizeof(struct completion), /* size */ - &completion_type, /* type */ - completion_dump, /* dump */ -- add_queue, /* add_queue */ -- remove_queue, /* remove_queue */ -- completion_signaled, /* signaled */ -+ completion_add_queue, /* add_queue */ -+ completion_remove_queue, /* remove_queue */ -+ NULL, /* signaled */ - NULL, /* get_esync_fd */ - NULL, /* get_fsync_idx */ - no_satisfied, /* satisfied */ -@@ -102,30 +139,63 @@ struct comp_msg - unsigned int status; - }; - --static void completion_destroy( struct object *obj) -+static void completion_wait_destroy( struct object *obj) - { -- struct completion *completion = (struct completion *) obj; -+ struct completion_wait *wait = (struct completion_wait *)obj; - struct comp_msg *tmp, *next; - -- LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &completion->queue, struct comp_msg, queue_entry ) -+ LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &wait->queue, struct comp_msg, queue_entry ) - { - free( tmp ); - } - } - -+static void completion_wait_dump( struct object *obj, int verbose ) -+{ -+ struct completion_wait *wait = (struct completion_wait *)obj; -+ -+ assert( obj->ops == &completion_wait_ops ); -+ fprintf( stderr, "Completion depth=%u\n", wait->depth ); -+} -+ -+static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ) -+{ -+ struct completion_wait *wait = (struct completion_wait *)obj; -+ -+ assert( obj->ops == &completion_wait_ops ); -+ return !list_empty( &wait->queue ); -+} -+ - static void completion_dump( struct object *obj, int verbose ) - { -- struct completion *completion = (struct completion *) obj; -+ struct completion *completion = (struct completion *)obj; -+ -+ assert( obj->ops == &completion_ops ); -+ completion->wait->obj.ops->dump( &completion->wait->obj, verbose ); -+} -+ -+static int completion_add_queue( struct object *obj, struct wait_queue_entry *entry ) -+{ -+ struct completion *completion = (struct completion *)obj; -+ -+ assert( obj->ops == &completion_ops ); -+ return completion->wait->obj.ops->add_queue( &completion->wait->obj, entry ); -+} -+ -+static void completion_remove_queue( struct object *obj, struct wait_queue_entry *entry ) -+{ -+ struct completion *completion = (struct completion *)obj; - - assert( obj->ops == &completion_ops ); -- fprintf( stderr, "Completion depth=%u\n", completion->depth ); -+ completion->wait->obj.ops->remove_queue( &completion->wait->obj, entry ); - } - --static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ) -+static void completion_destroy( struct object *obj ) - { - struct completion *completion = (struct completion *)obj; - -- return !list_empty( &completion->queue ); -+ assert( obj->ops == &completion_ops ); -+ release_object( &completion->wait->obj ); - } - - static struct completion *create_completion( struct object *root, const struct unicode_str *name, -@@ -134,15 +204,17 @@ static struct completion *create_completion( struct object *root, const struct u - { - struct completion *completion; - -- if ((completion = create_named_object( root, &completion_ops, name, attr, sd ))) -+ if (!(completion = create_named_object( root, &completion_ops, name, attr, sd ))) return NULL; -+ if (get_error() == STATUS_OBJECT_NAME_EXISTS) return completion; -+ if (!(completion->wait = alloc_object( &completion_wait_ops ))) - { -- if (get_error() != STATUS_OBJECT_NAME_EXISTS) -- { -- list_init( &completion->queue ); -- completion->depth = 0; -- } -+ release_object( completion ); -+ set_error( STATUS_NO_MEMORY ); -+ return NULL; - } - -+ list_init( &completion->wait->queue ); -+ completion->wait->depth = 0; - return completion; - } - -@@ -164,9 +236,9 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ - msg->status = status; - msg->information = information; - -- list_add_tail( &completion->queue, &msg->queue_entry ); -- completion->depth++; -- wake_up( &completion->obj, 1 ); -+ list_add_tail( &completion->wait->queue, &msg->queue_entry ); -+ completion->wait->depth++; -+ wake_up( &completion->wait->obj, 1 ); - } - - /* create a completion */ -@@ -220,13 +292,13 @@ DECL_HANDLER(remove_completion) - - if (!completion) return; - -- entry = list_head( &completion->queue ); -+ entry = list_head( &completion->wait->queue ); - if (!entry) - set_error( STATUS_PENDING ); - else - { - list_remove( entry ); -- completion->depth--; -+ completion->wait->depth--; - msg = LIST_ENTRY( entry, struct comp_msg, queue_entry ); - reply->ckey = msg->ckey; - reply->cvalue = msg->cvalue; -@@ -245,7 +317,7 @@ DECL_HANDLER(query_completion) - - if (!completion) return; - -- reply->depth = completion->depth; -+ reply->depth = completion->wait->depth; - - release_object( completion ); - } -From 17fd5adb927ccded85add314da85330f1a1dd007 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 7 Dec 2021 12:27:17 +0300 -Subject: [PATCH] server: Abandon wait when completion port is closed. - -CW-Bug-Id: #19621 - -Based on patches by Alexey Prokhin. ---- - dlls/ntdll/tests/sync.c | 65 +++++++++++++++++++++++++++++++++++++++++ - server/completion.c | 25 ++++++++++++---- - 2 files changed, 85 insertions(+), 5 deletions(-) - -diff --git a/dlls/ntdll/tests/sync.c b/dlls/ntdll/tests/sync.c -index f930767a8b0..562df0f66b0 100644 ---- a/dlls/ntdll/tests/sync.c -+++ b/dlls/ntdll/tests/sync.c -@@ -837,6 +837,70 @@ static void test_tid_alert( char **argv ) - CloseHandle( pi.hThread ); - } - -+static HANDLE test_close_io_completion_port_ready, test_close_io_completion_test_ready; -+static HANDLE test_close_io_completion_port; -+ -+static DWORD WINAPI test_close_io_completion_thread(void *param) -+{ -+ FILE_IO_COMPLETION_INFORMATION info; -+ IO_STATUS_BLOCK iosb; -+ ULONG_PTR key, value; -+ NTSTATUS status; -+ ULONG count; -+ DWORD ret; -+ -+ ret = WaitForSingleObject( test_close_io_completion_port_ready, INFINITE ); -+ ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); -+ SetEvent( test_close_io_completion_test_ready ); -+ status = NtRemoveIoCompletion( test_close_io_completion_port, &key, &value, &iosb, NULL ); -+ if (status == STATUS_INVALID_HANDLE) -+ skip( "Handle closed before wait started.\n" ); -+ else -+ ok( status == STATUS_ABANDONED_WAIT_0, "Got unexpected status %#x.\n", status ); -+ -+ ret = WaitForSingleObject( test_close_io_completion_port_ready, INFINITE ); -+ ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); -+ SetEvent( test_close_io_completion_test_ready ); -+ count = 0xdeadbeef; -+ status = NtRemoveIoCompletionEx( test_close_io_completion_port, &info, 1, &count, NULL, FALSE ); -+ ok( count == 1, "Got unexpected count %u.\n", count ); -+ if (status == STATUS_INVALID_HANDLE) -+ skip( "Handle closed before wait started.\n" ); -+ else -+ ok( status == STATUS_ABANDONED_WAIT_0, "Got unexpected status %#x.\n", status ); -+ -+ return 0; -+} -+ -+static void test_close_io_completion(void) -+{ -+ NTSTATUS status; -+ unsigned int i; -+ HANDLE thread; -+ DWORD ret; -+ -+ test_close_io_completion_port_ready = CreateEventA(NULL, FALSE, FALSE, NULL); -+ test_close_io_completion_test_ready = CreateEventA(NULL, FALSE, FALSE, NULL); -+ -+ thread = CreateThread( NULL, 0, test_close_io_completion_thread, NULL, 0, NULL ); -+ ok( !!thread, "Failed to create thread, error %u.\n", GetLastError() ); -+ -+ for (i = 0; i < 2; ++i) -+ { -+ status = NtCreateIoCompletion( &test_close_io_completion_port, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); -+ ok( !status, "Got unexpected status %#x.\n", status ); -+ ret = SignalObjectAndWait( test_close_io_completion_port_ready, test_close_io_completion_test_ready, -+ INFINITE, FALSE ); -+ ok( ret == WAIT_OBJECT_0, "Got unexpected ret %#x.\n", ret ); -+ Sleep(10); -+ status = pNtClose( test_close_io_completion_port ); -+ ok( !status, "Got unexpected status %#x.\n", status ); -+ } -+ -+ WaitForSingleObject( thread, INFINITE ); -+ CloseHandle( thread ); -+} -+ - START_TEST(sync) - { - HMODULE module = GetModuleHandleA("ntdll.dll"); -@@ -884,4 +948,5 @@ START_TEST(sync) - test_keyed_events(); - test_resource(); - test_tid_alert( argv ); -+ test_close_io_completion(); - } -diff --git a/server/completion.c b/server/completion.c -index 915a083e642..1d70897db83 100644 ---- a/server/completion.c -+++ b/server/completion.c -@@ -56,11 +56,14 @@ struct type_descr completion_type = - }, - }; - -+struct completion; -+ - struct completion_wait - { -- struct object obj; -- struct list queue; -- unsigned int depth; -+ struct object obj; -+ struct completion *completion; -+ struct list queue; -+ unsigned int depth; - }; - - struct completion -@@ -71,6 +74,7 @@ struct completion - - static void completion_wait_dump( struct object*, int ); - static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ); - static void completion_wait_destroy( struct object * ); - - static const struct object_ops completion_wait_ops = -@@ -83,7 +87,7 @@ static const struct object_ops completion_wait_ops = - completion_wait_signaled, /* signaled */ - NULL, /* get_esync_fd */ - NULL, /* get_fsync_idx */ -- no_satisfied, /* satisfied */ -+ completion_wait_satisfied, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ - default_map_access, /* map_access */ -@@ -163,7 +167,15 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry - struct completion_wait *wait = (struct completion_wait *)obj; - - assert( obj->ops == &completion_wait_ops ); -- return !list_empty( &wait->queue ); -+ return !wait->completion || !list_empty( &wait->queue ); -+} -+ -+static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ) -+{ -+ struct completion_wait *wait = (struct completion_wait *)obj; -+ -+ assert( obj->ops == &completion_wait_ops ); -+ if (!wait->completion) make_wait_abandoned( entry ); - } - - static void completion_dump( struct object *obj, int verbose ) -@@ -195,6 +207,8 @@ static void completion_destroy( struct object *obj ) - struct completion *completion = (struct completion *)obj; - - assert( obj->ops == &completion_ops ); -+ completion->wait->completion = NULL; -+ wake_up( &completion->wait->obj, 0 ); - release_object( &completion->wait->obj ); - } - -@@ -213,6 +227,7 @@ static struct completion *create_completion( struct object *root, const struct u - return NULL; - } - -+ completion->wait->completion = completion; - list_init( &completion->wait->queue ); - completion->wait->depth = 0; - return completion; -From a4f3fe1348f746376efd595ddc353a976ed650c4 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 7 Dec 2021 13:33:01 +0300 -Subject: [PATCH] server: Ensure completion port wait object exists after - successful wait. - -CW-Bug-Id: #19621 - -Based on the problem analysis by Andrew Eikum. ---- - dlls/ntdll/unix/sync.c | 6 ++++++ - server/completion.c | 36 ++++++++++++++++++++++++++++++------ - server/protocol.def | 1 + - server/thread.c | 2 ++ - server/thread.h | 1 + - 5 files changed, 40 insertions(+), 6 deletions(-) - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 8bd38f09e44..af0c53d441e 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -1939,6 +1939,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * - IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout ) - { - NTSTATUS status; -+ int waited = 0; - - TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout ); - -@@ -1947,6 +1948,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * - SERVER_START_REQ( remove_completion ) - { - req->handle = wine_server_obj_handle( handle ); -+ req->waited = waited; - if (!(status = wine_server_call( req ))) - { - *key = reply->ckey; -@@ -1959,6 +1961,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * - if (status != STATUS_PENDING) return status; - status = NtWaitForSingleObject( handle, FALSE, timeout ); - if (status != WAIT_OBJECT_0) return status; -+ waited = 1; - } - } - -@@ -1970,6 +1973,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM - ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable ) - { - NTSTATUS status; -+ int waited = 0; - ULONG i = 0; - - TRACE( "%p %p %u %p %p %u\n", handle, info, count, written, timeout, alertable ); -@@ -1981,6 +1985,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM - SERVER_START_REQ( remove_completion ) - { - req->handle = wine_server_obj_handle( handle ); -+ req->waited = waited; - if (!(status = wine_server_call( req ))) - { - info[i].CompletionKey = reply->ckey; -@@ -2000,6 +2005,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM - } - status = NtWaitForSingleObject( handle, alertable, timeout ); - if (status != WAIT_OBJECT_0) break; -+ waited = 1; - } - *written = i ? i : 1; - return status; -diff --git a/server/completion.c b/server/completion.c -index 1d70897db83..cbafe811796 100644 ---- a/server/completion.c -+++ b/server/completion.c -@@ -173,9 +173,16 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry - static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ) - { - struct completion_wait *wait = (struct completion_wait *)obj; -+ struct thread *thread; - - assert( obj->ops == &completion_wait_ops ); -- if (!wait->completion) make_wait_abandoned( entry ); -+ if (wait->completion) -+ { -+ thread = get_wait_queue_thread( entry ); -+ if (thread->locked_completion) release_object( thread->locked_completion ); -+ thread->locked_completion = grab_object( obj ); -+ } -+ else make_wait_abandoned( entry ); - } - - static void completion_dump( struct object *obj, int verbose ) -@@ -301,19 +308,36 @@ DECL_HANDLER(add_completion) - /* get completion from completion port */ - DECL_HANDLER(remove_completion) - { -- struct completion* completion = get_completion_obj( current->process, req->handle, IO_COMPLETION_MODIFY_STATE ); -+ struct completion* completion; -+ struct completion_wait *wait; - struct list *entry; - struct comp_msg *msg; - -- if (!completion) return; -+ if (req->waited && (wait = (struct completion_wait *)current->locked_completion)) -+ current->locked_completion = NULL; -+ else -+ { -+ if (current->locked_completion) -+ { -+ release_object( current->locked_completion ); -+ current->locked_completion = NULL; -+ } -+ completion = get_completion_obj( current->process, req->handle, IO_COMPLETION_MODIFY_STATE ); -+ if (!completion) return; -+ -+ wait = (struct completion_wait *)grab_object( completion->wait ); -+ release_object( completion ); -+ } - -- entry = list_head( &completion->wait->queue ); -+ assert( wait->obj.ops == &completion_wait_ops ); -+ -+ entry = list_head( &wait->queue ); - if (!entry) - set_error( STATUS_PENDING ); - else - { - list_remove( entry ); -- completion->wait->depth--; -+ wait->depth--; - msg = LIST_ENTRY( entry, struct comp_msg, queue_entry ); - reply->ckey = msg->ckey; - reply->cvalue = msg->cvalue; -@@ -322,7 +346,7 @@ DECL_HANDLER(remove_completion) - free( msg ); - } - -- release_object( completion ); -+ release_object( wait ); - } - - /* get queue depth for completion port */ -diff --git a/server/protocol.def b/server/protocol.def -index 586122a9928..b25a3ee2fd6 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -3479,6 +3479,7 @@ struct handle_info - /* get completion from completion port queue */ - @REQ(remove_completion) - obj_handle_t handle; /* port handle */ -+ int waited; /* port was just successfully waited on */ - @REPLY - apc_param_t ckey; /* completion key */ - apc_param_t cvalue; /* completion value */ -diff --git a/server/thread.c b/server/thread.c -index 6300fda0396..c7cfb1cdded 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -295,6 +295,7 @@ static inline void init_thread_structure( struct thread *thread ) - - thread->creation_time = current_time; - thread->exit_time = 0; -+ thread->locked_completion = NULL; - - list_init( &thread->mutex_list ); - list_init( &thread->system_apc ); -@@ -512,6 +513,7 @@ static void destroy_thread( struct object *obj ) - release_object( thread->process ); - if (thread->id) free_ptid( thread->id ); - if (thread->token) release_object( thread->token ); -+ if (thread->locked_completion) release_object( thread->locked_completion ); - - if (do_esync()) - close( thread->esync_fd ); -diff --git a/server/thread.h b/server/thread.h -index d9c782e7bee..824c4090182 100644 ---- a/server/thread.h -+++ b/server/thread.h -@@ -95,6 +95,7 @@ struct thread - data_size_t desc_len; /* thread description length in bytes */ - WCHAR *desc; /* thread description string */ - struct timeout_user *exit_poll; /* poll if the thread/process has exited already */ -+ struct object *locked_completion; /* completion port wait object successfully waited by the thread */ - }; - - extern struct thread *current; -From 74c1b244095cad0efbb48a65049ab638daad4093 Mon Sep 17 00:00:00 2001 -From: Alexey Prokhin -Date: Thu, 23 Apr 2020 12:29:55 +0300 -Subject: [PATCH] kernelbase: Set the proper error code in - GetQueuedCompletionStatus{Ex} when the handle is closed. - -Planet Zoo relies on it being ERROR_ABANDONED_WAIT_0. ---- - dlls/kernelbase/sync.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c -index 1ae72c770eb..c6e4150749e 100644 ---- a/dlls/kernelbase/sync.c -+++ b/dlls/kernelbase/sync.c -@@ -1067,6 +1067,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatus( HANDLE port, LPDWORD co - } - - if (status == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); -+ else if (status == ERROR_WAIT_NO_CHILDREN) SetLastError( ERROR_ABANDONED_WAIT_0 ); - else SetLastError( RtlNtStatusToDosError(status) ); - return FALSE; - } -@@ -1088,6 +1089,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatusEx( HANDLE port, OVERLAPP - if (ret == STATUS_SUCCESS) return TRUE; - else if (ret == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); - else if (ret == STATUS_USER_APC) SetLastError( WAIT_IO_COMPLETION ); -+ else if (ret == ERROR_WAIT_NO_CHILDREN) SetLastError( ERROR_ABANDONED_WAIT_0 ); - else SetLastError( RtlNtStatusToDosError(ret) ); - return FALSE; - } -From e9565a4160533f5236e635849495d4203f6853b7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= -Date: Fri, 24 Apr 2020 14:37:58 +0300 -Subject: [PATCH] server: Try to retrieve the unix name on handles created from - file descriptors. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46070 -Signed-off-by: Gabriel Ivăncescu - -Fixes Unity of Command II, and possibly other games that use -Python38.dll. ---- - server/fd.c | 39 +++++++++++++++++++++++++++++++++++++++ - server/file.c | 1 + - server/file.h | 2 ++ - 3 files changed, 42 insertions(+) - -diff --git a/server/fd.c b/server/fd.c -index 7ee687f2dfc..0bd29c016d0 100644 ---- a/server/fd.c -+++ b/server/fd.c -@@ -2143,6 +2143,45 @@ struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, int unix_fd, s - return NULL; - } - -+void set_unix_name_of_fd( struct fd *fd, const struct stat *fd_st ) -+{ -+#ifdef __linux__ -+ static const char procfs_fmt[] = "/proc/self/fd/%d"; -+ -+ char path[PATH_MAX], procfs_path[sizeof(procfs_fmt) - 2 /* %d */ + 11]; -+ struct stat path_st; -+ ssize_t len; -+ -+ sprintf( procfs_path, procfs_fmt, fd->unix_fd ); -+ len = readlink( procfs_path, path, sizeof(path) ); -+ if (len == -1 || len >= sizeof(path) ) -+ return; -+ path[len] = '\0'; -+ -+ /* Make sure it's an absolute path, has at least one hardlink, and the same inode */ -+ if (path[0] != '/' || stat( path, &path_st ) || path_st.st_nlink < 1 || -+ path_st.st_dev != fd_st->st_dev || path_st.st_ino != fd_st->st_ino) -+ return; -+ -+ if (!(fd->unix_name = mem_alloc( len + 1 ))) -+ return; -+ memcpy( fd->unix_name, path, len + 1 ); -+ -+#elif defined(F_GETPATH) -+ char path[PATH_MAX]; -+ size_t size; -+ -+ if (fcntl( fd->unix_fd, F_GETPATH, path ) == -1 || path[0] != '/') -+ return; -+ -+ size = strlen(path) + 1; -+ if (!(fd->unix_name = mem_alloc( size ))) -+ return; -+ memcpy( fd->unix_name, path, size ); -+ -+#endif -+} -+ - /* retrieve the object that is using an fd */ - void *get_fd_user( struct fd *fd ) - { -diff --git a/server/file.c b/server/file.c -index c2b06e29717..dfc59e83034 100644 ---- a/server/file.c -+++ b/server/file.c -@@ -157,6 +157,7 @@ struct file *create_file_for_fd( int fd, unsigned int access, unsigned int shari - release_object( file ); - return NULL; - } -+ set_unix_name_of_fd( file->fd, &st ); - allow_fd_caching( file->fd ); - return file; - } -diff --git a/server/file.h b/server/file.h -index 38964d73c13..629862baf8d 100644 ---- a/server/file.h -+++ b/server/file.h -@@ -22,6 +22,7 @@ - #define __WINE_SERVER_FILE_H - - #include -+#include - - #include "object.h" - -@@ -85,6 +86,7 @@ extern struct fd *open_fd( struct fd *root, const char *name, struct unicode_str - unsigned int sharing, unsigned int options ); - extern struct fd *create_anonymous_fd( const struct fd_ops *fd_user_ops, - int unix_fd, struct object *user, unsigned int options ); -+extern void set_unix_name_of_fd( struct fd *fd, const struct stat *fd_st ); - extern struct fd *dup_fd_object( struct fd *orig, unsigned int access, unsigned int sharing, - unsigned int options ); - extern struct fd *get_fd_object_for_mapping( struct fd *fd, unsigned int access, unsigned int sharing ); -From e9ecb95ae4a0bde8d6e03776e556aa4c5fdf623b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 10 Sep 2021 09:46:52 +0200 -Subject: [PATCH] wine.inf: Force clobber pdffile shell open command. - -Cw-Bug-Id: #19035 ---- - loader/wine.inf.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index bbaade48799..a702100e248 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -319,7 +319,7 @@ HKCR,Msi.Patch,,2,"Windows Installer Patch" - HKCR,Msi.Patch\DefaultIcon,,2,"msiexec.exe" - HKCR,Msi.Patch\shell\Open\command,,2,"%11%\msiexec.exe /p ""%1""" - HKCR,pdffile,,2,"PDF Document" --HKCR,pdffile\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" -+HKCR,pdffile\shell\open\command,,,"""%11%\winebrowser.exe"" ""%1""" - HKCR,rtffile,,2,"Rich Text Document" - HKCR,rtffile\shell\open\command,,2,"""%16422%\Windows NT\Accessories\wordpad.exe"" ""%1""" - HKCR,rtffile\shell\print\command,,2,"""%16422%\Windows NT\Accessories\wordpad.exe"" /p ""%1""" -From b94e737d43384fdde0e332b6669d9074f04ef329 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Mon, 26 Jul 2021 17:36:04 +0300 -Subject: [PATCH] kernel32: Align stack pointer for lstrcpyA() on x64. - -For Blood of Steel crash on launch. - -CW-Bug-Id: #19148 ---- - dlls/kernel32/virtual.c | 40 +++++++++++++++++++++++++++++++++++++++- - 1 file changed, 39 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernel32/virtual.c b/dlls/kernel32/virtual.c -index f5693de4e28..800c25d34cd 100644 ---- a/dlls/kernel32/virtual.c -+++ b/dlls/kernel32/virtual.c -@@ -36,6 +36,7 @@ - #include "psapi.h" - #include "wine/exception.h" - #include "wine/debug.h" -+#include "wine/asm.h" - - #include "kernel_private.h" - -@@ -294,7 +295,8 @@ LPWSTR WINAPI lstrcatW( LPWSTR dst, LPCWSTR src ) - * lstrcpyA (KERNEL32.@) - * lstrcpy (KERNEL32.@) - */ --LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) -+#ifdef __x86_64__ -+LPSTR WINAPI lstrcpyA_impl( LPSTR dst, LPCSTR src ) - { - __TRY - { -@@ -310,6 +312,42 @@ LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) - return dst; - } - -+__ASM_GLOBAL_FUNC( lstrcpyA, -+ ".byte 0x48, 0x8d, 0xa4, 0x24, 0x00, 0x00, 0x00, 0x00\n\t" -+ "pushq %rbp\n\t" -+ __ASM_SEH(".seh_pushreg %rbp\n\t") -+ __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") -+ __ASM_CFI(".cfi_rel_offset %rbp,0\n\t") -+ "movq %rsp,%rbp\n\t" -+ __ASM_SEH(".seh_setframe %rbp,0\n\t") -+ __ASM_CFI(".cfi_def_cfa_register %rbp\n\t") -+ __ASM_SEH(".seh_endprologue\n\t") -+ "subq $0x20,%rsp\n\t" -+ "andq $~15,%rsp\n\t" -+ "call " __ASM_NAME("lstrcpyA_impl") "\n\t" -+ "leaq 0(%rbp),%rsp\n\t" -+ __ASM_CFI(".cfi_def_cfa_register %rsp\n\t") -+ "popq %rbp\n\t" -+ __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") -+ __ASM_CFI(".cfi_same_value %rbp\n\t") -+ "ret" ) -+#else /* __x86_64__ */ -+LPSTR WINAPI lstrcpyA( LPSTR dst, LPCSTR src ) -+{ -+ __TRY -+ { -+ /* this is how Windows does it */ -+ memmove( dst, src, strlen(src)+1 ); -+ } -+ __EXCEPT( badptr_handler ) -+ { -+ SetLastError( ERROR_INVALID_PARAMETER ); -+ return NULL; -+ } -+ __ENDTRY -+ return dst; -+} -+#endif - - /*********************************************************************** - * lstrcpyW (KERNEL32.@) -From 537afeeb629a14baa467de6c8ce0084a5727edf8 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 14 Jul 2021 20:45:38 +0300 -Subject: [PATCH] ntdll: Add stub implementation for - NtSetInformationFile(FileAllocationInformation). - -CW-Bug-Id: #19085 ---- - dlls/ntdll/unix/file.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 58bee431168..cf4eb431773 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -4558,6 +4558,15 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, - else status = STATUS_INVALID_PARAMETER_3; - break; - -+ case FileAllocationInformation: -+ { -+ const FILE_ALLOCATION_INFORMATION *info = ptr; -+ -+ FIXME("FileAllocationInformation AllocationSize %p stub.\n", (void *)(ULONG_PTR)info->AllocationSize.QuadPart); -+ io->u.Status = STATUS_SUCCESS; -+ break; -+ } -+ - case FilePipeInformation: - if (len >= sizeof(FILE_PIPE_INFORMATION)) - { -From c4872f67ec7b9ff5c68f2b82866a0b7f9cf46836 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 14 Jul 2021 20:43:39 +0300 -Subject: [PATCH] ntdll: Support '\??\GlobalRoot' prefix in - get_dos_prefix_len(). - -CW-Bug-Id: #19085 ---- - dlls/ntdll/unix/file.c | 29 ++++++++++++++++++++++------- - 1 file changed, 22 insertions(+), 7 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index cf4eb431773..3f60060bb38 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -2865,16 +2865,31 @@ static inline int get_dos_prefix_len( const UNICODE_STRING *name ) - { - static const WCHAR nt_prefixW[] = {'\\','?','?','\\'}; - static const WCHAR dosdev_prefixW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\'}; -+ static const WCHAR globalrootW[] = {'\\','?','?','\\','G','l','o','b','a','l','R','o','o','t'}; -+ int prefix_len = 0; -+ WCHAR *prefix; -+ USHORT length; - -- if (name->Length >= sizeof(nt_prefixW) && -- !memcmp( name->Buffer, nt_prefixW, sizeof(nt_prefixW) )) -- return ARRAY_SIZE( nt_prefixW ); -+ prefix = name->Buffer; -+ length = name->Length; - -- if (name->Length >= sizeof(dosdev_prefixW) && -- !wcsnicmp( name->Buffer, dosdev_prefixW, ARRAY_SIZE( dosdev_prefixW ))) -- return ARRAY_SIZE( dosdev_prefixW ); -+ if (length >= ARRAY_SIZE( globalrootW ) && -+ !wcsnicmp( prefix, globalrootW, ARRAY_SIZE( globalrootW ))) -+ { -+ WARN("Stripping off GlobalRoot prefix.\n"); -+ prefix += ARRAY_SIZE( globalrootW ); -+ prefix_len += ARRAY_SIZE( globalrootW ); -+ length -= ARRAY_SIZE( globalrootW ); -+ } -+ -+ if (length >= sizeof(nt_prefixW) && -+ !memcmp( prefix, nt_prefixW, sizeof(nt_prefixW) )) -+ prefix_len += ARRAY_SIZE( nt_prefixW ); -+ else if (length >= sizeof(dosdev_prefixW) && -+ !wcsnicmp( prefix, dosdev_prefixW, ARRAY_SIZE( dosdev_prefixW ))) -+ prefix_len += ARRAY_SIZE( dosdev_prefixW ); - -- return 0; -+ return prefix_len; - } - - - -From 48c1e8334c4fa200397acaa0637a008d589f763d Mon Sep 17 00:00:00 2001 -From: Jacek Caban -Date: Mon, 8 Mar 2021 16:41:19 +0100 -Subject: [PATCH] webservices: Prefer native. - ---- - dlls/webservices/Makefile.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/webservices/Makefile.in b/dlls/webservices/Makefile.in -index b58714d3253..c1a6b1438ea 100644 ---- a/dlls/webservices/Makefile.in -+++ b/dlls/webservices/Makefile.in -@@ -2,6 +2,8 @@ MODULE = webservices.dll - IMPORTLIB = webservices - IMPORTS = winhttp rpcrt4 user32 ws2_32 - -+EXTRADLLFLAGS = -Wb,--prefer-native -+ - C_SRCS = \ - channel.c \ - error.c \ -From 1e979a7c33ec3dbc05435255175bd44a9bcf235c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 16 Nov 2021 21:41:28 +0100 -Subject: [PATCH] HACK: mscoree: Build a dummy CameraQuakeViewer.dll for Nights - of Azure. - -The game references types from a non-existing DLL, and Mono cannot -be taught to handle it easily. This is an ugly hack to make sure the -load succeeds. - -CW-Bug-Id: #19046 ---- - dlls/mscoree/metahost.c | 62 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 62 insertions(+) - -diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c -index bf281557c4e..366c415090e 100644 ---- a/dlls/mscoree/metahost.c -+++ b/dlls/mscoree/metahost.c -@@ -1687,6 +1687,44 @@ static MonoAssembly* mono_assembly_try_load(WCHAR *path) - return result; - } - -+static BOOL compile_assembly(const char *source, const char *target, char *target_path, DWORD target_path_len) -+{ -+ static const char *csc = "C:\\windows\\Microsoft.NET\\Framework\\v2.0.50727\\csc.exe"; -+ char cmdline[2 * MAX_PATH + 74], tmp[MAX_PATH], tmpdir[MAX_PATH], source_path[MAX_PATH]; -+ STARTUPINFOA si = {.cb = sizeof(STARTUPINFOA)}; -+ PROCESS_INFORMATION pi; -+ HANDLE file; -+ DWORD size; -+ BOOL ret; -+ LUID id; -+ -+ if (!PathFileExistsA(csc)) return FALSE; -+ if (!AllocateLocallyUniqueId(&id)) return FALSE; -+ -+ GetTempPathA(MAX_PATH, tmp); -+ if (!GetTempFileNameA(tmp, "assembly", id.LowPart, tmpdir)) return FALSE; -+ if (!CreateDirectoryA(tmpdir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) return FALSE; -+ -+ snprintf(source_path, MAX_PATH, "%s\\source.cs", tmpdir); -+ snprintf(target_path, target_path_len, "%s\\%s", tmpdir, target); -+ -+ file = CreateFileA(source_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); -+ if (file == INVALID_HANDLE_VALUE) return FALSE; -+ ret = WriteFile(file, source, strlen(source), &size, NULL); -+ CloseHandle(file); -+ if (!ret) return FALSE; -+ -+ snprintf(cmdline, ARRAY_SIZE(cmdline), "%s /t:library /out:\"%s\" \"%s\"", csc, target_path, source_path); -+ ret = CreateProcessA(csc, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); -+ if (!ret) return FALSE; -+ -+ WaitForSingleObject(pi.hProcess, INFINITE); -+ CloseHandle(pi.hThread); -+ CloseHandle(pi.hProcess); -+ -+ return PathFileExistsA(target_path); -+} -+ - static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname, char **assemblies_path, void *user_data) - { - HRESULT hr; -@@ -1786,6 +1824,30 @@ static MonoAssembly* CDECL mono_assembly_preload_hook_fn(MonoAssemblyName *aname - } - } - -+ if (!strcmp(assemblyname, "CameraQuakeViewer")) -+ { -+ /* HACK for Nights of Azure which references type from a non-existing DLL. -+ * Native .NET framework normally gets away with it but Mono cannot -+ * due to some deeply rooted differences. */ -+ const char* sgi = getenv("SteamGameId"); -+ if (sgi && !strcmp(sgi, "527280")) -+ { -+ char assembly_path[MAX_PATH]; -+ -+ FIXME("HACK: Building CameraQuakeViewer.dll\n"); -+ -+ if (compile_assembly("namespace CQViewer { class CQMgr {} }", "CameraQuakeViewer.dll", assembly_path, MAX_PATH)) -+ result = mono_assembly_open(assembly_path, &stat); -+ else -+ ERR("HACK: Failed to build CameraQuakeViewer.dll\n"); -+ -+ if (result) -+ goto done; -+ else -+ ERR("HACK: Failed to load CameraQuakeViewer.dll\n"); -+ } -+ } -+ - /* FIXME: We should search the given paths before the GAC. */ - - if ((search_flags & ASSEMBLY_SEARCH_GAC) != 0) -From fc3d95a311a8e329af3d55a88fc68b41869af863 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 22 Dec 2021 00:57:25 +0300 -Subject: [PATCH] wine.inf: Set a valid Win10 ProductId. - -CW-Bug-Id: #19702 ---- - loader/wine.inf.in | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 0a41810d884..1c2286d722f 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -549,7 +549,7 @@ HKCU,%CurrentVersion%\Run,,16 - HKCU,%CurrentVersionNT%\Winlogon,,16 - HKLM,%CurrentVersion%,"CommonFilesDir",,"%16427%" - HKLM,%CurrentVersion%,"FirstInstallDateTime",1,21,81,7c,23 --HKLM,%CurrentVersion%,"ProductId",,"12345-oem-0000001-54321" -+HKLM,%CurrentVersion%,"ProductId",,"00330-50000-00000-AAOEM" - HKLM,%CurrentVersion%,"ProgramFilesDir",,"%16422%" - HKLM,%CurrentVersion%,"ProgramFilesPath",0x20000,"%%ProgramFiles%%" - HKLM,%CurrentVersion%,"RegisteredOrganization",2,"" -@@ -573,7 +573,7 @@ HKLM,%CurrentVersion%\Setup\WindowsFeatures\WindowsMediaVersion,,,"12.0.7601.188 - HKLM,%CurrentVersion%\Shell Extensions\Approved,,16 - HKLM,%CurrentVersion%\Uninstall,,16 - HKLM,%CurrentVersionNT%,"InstallDate",0x10003,1273299354 --HKLM,%CurrentVersionNT%,"ProductId",,"12345-oem-0000001-54321" -+HKLM,%CurrentVersionNT%,"ProductId",,"00330-50000-00000-AAOEM" - HKLM,%CurrentVersionNT%,"RegisteredOrganization",2,"" - HKLM,%CurrentVersionNT%,"RegisteredOwner",2,"" - HKLM,%CurrentVersionNT%,"SystemRoot",,"%10%" -From 80d7c0c041636e900589e8ae41c5fdd3a0470b29 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 22 Dec 2021 00:59:32 +0300 -Subject: [PATCH] wineboot: Generate better DigitalProductId. - -CW-Bug-Id: #19702 ---- - loader/wine.inf.in | 4 +-- - programs/wineboot/wineboot.c | 48 ++++++++++++++++++++++++++++++++++++ - 2 files changed, 50 insertions(+), 2 deletions(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 1c2286d722f..677ae91a406 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -5640,7 +5640,7 @@ HKLM,%CurrentVersionNT%,"CSDVersion",2,"" - HKLM,%CurrentVersionNT%,"CurrentBuild",2,"19043" - HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"19043" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" --HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ -+HKLM,%CurrentVersionNT%,"DigitalProductId",2,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -@@ -5660,7 +5660,7 @@ HKLM,%CurrentVersionNT%,"CSDVersion",2,"" - HKLM,%CurrentVersionNT%,"CurrentBuild",2,"19043" - HKLM,%CurrentVersionNT%,"CurrentBuildNumber",2,"19043" - HKLM,%CurrentVersionNT%,"CurrentType",2,"Uniprocessor Free" --HKLM,%CurrentVersionNT%,"DigitalProductId",1,00,00,00,00,00,00,00,00,00,00,00,\ -+HKLM,%CurrentVersionNT%,"DigitalProductId",2,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ - 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 5d1190583b1..16b44ca28ab 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -68,6 +68,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -1605,6 +1606,52 @@ static void usage( int status ) - exit( status ); - } - -+static void create_digitalproductid(void) -+{ -+ BYTE digital_product_id[0xa4]; -+ char product_id[256]; -+ LSTATUS status; -+ unsigned int i; -+ DWORD size; -+ DWORD type; -+ HKEY key; -+ -+ if ((status = RegOpenKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion", -+ 0, KEY_ALL_ACCESS, &key ))) -+ return; -+ size = sizeof(product_id); -+ status = RegQueryValueExA( key, "ProductId", NULL, &type, (BYTE *)product_id, &size ); -+ if (status) goto done; -+ if (!size) goto done; -+ if (product_id[size - 1]) -+ { -+ if (size == sizeof(product_id)) goto done; -+ product_id[size++] = 0; -+ } -+ -+ if (!RegQueryValueExA( key, "DigitalProductId", NULL, &type, NULL, &size ) && size == sizeof(digital_product_id)) -+ { -+ if (RegQueryValueExA( key, "DigitalProductId", NULL, &type, digital_product_id, &size )) -+ goto done; -+ for (i = 0; i < size; ++i) -+ if (digital_product_id[i]) break; -+ if (i < size) goto done; -+ } -+ -+ memset( digital_product_id, 0, sizeof(digital_product_id) ); -+ *(DWORD *)digital_product_id = sizeof(digital_product_id); -+ digital_product_id[4] = 3; -+ strcpy( (char *)digital_product_id + 8, product_id ); -+ *(DWORD *)(digital_product_id + 0x20) = 0x0cec; -+ *(DWORD *)(digital_product_id + 0x34) = 0x0cec; -+ strcpy( (char *)digital_product_id + 0x24, "[TH] X19-99481" ); -+ digital_product_id[0x42] = 8; -+ RtlGenRandom( digital_product_id + 0x38, 0x18 ); -+ RegSetValueExA( key, "DigitalProductId", 0, REG_BINARY, digital_product_id, sizeof(digital_product_id) ); -+done: -+ RegCloseKey( key ); -+} -+ - int __cdecl main( int argc, char *argv[] ) - { - /* First, set the current directory to SystemRoot */ -@@ -1716,6 +1763,7 @@ int __cdecl main( int argc, char *argv[] ) - } - if (init || update) update_wineprefix( update ); - -+ create_digitalproductid(); - create_volatile_environment_registry_key(); - - ProcessRunKeys( HKEY_LOCAL_MACHINE, L"RunOnce", TRUE, TRUE ); -From ec73e47719b3d135a3b266eb195f3663e0bed847 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 6 Jan 2022 14:00:35 +0300 -Subject: [PATCH] winhttp: HACK: Reuse threadpool for Monster Hunter Rise. - -CW-Bug-Id: #19484 ---- - dlls/winhttp/main.c | 6 ++++ - dlls/winhttp/request.c | 64 +++++++++++++++++++++++++++++++--- - dlls/winhttp/winhttp_private.h | 1 + - 3 files changed, 67 insertions(+), 4 deletions(-) - -diff --git a/dlls/winhttp/main.c b/dlls/winhttp/main.c -index e4449364386..86d0e79a182 100644 ---- a/dlls/winhttp/main.c -+++ b/dlls/winhttp/main.c -@@ -42,9 +42,15 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) - switch(fdwReason) - { - case DLL_PROCESS_ATTACH: -+ { -+ char str[64]; -+ - winhttp_instance = hInstDLL; - DisableThreadLibraryCalls(hInstDLL); -+ if ((reuse_threadpool = GetEnvironmentVariableA( "SteamGameId", str, sizeof(str)) && !strcmp(str, "1446780" ))) -+ ERR( "HACK: setting reuse_threadpool.\n" ); - break; -+ } - case DLL_PROCESS_DETACH: - if (lpv) break; - netconn_unload(); -diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c -index d76edfa71d7..18c30087d6f 100644 ---- a/dlls/winhttp/request.c -+++ b/dlls/winhttp/request.c -@@ -43,6 +43,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(winhttp); - - #define DEFAULT_KEEP_ALIVE_TIMEOUT 30000 - -+BOOL reuse_threadpool; -+ -+static struct -+{ -+ TP_POOL *pool; -+ LONG ref; -+} -+thread_pool_cache; -+ -+static CRITICAL_SECTION thread_pool_cache_cs; -+static CRITICAL_SECTION_DEBUG thread_pool_cache_debug = -+{ -+ 0, 0, &thread_pool_cache_cs, -+ { &thread_pool_cache_debug.ProcessLocksList, &thread_pool_cache_debug.ProcessLocksList }, -+ 0, 0, { (DWORD_PTR)(__FILE__ ": thread_pool_cache_cs") } -+}; -+static CRITICAL_SECTION thread_pool_cache_cs = { &thread_pool_cache_debug, -1, 0, 0, 0, 0 }; -+ - static const WCHAR *attribute_table[] = - { - L"Mime-Version", /* WINHTTP_QUERY_MIME_VERSION = 0 */ -@@ -122,13 +140,37 @@ static const WCHAR *attribute_table[] = - NULL /* WINHTTP_QUERY_PASSPORT_CONFIG = 78 */ - }; - -+static TP_POOL *create_thread_pool(void) -+{ -+ TP_POOL *pool; -+ -+ if (!(pool = CreateThreadpool( NULL ))) return NULL; -+ SetThreadpoolThreadMinimum( pool, 1 ); -+ SetThreadpoolThreadMaximum( pool, 1 ); -+ -+ return pool; -+} -+ - static DWORD start_queue( struct queue *queue ) - { - if (queue->pool) return ERROR_SUCCESS; - -- if (!(queue->pool = CreateThreadpool( NULL ))) return GetLastError(); -- SetThreadpoolThreadMinimum( queue->pool, 1 ); -- SetThreadpoolThreadMaximum( queue->pool, 1 ); -+ if (reuse_threadpool) -+ { -+ EnterCriticalSection( &thread_pool_cache_cs ); -+ if (!thread_pool_cache.pool) -+ { -+ assert( !thread_pool_cache.ref ); -+ thread_pool_cache.pool = create_thread_pool(); -+ } -+ ++thread_pool_cache.ref; -+ queue->pool = thread_pool_cache.pool; -+ LeaveCriticalSection( &thread_pool_cache_cs ); -+ } -+ else -+ { -+ if (!(queue->pool = create_thread_pool())) return GetLastError(); -+ } - - memset( &queue->env, 0, sizeof(queue->env) ); - queue->env.Version = 1; -@@ -141,7 +183,21 @@ static DWORD start_queue( struct queue *queue ) - void stop_queue( struct queue *queue ) - { - if (!queue->pool) return; -- CloseThreadpool( queue->pool ); -+ if (reuse_threadpool) -+ { -+ EnterCriticalSection( &thread_pool_cache_cs ); -+ assert(thread_pool_cache.ref); -+ if (!--thread_pool_cache.ref) -+ { -+ CloseThreadpool( thread_pool_cache.pool ); -+ thread_pool_cache.pool = NULL; -+ } -+ LeaveCriticalSection( &thread_pool_cache_cs ); -+ } -+ else -+ { -+ CloseThreadpool( queue->pool ); -+ } - queue->pool = NULL; - TRACE("stopped %p\n", queue); - } -diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h -index 291a38e7bdd..fbd52a0eea7 100644 ---- a/dlls/winhttp/winhttp_private.h -+++ b/dlls/winhttp/winhttp_private.h -@@ -397,5 +397,6 @@ static inline char *strdupWA_sized( const WCHAR *src, DWORD size ) - } - - extern HINSTANCE winhttp_instance DECLSPEC_HIDDEN; -+extern BOOL reuse_threadpool DECLSPEC_HIDDEN; - - #endif /* _WINE_WINHTTP_PRIVATE_H_ */ -From 883cf0f65186fb8f6faa2f903132ebfdb84f9fb0 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Thu, 20 Jan 2022 22:49:14 +0300 -Subject: [PATCH] win32u: Allow getting GL driver when DC is locked by another - thread. - -CW-Bug-Id: #20015 ---- - dlls/win32u/dc.c | 19 ------------------- - dlls/win32u/driver.c | 16 +++++++++++----- - dlls/win32u/ntgdi_private.h | 19 +++++++++++++++++++ - 3 files changed, 30 insertions(+), 24 deletions(-) - -diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c -index 3aae73779e9..9c09bf66e03 100644 ---- a/dlls/win32u/dc.c -+++ b/dlls/win32u/dc.c -@@ -63,25 +63,6 @@ static const struct gdi_obj_funcs dc_funcs = - }; - - --static inline DC *get_dc_obj( HDC hdc ) --{ -- DWORD type; -- DC *dc = get_any_obj_ptr( hdc, &type ); -- if (!dc) return NULL; -- -- switch (type) -- { -- case NTGDI_OBJ_DC: -- case NTGDI_OBJ_MEMDC: -- case NTGDI_OBJ_ENHMETADC: -- return dc; -- default: -- GDI_ReleaseObj( hdc ); -- SetLastError( ERROR_INVALID_HANDLE ); -- return NULL; -- } --} -- - /* alloc DC_ATTR from a pool of memory accessible from client */ - static DC_ATTR *alloc_dc_attr(void) - { -diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c -index 39996086c6d..147f7da1cef 100644 ---- a/dlls/win32u/driver.c -+++ b/dlls/win32u/driver.c -@@ -1348,13 +1348,19 @@ NTSTATUS WINAPI NtGdiDdDDICheckVidPnExclusiveOwnership( const D3DKMT_CHECKVIDPNE - struct opengl_funcs * CDECL __wine_get_wgl_driver( HDC hdc, UINT version ) - { - struct opengl_funcs *ret = NULL; -- DC * dc = get_dc_ptr( hdc ); -+ DC * dc = get_dc_obj( hdc ); -+ PHYSDEV physdev; - -- if (dc) -+ if (!dc) return NULL; -+ -+ if (dc->attr->disabled) - { -- PHYSDEV physdev = GET_DC_PHYSDEV( dc, wine_get_wgl_driver ); -- ret = physdev->funcs->wine_get_wgl_driver( physdev, version ); -- release_dc_ptr( dc ); -+ GDI_ReleaseObj( hdc ); -+ return NULL; - } -+ -+ physdev = GET_DC_PHYSDEV( dc, wine_get_wgl_driver ); -+ ret = physdev->funcs->wine_get_wgl_driver( physdev, version ); -+ GDI_ReleaseObj( hdc ); - return ret; - } -diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h -index bfeb4557da7..d89f9a56ad4 100644 ---- a/dlls/win32u/ntgdi_private.h -+++ b/dlls/win32u/ntgdi_private.h -@@ -660,6 +660,25 @@ static inline void copy_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *src ) - memcpy( dst, src, get_dib_info_size( src, DIB_RGB_COLORS )); - } - -+static inline DC *get_dc_obj( HDC hdc ) -+{ -+ DWORD type; -+ DC *dc = get_any_obj_ptr( hdc, &type ); -+ if (!dc) return NULL; -+ -+ switch (type) -+ { -+ case NTGDI_OBJ_DC: -+ case NTGDI_OBJ_MEMDC: -+ case NTGDI_OBJ_ENHMETADC: -+ return dc; -+ default: -+ GDI_ReleaseObj( hdc ); -+ SetLastError( ERROR_INVALID_HANDLE ); -+ return NULL; -+ } -+} -+ - extern void CDECL free_heap_bits( struct gdi_image_bits *bits ) DECLSPEC_HIDDEN; - - void set_gdi_client_ptr( HGDIOBJ handle, void *ptr ) DECLSPEC_HIDDEN; -From 02303a876c719603df9c1754984edacd7c5bfa2c Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 25 Jan 2022 14:42:07 +0300 -Subject: [PATCH] server: Release correct sockets in poll_socket(). - -CW-Bug-Id: #20051 ---- - server/sock.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/server/sock.c b/server/sock.c -index 7343305d6e0..42c3f0684cc 100644 ---- a/server/sock.c -+++ b/server/sock.c -@@ -3052,7 +3052,7 @@ static void poll_socket( struct sock *poll_sock, struct async *async, int exclus - req->sockets[i].sock = (struct sock *)get_handle_obj( current->process, sockets[i].socket, 0, &sock_ops ); - if (!req->sockets[i].sock) - { -- for (j = 0; j < i; ++j) release_object( req->sockets[i].sock ); -+ for (j = 0; j < i; ++j) release_object( req->sockets[j].sock ); - if (req->timeout) remove_timeout_user( req->timeout ); - free( req ); - return; -From 762a8d7bd8e1027eae7222c23253726a08af9964 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 3 Feb 2022 11:35:13 -0600 -Subject: [PATCH] HACK: shell32: Preserve duplicated Documents/Stuff - directories - ---- - dlls/shell32/shellpath.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c -index 78a09888194..7c8bc029575 100644 ---- a/dlls/shell32/shellpath.c -+++ b/dlls/shell32/shellpath.c -@@ -3113,6 +3113,23 @@ static HRESULT create_extra_folders(void) - hr = SHGetFolderPathAndSubDirW(0, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, - SHGFP_TYPE_DEFAULT, L"Microsoft\\Windows\\Themes", path); - } -+ -+ -+ /* Proton HACK: In older Proton versions, duplicate Stuff directories were -+ * created at both %PROFILE%\Music and %PROFILE\Documents\Music. Due to -+ * some bugs when downgrading to those older Proton versions, create those -+ * missing Documents directories here, too. */ -+ SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, -+ SHGFP_TYPE_DEFAULT, L"Downloads", path); -+ SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, -+ SHGFP_TYPE_DEFAULT, L"Music", path); -+ SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, -+ SHGFP_TYPE_DEFAULT, L"Pictures", path); -+ SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, -+ SHGFP_TYPE_DEFAULT, L"Templates", path); -+ SHGetFolderPathAndSubDirW(0, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, -+ SHGFP_TYPE_DEFAULT, L"Videos", path); -+ - return hr; - } - -From 1143da088beef1fdbcfc208af189d25ce28e9f75 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 8 Feb 2022 16:39:35 +0200 -Subject: [PATCH] server: Always update cached socket name after connect. - -Fixes a regression introduced by -5c009c17b3a212c3f5b0034c465077c0c593daae. - -For IPV6 socket already bound with bind() with IPV6_V6ONLY set to 0 -the address returned by getsockname() may change after it is connected -to a IPV4 peer (e. g., from :: to ::ffff:192.0.2.128). - -The effect of blamed commit is that before that Unix getsockname() -was called for each ws2_32 getsockname() and after the commit the -socket name is cached at bind and connect. - -Signed-off-by: Paul Gofman -CW-Bug-Id: #20115 ---- - server/sock.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/server/sock.c b/server/sock.c -index 42c3f0684cc..3c78efcc134 100644 ---- a/server/sock.c -+++ b/server/sock.c -@@ -2342,7 +2342,7 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) - allow_fd_caching( sock->fd ); - - unix_len = sizeof(unix_addr); -- if (!sock->bound && !getsockname( unix_fd, &unix_addr.addr, &unix_len )) -+ if (!getsockname( unix_fd, &unix_addr.addr, &unix_len )) - sock->addr_len = sockaddr_from_unix( &unix_addr, &sock->addr.addr, sizeof(sock->addr) ); - sock->bound = 1; - -From 3244ba9966c0e7bcd445a65b5c325801f9b77131 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 5 Jan 2022 13:31:14 +0300 -Subject: [PATCH] audioses: Add stub dll. - -CW-Bug-Id: #19918 ---- - configure.ac | 1 + - dlls/audioses/Makefile.in | 1 + - dlls/audioses/audioses.spec | 11 +++++++++++ - 3 files changed, 13 insertions(+) - create mode 100644 dlls/audioses/Makefile.in - create mode 100644 dlls/audioses/audioses.spec - -diff --git a/configure.ac b/configure.ac -index f37f4e02324..95f9a35bf7f 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -2625,6 +2625,7 @@ WINE_CONFIG_MAKEFILE(dlls/atl90) - WINE_CONFIG_MAKEFILE(dlls/atlthunk) - WINE_CONFIG_MAKEFILE(dlls/atlthunk/tests) - WINE_CONFIG_MAKEFILE(dlls/atmlib) -+WINE_CONFIG_MAKEFILE(dlls/audioses) - WINE_CONFIG_MAKEFILE(dlls/authz) - WINE_CONFIG_MAKEFILE(dlls/avicap32) - WINE_CONFIG_MAKEFILE(dlls/avifil32) -diff --git a/dlls/audioses/Makefile.in b/dlls/audioses/Makefile.in -new file mode 100644 -index 00000000000..370949ea4fe ---- /dev/null -+++ b/dlls/audioses/Makefile.in -@@ -0,0 +1 @@ -+MODULE = audioses.dll -diff --git a/dlls/audioses/audioses.spec b/dlls/audioses/audioses.spec -new file mode 100644 -index 00000000000..a1884e53243 ---- /dev/null -+++ b/dlls/audioses/audioses.spec -@@ -0,0 +1,11 @@ -+# @ stub AUDIOSES_1 -+# @ stub AUDIOSES_2 -+# @ stub AUDIOSES_3 -+# @ stub AUDIOSES_4 -+# @ stub AUDIOSES_5 -+# @ stub DllCanUnloadNow -+# @ stub AUDIOSES_7 -+# @ stub DllGetActivationFactory -+# @ stub DllGetClassObject -+# @ stub DllRegisterServer -+# @ stub DllUnregisterServer -From 21ca36991c672528f8e0b3627a180d2049910bd6 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 7 Jan 2022 23:54:20 +0300 -Subject: [PATCH] mshtml: Also call before_async_open() for iframe in - nsChannel_AsyncOpen(). - -CW-Bug-Id: #19930 ---- - dlls/ieframe/tests/webbrowser.c | 144 +++++++++++++++++++++++++++----- - dlls/mshtml/nsio.c | 65 ++++++++++++++ - 2 files changed, 188 insertions(+), 21 deletions(-) - -diff --git a/dlls/ieframe/tests/webbrowser.c b/dlls/ieframe/tests/webbrowser.c -index 864a8baf27f..d8587216550 100644 ---- a/dlls/ieframe/tests/webbrowser.c -+++ b/dlls/ieframe/tests/webbrowser.c -@@ -172,6 +172,7 @@ static HRESULT hr_site_TranslateAccelerator = E_NOTIMPL; - static const WCHAR *current_url; - static int wb_version, expect_update_commands_enable, set_update_commands_enable; - static BOOL nav_back_todo, nav_forward_todo; /* FIXME */ -+static BOOL navigation_cancelled; - - enum SessionOp - { -@@ -191,6 +192,8 @@ static LONG (WINAPI *pSetQueryNetSessionCount)(DWORD); - #define DWL_HTTP 0x10 - #define DWL_REFRESH 0x20 - #define DWL_BACK_ENABLE 0x40 -+#define DWL_IFRAME_NAV_CANCEL 0x80 -+#define DWL_FROM_IFRAME_NAV_CANCEL 0x100 - - static DWORD dwl_flags; - -@@ -290,6 +293,8 @@ static void _test_ready_state(unsigned line, READYSTATE exstate, VARIANT_BOOL ex - hres = IWebBrowser2_get_Busy(wb, &busy); - if(expect_busy != BUSY_FAIL) { - ok_(__FILE__,line)(hres == S_OK, "get_ReadyState failed: %08x\n", hres); -+ todo_wine_if(dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL && state == READYSTATE_LOADING -+ && busy != expect_busy) - ok_(__FILE__,line)(busy == expect_busy, "Busy = %x, expected %x for ready state %d\n", - busy, expect_busy, state); - }else { -@@ -415,13 +420,13 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID - ok(nCmdexecopt == OLECMDEXECOPT_DONTPROMPTUSER || !nCmdexecopt, - "nCmdexecopts=%08x\n", nCmdexecopt); - else -- ok(!nCmdexecopt, "nCmdexecopts=%08x\n", nCmdexecopt); -+ todo_wine_if(dwl_flags & DWL_IFRAME_NAV_CANCEL) ok(!nCmdexecopt, "nCmdexecopts=%08x\n", nCmdexecopt); - ok(pvaOut == NULL, "pvaOut=%p\n", pvaOut); - ok(pvaIn != NULL, "pvaIn == NULL\n"); - ok(V_VT(pvaIn) == VT_I4, "V_VT(pvaIn)=%d\n", V_VT(pvaIn)); - switch(V_I4(pvaIn)) { - case 0: -- CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_0); -+ todo_wine_if(dwl_flags & DWL_IFRAME_NAV_CANCEL) CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_0); - break; - case 1: - CHECK_EXPECT2(Exec_SETDOWNLOADSTATE_1); -@@ -480,6 +485,7 @@ static HRESULT WINAPI OleCommandTarget_Exec(IOleCommandTarget *iface, const GUID - }else if(IsEqualGUID(&CGID_ShellDocView, pguidCmdGroup)) { - switch(nCmdID) { - case 63: /* win10 */ -+ case 65: - case 105: /* TODO */ - case 132: /* win10 */ - case 133: /* IE11 */ -@@ -719,11 +725,11 @@ static void _test_invoke_bool(unsigned line, const DISPPARAMS *params, BOOL stri - static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const VARIANT *flags, - const VARIANT *frame, const VARIANT *post_data, const VARIANT *headers, const VARIANT *cancel) - { -+ BOOL cancel_nav = FALSE; - BSTR str; - - ok(V_VT(disp) == VT_DISPATCH, "V_VT(disp)=%d, expected VT_DISPATCH\n", V_VT(disp)); - ok(V_DISPATCH(disp) != NULL, "V_DISPATCH(disp) == NULL\n"); -- ok(V_DISPATCH(disp) == (IDispatch*)wb, "V_DISPATCH(disp)=%p, wb=%p\n", V_DISPATCH(disp), wb); - - ok(V_VT(url) == (VT_BYREF|VT_VARIANT), "V_VT(url)=%x, expected VT_BYREF|VT_VARIANT\n", V_VT(url)); - ok(V_VARIANTREF(url) != NULL, "V_VARIANTREF(url) == NULL)\n"); -@@ -731,10 +737,21 @@ static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const - ok(V_VT(V_VARIANTREF(url)) == VT_BSTR, "V_VT(V_VARIANTREF(url))=%d, expected VT_BSTR\n", - V_VT(V_VARIANTREF(url))); - ok(V_BSTR(V_VARIANTREF(url)) != NULL, "V_BSTR(V_VARIANTREF(url)) == NULL\n"); -- ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), current_url), "unexpected url %s, expected %s\n", -- wine_dbgstr_w(V_BSTR(V_VARIANTREF(url))), wine_dbgstr_w(current_url)); -+ if (!wcscmp(V_BSTR(V_VARIANTREF(url)), L"invalid:///")) -+ cancel_nav = TRUE; -+ if (!(dwl_flags & DWL_IFRAME_NAV_CANCEL && cancel_nav)) -+ ok(!lstrcmpW(V_BSTR(V_VARIANTREF(url)), current_url), "unexpected url %s, expected %s\n", -+ wine_dbgstr_w(V_BSTR(V_VARIANTREF(url))), wine_dbgstr_w(current_url)); - } - -+ if (dwl_flags & DWL_IFRAME_NAV_CANCEL && cancel_nav) -+ { -+ ok(!!V_DISPATCH(disp), "Got NULL disp.\n"); -+ todo_wine ok(V_DISPATCH(disp) != (IDispatch*)wb, "Got the same browser.\n"); -+ } -+ else -+ ok(V_DISPATCH(disp) == (IDispatch*)wb, "V_DISPATCH(disp)=%p, wb=%p\n", V_DISPATCH(disp), wb); -+ - ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", - V_VT(flags)); - ok(V_VT(flags) == (VT_BYREF|VT_VARIANT), "V_VT(flags)=%x, expected VT_BYREF|VT_VARIANT\n", -@@ -805,8 +822,15 @@ static void test_OnBeforeNavigate(const VARIANT *disp, const VARIANT *url, const - V_VT(cancel)); - ok(V_BOOLREF(cancel) != NULL, "V_BOOLREF(pDispParams->rgvarg[0] == NULL)\n"); - if(V_BOOLREF(cancel)) -+ { - ok(*V_BOOLREF(cancel) == VARIANT_FALSE, "*V_BOOLREF(cancel) = %x, expected VARIANT_FALSE\n", - *V_BOOLREF(cancel)); -+ if (cancel_nav) -+ { -+ *V_BOOLREF(cancel) = TRUE; -+ navigation_cancelled = TRUE; -+ } -+ } - } - - static void test_navigatecomplete2(DISPPARAMS *dp) -@@ -821,6 +845,7 @@ static void test_navigatecomplete2(DISPPARAMS *dp) - ok(V_VT(dp->rgvarg) == (VT_BYREF|VT_VARIANT), "V_VT(dp->rgvarg) = %d\n", V_VT(dp->rgvarg)); - v = V_VARIANTREF(dp->rgvarg); - ok(V_VT(v) == VT_BSTR, "V_VT(url) = %d\n", V_VT(v)); -+ todo_wine_if(!memcmp(V_BSTR(v), L"file:", 10)) - ok(!lstrcmpW(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), - wine_dbgstr_w(current_url)); - -@@ -845,6 +870,8 @@ static void test_documentcomplete(DISPPARAMS *dp) - ok(V_VT(dp->rgvarg) == (VT_BYREF|VT_VARIANT), "V_VT(dp->rgvarg) = %d\n", V_VT(dp->rgvarg)); - v = V_VARIANTREF(dp->rgvarg); - ok(V_VT(v) == VT_BSTR, "V_VT(url) = %d\n", V_VT(v)); -+ -+ todo_wine_if(!memcmp(V_BSTR(v), L"file:", 10)) - ok(!lstrcmpW(V_BSTR(v), current_url), "url=%s, expected %s\n", wine_dbgstr_w(V_BSTR(v)), - wine_dbgstr_w(current_url)); - -@@ -907,9 +934,19 @@ static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMe - pDispParams->rgvarg+3, pDispParams->rgvarg+2, pDispParams->rgvarg+1, - pDispParams->rgvarg); - if(dwl_flags & (DWL_FROM_PUT_HREF|DWL_FROM_GOFORWARD)) -+ { - test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); -+ } -+ else if (dwl_flags & DWL_IFRAME_NAV_CANCEL) -+ { -+ test_ready_state(READYSTATE_LOADING, navigation_cancelled ? VARIANT_TRUE : VARIANT_FALSE); -+ if (!navigation_cancelled) -+ SET_EXPECT(Invoke_BEFORENAVIGATE2); -+ } - else -- test_ready_state(READYSTATE_LOADING, VARIANT_FALSE); -+ { -+ test_ready_state(READYSTATE_LOADING, dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL ? VARIANT_TRUE : VARIANT_FALSE); -+ } - break; - - case DISPID_SETSECURELOCKICON: -@@ -948,7 +985,7 @@ static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMe - CHECK_EXPECT2(Invoke_COMMANDSTATECHANGE_NAVIGATEFORWARD_FALSE); - } - } -- else if (V_I4(pDispParams->rgvarg+1) == CSC_NAVIGATEBACK) -+ else if (V_I4(pDispParams->rgvarg+1) == CSC_NAVIGATEBACK && !(dwl_flags & DWL_FROM_IFRAME_NAV_CANCEL)) - { - todo_wine_if(nav_back_todo) { - if(V_BOOL(pDispParams->rgvarg)) -@@ -1681,6 +1718,8 @@ static HRESULT WINAPI DocHostUIHandler_TranslateUrl(IDocHostUIHandler2 *iface, D - { - todo_wine_if(is_downloading && !(dwl_flags & DWL_EXPECT_BEFORE_NAVIGATE)) - CHECK_EXPECT(TranslateUrl); -+ if (dwl_flags & DWL_IFRAME_NAV_CANCEL && wcscmp(pchURLIn, L"invalid:///")) -+ SET_EXPECT(TranslateUrl); - return E_NOTIMPL; - } - -@@ -2814,12 +2853,16 @@ static void test_ConnectionPoint(IWebBrowser2 *unk, BOOL init) - static void test_Navigate2(IWebBrowser2 *webbrowser, const WCHAR *nav_url) - { - const WCHAR *title = L"WineHQ - Run Windows applications on Linux, BSD, Solaris and Mac OS X"; -+ const WCHAR *file_title = L"wine_test"; - VARIANT url; - BOOL is_file; - HRESULT hres; - - test_LocationURL(webbrowser, is_first_load ? L"" : current_url); -- test_LocationName(webbrowser, is_first_load ? L"" : (is_http ? title : current_url)); -+ if (current_url && !memcmp(current_url, L"file:", 10)) -+ test_LocationName(webbrowser, file_title); -+ else -+ test_LocationName(webbrowser, is_first_load ? L"" : (is_http ? title : current_url)); - test_ready_state(is_first_load ? READYSTATE_UNINITIALIZED : READYSTATE_COMPLETE, VARIANT_FALSE); - - is_http = !memcmp(nav_url, "http:", 5); -@@ -2990,6 +3033,8 @@ static void test_download(DWORD flags) - BOOL *b = &called_Invoke_DOCUMENTCOMPLETE; - MSG msg; - -+ navigation_cancelled = FALSE; -+ - if(flags & DWL_REFRESH) - b = use_container_olecmd ? &called_Exec_SETDOWNLOADSTATE_0 : &called_Invoke_DOWNLOADCOMPLETE; - else if((flags & DWL_FROM_PUT_HREF) && !use_container_olecmd && 0) -@@ -3001,8 +3046,9 @@ static void test_download(DWORD flags) - if(flags & (DWL_FROM_PUT_HREF|DWL_FROM_GOBACK|DWL_FROM_GOFORWARD|DWL_REFRESH)) - test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); - else -- test_ready_state(READYSTATE_LOADING, VARIANT_FALSE); -- -+ { -+ test_ready_state(READYSTATE_LOADING, flags & DWL_FROM_IFRAME_NAV_CANCEL ? VARIANT_TRUE : VARIANT_FALSE); -+ } - if(flags & (DWL_EXPECT_BEFORE_NAVIGATE|(is_http ? DWL_FROM_PUT_HREF : 0)|DWL_FROM_GOFORWARD|DWL_REFRESH)) - SET_EXPECT(Invoke_PROPERTYCHANGE); - -@@ -3065,7 +3111,7 @@ static void test_download(DWORD flags) - SET_EXPECT(GetOverridesKeyPath); /* Called randomly on some VMs. */ - - trace("Downloading...\n"); -- while(!*b && GetMessageW(&msg, NULL, 0, 0)) { -+ while(!navigation_cancelled && !*b && GetMessageW(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } -@@ -3096,11 +3142,14 @@ static void test_download(DWORD flags) - CLEAR_CALLED(EnableModeless_FALSE); /* IE 8 */ - - if(!(flags & DWL_REFRESH)) { -- todo_wine_if(nav_back_todo) { -- if(flags & (DWL_FROM_GOFORWARD|DWL_BACK_ENABLE)) -- CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_TRUE); -- else -- CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_FALSE); -+ if (!(flags & DWL_FROM_IFRAME_NAV_CANCEL)) -+ { -+ todo_wine_if(nav_back_todo) { -+ if(flags & (DWL_FROM_GOFORWARD|DWL_BACK_ENABLE)) -+ CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_TRUE); -+ else -+ CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEBACK_FALSE); -+ } - } - if(flags & DWL_FROM_GOBACK) - CHECK_CALLED(Invoke_COMMANDSTATECHANGE_NAVIGATEFORWARD_TRUE); -@@ -3117,20 +3166,26 @@ static void test_download(DWORD flags) - if(!is_first_load) - todo_wine CHECK_CALLED(GetHostInfo); - if(use_container_olecmd) -- CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); -+ todo_wine_if(flags & DWL_IFRAME_NAV_CANCEL) CHECK_CALLED(Exec_SETDOWNLOADSTATE_0); - else -- CHECK_CALLED(Invoke_DOWNLOADCOMPLETE); -+ todo_wine_if(flags & DWL_IFRAME_NAV_CANCEL) CHECK_CALLED(Invoke_DOWNLOADCOMPLETE); - todo_wine CHECK_CALLED(Invoke_TITLECHANGE); - if(!(flags & DWL_REFRESH)) - CHECK_CALLED(Invoke_NAVIGATECOMPLETE2); - if(is_first_load) - todo_wine CHECK_CALLED(GetDropTarget); -- if(!(flags & DWL_REFRESH)) -+ if(!(flags & (DWL_REFRESH | DWL_IFRAME_NAV_CANCEL))) - CHECK_CALLED(Invoke_DOCUMENTCOMPLETE); - - is_downloading = FALSE; - -- test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); -+ if (flags & DWL_IFRAME_NAV_CANCEL) -+ { -+ test_ready_state(READYSTATE_INTERACTIVE, VARIANT_TRUE); -+ SET_EXPECT(Invoke_TITLECHANGE); -+ } -+ else -+ test_ready_state(READYSTATE_COMPLETE, VARIANT_FALSE); - - while(use_container_olecmd && !called_Exec_UPDATECOMMANDS && GetMessageA(&msg, NULL, 0, 0)) { - TranslateMessage(&msg); -@@ -3840,6 +3895,51 @@ static void init_test(IWebBrowser2 *webbrowser, DWORD flags) - use_container_dochostui = !(flags & TEST_NODOCHOST); - } - -+static const char iframe_doc_str[] = -+ ""; -+ -+static void test_iframe_load(IWebBrowser2 *webbrowser) -+{ -+ WCHAR file_path[MAX_PATH]; -+ WCHAR file_url[MAX_PATH]; -+ HRESULT hres; -+ HANDLE file; -+ VARIANT url; -+ DWORD size; -+ BOOL bret; -+ -+ GetTempPathW(MAX_PATH, file_path); -+ lstrcatW(file_path, L"wine_ifr_test.html"); -+ -+ file = CreateFileW(file_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); -+ ok(file != INVALID_HANDLE_VALUE, "CreateFile failed, error %u.\n", GetLastError()); -+ if(file == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS){ -+ ok(0, "CreateFile failed\n"); -+ return; -+ } -+ WriteFile(file, iframe_doc_str, strlen(iframe_doc_str), &size, NULL); -+ CloseHandle(file); -+ -+ GetLongPathNameW(file_path, file_path, ARRAY_SIZE(file_path)); -+ lstrcpyW(file_url, L"file://"); -+ lstrcatW(file_url, file_path); -+ -+ trace("iframe load...\n"); -+ test_Navigate2(webbrowser, file_url); -+ test_download(DWL_EXPECT_BEFORE_NAVIGATE|DWL_IFRAME_NAV_CANCEL|DWL_BACK_ENABLE); -+ -+ V_VT(&url) = VT_BSTR; -+ V_BSTR(&url) = SysAllocString(current_url = L"about:blank"); -+ hres = IWebBrowser2_Navigate2(webbrowser, &url, NULL, NULL, NULL, NULL); -+ ok(hres == S_OK, "Navigate2 failed: %08x\n", hres); -+ VariantClear(&url); -+ -+ test_download(DWL_EXPECT_BEFORE_NAVIGATE|DWL_FROM_IFRAME_NAV_CANCEL); -+ -+ bret = DeleteFileW(file_path); -+ ok(bret, "DeleteFileW failed, err %u.\n", GetLastError()); -+} -+ - static void test_WebBrowser(DWORD flags, BOOL do_close) - { - IWebBrowser2 *webbrowser; -@@ -3868,6 +3968,7 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) - test_LocationURL(webbrowser, L""); - test_ConnectionPoint(webbrowser, TRUE); - -+ - test_ClientSite(webbrowser, &ClientSite, !do_download); - test_Extent(webbrowser); - test_wb_funcs(webbrowser, TRUE); -@@ -3934,6 +4035,8 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) - trace("GoForward...\n"); - test_go_forward(webbrowser, L"http://test.winehq.org/tests/winehq_snapshot/", -1, 0); - test_download(DWL_FROM_GOFORWARD|DWL_HTTP); -+ if (!(flags & TEST_NOOLECMD)) -+ test_iframe_load(webbrowser); - }else { - trace("Navigate2 repeated with the same URL...\n"); - test_Navigate2(webbrowser, L"about:blank"); -@@ -3942,7 +4045,6 @@ static void test_WebBrowser(DWORD flags, BOOL do_close) - - test_EnumVerbs(webbrowser); - test_TranslateAccelerator(webbrowser); -- - test_dochost_qs(webbrowser); - }else { - test_ExecWB(webbrowser, TRUE); -diff --git a/dlls/mshtml/nsio.c b/dlls/mshtml/nsio.c -index f921acf4dce..61587570678 100644 ---- a/dlls/mshtml/nsio.c -+++ b/dlls/mshtml/nsio.c -@@ -275,6 +275,50 @@ static nsresult before_async_open(nsChannel *channel, GeckoBrowser *container, B - return NS_OK; - } - -+static nsresult fire_before_navigate(nsChannel *channel, HTMLOuterWindow *window, BOOL *cancel) -+{ -+ BSTR frame_name = NULL; -+ OLECHAR *new_url; -+ BSTR uri_str; -+ HRESULT hres; -+ -+ hres = IUri_GetDisplayUri(channel->uri->uri, &uri_str); -+ if(FAILED(hres)) -+ { -+ ERR("IUri_GetDisplayUri failed, hres %#x.\n", hres); -+ return NS_ERROR_FAILURE; -+ } -+ if(window->browser->doc->hostui) -+ { -+ hres = IDocHostUIHandler_TranslateUrl(window->browser->doc->hostui, 0, uri_str, &new_url); -+ if(hres == S_OK && new_url) -+ { -+ if(wcscmp(uri_str, new_url)) -+ { -+ FIXME("TranslateUrl returned new URL %s -> %s.\n", debugstr_w(uri_str), debugstr_w(new_url)); -+ CoTaskMemFree(new_url); -+ *cancel = TRUE; -+ SysFreeString(uri_str); -+ return NS_OK; -+ } -+ CoTaskMemFree(new_url); -+ } -+ } -+ -+ hres = IHTMLWindow2_get_name(&window->base.IHTMLWindow2_iface, &frame_name); -+ if (FAILED(hres)) -+ { -+ SysFreeString(uri_str); -+ return NS_ERROR_FAILURE; -+ } -+ -+ hres = IDocObjectService_FireBeforeNavigate2(window->browser->doc->doc_object_service, NULL, uri_str, 0x40, -+ frame_name, NULL, 0, NULL, TRUE, cancel); -+ SysFreeString(frame_name); -+ SysFreeString(uri_str); -+ return SUCCEEDED(hres) ? NS_OK : NS_ERROR_FAILURE; -+} -+ - HRESULT load_nsuri(HTMLOuterWindow *window, nsWineURI *uri, nsIInputStream *post_stream, - nsChannelBSC *channelbsc, DWORD flags) - { -@@ -1077,6 +1121,27 @@ static nsresult NSAPI nsChannel_AsyncOpen(nsIHttpChannel *iface, nsIStreamListen - This->content_type = heap_strdupWtoA(window->browser->doc->mime); - } - } -+ else if (window->browser && window->frame_element && window->browser->doc -+ && window->browser->doc->doc_object_service) -+ { -+ IUnknown *unk; -+ if (SUCCEEDED(IHTMLFrameBase_QueryInterface(&window->frame_element->IHTMLFrameBase_iface, -+ &IID_IHTMLIFrameElement, (void **)&unk))) -+ { -+ IUnknown_Release(unk); -+ nsres = fire_before_navigate(This, window, &cancel); -+ if(NS_SUCCEEDED(nsres) && cancel) -+ { -+ TRACE("canceled.\n"); -+ nsres = NS_BINDING_ABORTED; -+ } -+ else -+ { -+ FIXME("fire_before_navigate returned error %#x.\n", nsres); -+ nsres = NS_OK; -+ } -+ } -+ } - } - - if(!cancel) -From 353834ad445346cc37e5cc214534edc6f476f051 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Sat, 18 Dec 2021 00:24:39 +0300 -Subject: [PATCH] ntdll: Change module search order in - LdrFindEntryForAddress(). - -CW-Bug-Id: #19827 - -To be dropped once we have module search tree implementation. ---- - dlls/ntdll/loader.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c -index a1e5c8acd07..10201aa586d 100644 ---- a/dlls/ntdll/loader.c -+++ b/dlls/ntdll/loader.c -@@ -1733,10 +1733,10 @@ NTSTATUS WINAPI LdrFindEntryForAddress( const void *addr, PLDR_DATA_TABLE_ENTRY - PLIST_ENTRY mark, entry; - PLDR_DATA_TABLE_ENTRY mod; - -- mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; -- for (entry = mark->Flink; entry != mark; entry = entry->Flink) -+ mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList; -+ for (entry = mark->Blink; entry != mark; entry = entry->Blink) - { -- mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); -+ mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - if (mod->DllBase <= addr && - (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage) - { diff --git a/patches/proton/68-proton-tabtip-uiautomationcore.patch b/patches/proton/68-proton-tabtip-uiautomationcore.patch deleted file mode 100644 index 97b6c93f0..000000000 --- a/patches/proton/68-proton-tabtip-uiautomationcore.patch +++ /dev/null @@ -1,13462 +0,0 @@ -From 7440c4f31475e7c6d4676d99e9fc9006165c55b3 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 13 Dec 2021 10:57:27 -0500 -Subject: [PATCH] uiautomationcore: Add more UI Automation interface - definitions. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - include/uiautomationclient.idl | 1336 ++++++++++++++++++++++++++++++++ - include/uiautomationcore.idl | 136 ++++ - 2 files changed, 1472 insertions(+) - -diff --git a/include/uiautomationclient.idl b/include/uiautomationclient.idl -index 917d3456ebf..0079f5316b9 100644 ---- a/include/uiautomationclient.idl -+++ b/include/uiautomationclient.idl -@@ -19,6 +19,37 @@ - #define DO_NO_IMPORTS - import "uiautomationcore.idl"; - -+cpp_quote( "#ifndef _INC_UIAUTOMATIONCOREAPI" ) -+ -+enum TreeScope { -+ TreeScope_Element = 0x01, -+ TreeScope_Children = 0x02, -+ TreeScope_Descendants = 0x04, -+ TreeScope_Parent = 0x08, -+ TreeScope_Ancestors = 0x10, -+ TreeScope_SubTree = TreeScope_Element | TreeScope_Children | TreeScope_Descendants, -+}; -+ -+enum PropertyConditionFlags { -+ PropertyConditionFlags_None = 0x00, -+ PropertyConditionFlags_IgnoreCase = 0x01, -+}; -+ -+enum AutomationElementMode { -+ AutomationElementMode_None = 0x00, -+ AutomationElementMode_Full = 0x01, -+}; -+ -+cpp_quote( "#endif" ) -+ -+struct ExtendedProperty -+{ -+ BSTR PropertyName; -+ BSTR PropertyValue; -+}; -+ -+typedef HWND UIA_HWND; -+ - [ - uuid(944de083-8fb8-45cf-bcb7-c477acb2f897), - lcid(0), -@@ -70,6 +101,49 @@ library UIAutomationClient { - } - */ - -+ /* FIXME: Uncomment when properly supported in widl -+ [dllname("")] -+ module UIA_EventIds -+ { -+ */ -+ const long UIA_ToolTipOpenedEventId = 20000; -+ const long UIA_ToolTipClosedEventId = 20001; -+ const long UIA_StructureChangedEventId = 20002; -+ const long UIA_MenuOpenedEventId = 20003; -+ const long UIA_AutomationPropertyChangedEventId = 20004; -+ const long UIA_AutomationFocusChangedEventId = 20005; -+ const long UIA_AsyncContentLoadedEventId = 20006; -+ const long UIA_MenuClosedEventId = 20007; -+ const long UIA_LayoutInvalidatedEventId = 20008; -+ const long UIA_Invoke_InvokedEventId = 20009; -+ const long UIA_SelectionItem_ElementAddedToSelectionEventId = 20010; -+ const long UIA_SelectionItem_ElementRemovedFromSelectionEventId = 20011; -+ const long UIA_SelectionItem_ElementSelectedEventId= 20012; -+ const long UIA_Selection_InvalidatedEventId = 20013; -+ const long UIA_Text_TextSelectionChangedEventId = 20014; -+ const long UIA_Text_TextChangedEventId = 20015; -+ const long UIA_Window_WindowOpenedEventId = 20016; -+ const long UIA_Window_WindowClosedEventId = 20017; -+ const long UIA_MenuModeStartEventId = 20018; -+ const long UIA_MenuModeEndEventId = 20019; -+ const long UIA_InputReachedTargetEventId = 20020; -+ const long UIA_InputReachedOtherElementEventId = 20021; -+ const long UIA_InputDiscardedEventId = 20022; -+ const long UIA_SystemAlertEventId = 20023; -+ const long UIA_LiveRegionChangedEventId = 20024; -+ const long UIA_HostedFragmentRootsInvalidatedEventId = 20025; -+ const long UIA_Drag_DragStartEventId = 20026; -+ const long UIA_Drag_DragCancelEventId = 20027; -+ const long UIA_Drag_DragCompleteEventId = 20028; -+ const long UIA_DropTarget_DragEnterEventId = 20029; -+ const long UIA_DropTarget_DragLeaveEventId = 20030; -+ const long UIA_DropTarget_DroppedEventId = 20031; -+ const long UIA_TextEdit_TextChangedEventId = 20032; -+ const long UIA_TextEdit_ConversionTargetChangedEventId = 20033; -+ /* -+ }; -+ */ -+ - /* FIXME: Uncomment when properly supported in widl - [dllname("")] - module UIA_PropertyIds -@@ -253,4 +327,1266 @@ library UIAutomationClient { - /* - } - */ -+ -+ /* FIXME: Uncomment when properly supported in widl -+ [dllname("")] -+ module UIA_ControlTypeIds -+ { -+ */ -+ const long UIA_ButtonControlTypeId = 50000; -+ const long UIA_CalendarControlTypeId = 50001; -+ const long UIA_CheckBoxControlTypeId = 50002; -+ const long UIA_ComboBoxControlTypeId = 50003; -+ const long UIA_EditControlTypeId = 50004; -+ const long UIA_HyperlinkControlTypeId = 50005; -+ const long UIA_ImageControlTypeId = 50006; -+ const long UIA_ListItemControlTypeId = 50007; -+ const long UIA_ListControlTypeId = 50008; -+ const long UIA_MenuControlTypeId = 50009; -+ const long UIA_MenuBarControlTypeId = 50010; -+ const long UIA_MenuItemControlTypeId = 50011; -+ const long UIA_ProgressBarControlTypeId = 50012; -+ const long UIA_RadioButtonControlTypeId = 50013; -+ const long UIA_ScrollBarControlTypeId = 50014; -+ const long UIA_SliderControlTypeId = 50015; -+ const long UIA_SpinnerControlTypeId = 50016; -+ const long UIA_StatusBarControlTypeId = 50017; -+ const long UIA_TabControlTypeId = 50018; -+ const long UIA_TabItemControlTypeId = 50019; -+ const long UIA_TextControlTypeId = 50020; -+ const long UIA_ToolBarControlTypeId = 50021; -+ const long UIA_ToolTipControlTypeId = 50022; -+ const long UIA_TreeControlTypeId = 50023; -+ const long UIA_TreeItemControlTypeId = 50024; -+ const long UIA_CustomControlTypeId = 50025; -+ const long UIA_GroupControlTypeId = 50026; -+ const long UIA_ThumbControlTypeId = 50027; -+ const long UIA_DataGridControlTypeId = 50028; -+ const long UIA_DataItemControlTypeId = 50029; -+ const long UIA_DocumentControlTypeId = 50030; -+ const long UIA_SplitButtonControlTypeId = 50031; -+ const long UIA_WindowControlTypeId = 50032; -+ const long UIA_PaneControlTypeId = 50033; -+ const long UIA_HeaderControlTypeId = 50034; -+ const long UIA_HeaderItemControlTypeId = 50035; -+ const long UIA_TableControlTypeId = 50036; -+ const long UIA_TitleBarControlTypeId = 50037; -+ const long UIA_SeparatorControlTypeId = 50038; -+ const long UIA_SemanticZoomControlTypeId = 50039; -+ const long UIA_AppBarControlTypeId = 50040; -+ /* -+ }; -+ */ -+ interface IUIAutomationElement; -+ interface IUIAutomationElementArray; -+ -+ [ -+ object, -+ uuid(352ffba8-0973-437c-a61f-f64cafd81df9), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationCondition : IUnknown { } -+ -+ [ -+ object, -+ uuid(1b4e1f2e-75eb-4d0b-8952-5a69988e2307), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationBoolCondition : IUIAutomationCondition { -+ [propget]HRESULT BooleanValue([out, retval]BOOL *boolVal); -+ } -+ -+ [ -+ object, -+ uuid(99ebf2cb-5578-4267-9ad4-afd6ea77e94b), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationPropertyCondition : IUIAutomationCondition { -+ [propget]HRESULT PropertyId([out, retval]PROPERTYID *propertyId); -+ [propget]HRESULT PropertyValue([out, retval]VARIANT *propertyValue); -+ [propget]HRESULT PropertyConditionFlags([out, retval]enum PropertyConditionFlags *flags); -+ } -+ -+ [ -+ object, -+ uuid(a7d0af36-b912-45fe-9855-091ddc174aec), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationAndCondition : IUIAutomationCondition { -+ [propget]HRESULT ChildCount(int *childCount); -+ -+ HRESULT GetChildrenAsNativeArray([out, size_is( ,*childArrayCount)]IUIAutomationCondition ***childArray, -+ [out]int *childArrayCount); -+ -+ HRESULT GetChildren([out, retval]SAFEARRAY(IUIAutomationCondition) *childArray); -+ } -+ -+ [ -+ object, -+ uuid(8753f032-3db1-47b5-a1fc-6e34a266c712), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationOrCondition : IUIAutomationCondition { -+ [propget]HRESULT ChildCount([out, retval]int *childCount); -+ -+ HRESULT GetChildrenAsNativeArray([out, size_is( ,*childArrayCount)]IUIAutomationCondition ***childArray, -+ [out]int *childArrayCount); -+ -+ HRESULT GetChildren([out, retval]SAFEARRAY(IUIAutomationCondition) *childArray); -+ } -+ -+ [ -+ object, -+ uuid(f528b657-847b-498c-8896-d52b565407a1), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationNotCondition : IUIAutomationCondition { -+ HRESULT GetChild([out, retval]IUIAutomationCondition **condition); -+ } -+ -+ [ -+ object, -+ uuid(b32a92b5-bc25-4078-9c08-d7ee95c48e03), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationCacheRequest : IUnknown { -+ HRESULT AddProperty([in]PROPERTYID propertyId); -+ HRESULT AddPattern([in]PATTERNID patternId); -+ HRESULT Clone([out, retval]IUIAutomationCacheRequest **clonedRequest); -+ -+ [propget]HRESULT TreeScope([out, retval]enum TreeScope *scope); -+ [propput]HRESULT TreeScope([in]enum TreeScope scope); -+ [propget]HRESULT TreeFilter([out, retval]IUIAutomationCondition **filter); -+ [propput]HRESULT TreeFilter([in]IUIAutomationCondition *filter); -+ [propget]HRESULT AutomationElementMode([out, retval]enum AutomationElementMode *mode); -+ [propput]HRESULT AutomationElementMode([in]enum AutomationElementMode mode); -+ } -+ -+ [ -+ object, -+ uuid(4042c624-389c-4afc-a630-9df854a541fc), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTreeWalker : IUnknown { -+ HRESULT GetParentElement([in]IUIAutomationElement *element, -+ [out, retval]IUIAutomationElement **parent); -+ -+ HRESULT GetFirstChildElement([in]IUIAutomationElement *element, -+ [out, retval]IUIAutomationElement **first); -+ -+ HRESULT GetLastChildElement([in]IUIAutomationElement *element, -+ [out, retval]IUIAutomationElement **last); -+ -+ HRESULT GetNextSiblingElement([in]IUIAutomationElement *element, -+ [out, retval]IUIAutomationElement **next); -+ -+ HRESULT GetPreviousSiblingElement([in]IUIAutomationElement *element, -+ [out, retval]IUIAutomationElement **previous); -+ -+ HRESULT NormalizeElement([in]IUIAutomationElement *element, -+ [out, retval]IUIAutomationElement **normalized); -+ -+ HRESULT GetParentElementBuildCache([in]IUIAutomationElement *element, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **parent); -+ -+ HRESULT GetFirstChildElementBuildCache([in]IUIAutomationElement *element, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **first); -+ -+ HRESULT GetLastChildElementBuildCache([in]IUIAutomationElement *element, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **last); -+ -+ HRESULT GetNextSiblingElementBuildCache([in]IUIAutomationElement *element, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **next); -+ -+ HRESULT GetPreviousSiblingElementBuildCache([in]IUIAutomationElement *element, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **previous); -+ -+ HRESULT NormalizeElementBuildCache([in]IUIAutomationElement *element, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **normalized); -+ -+ [propget]HRESULT Condition([out, retval]IUIAutomationCondition **condition); -+ } -+ -+ [ -+ object, -+ uuid(146c3c17-f12e-4e22-8c27-f894b9b79c69), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IUIAutomationEventHandler : IUnknown { -+ HRESULT HandleAutomationEvent([in]IUIAutomationElement *sender, -+ [in]EVENTID eventId); -+ } -+ -+ [ -+ object, -+ uuid(40cd37d4-c756-4b0c-8c6f-bddfeeb13b50), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IUIAutomationPropertyChangedEventHandler : IUnknown { -+ HRESULT HandlePropertyChangedEvent([in]IUIAutomationElement *sender, -+ [in]PROPERTYID propertyId, -+ [in]VARIANT newValue); -+ } -+ -+ [ -+ object, -+ uuid(e81d1b4e-11c5-42f8-9754-e7036c79f054), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IUIAutomationStructureChangedEventHandler : IUnknown { -+ HRESULT HandleStructureChangedEvent([in]IUIAutomationElement *sender, -+ [in]enum StructureChangeType changeType, -+ [in]SAFEARRAY(int) runtimeId); -+ } -+ -+ [ -+ object, -+ uuid(c270f6b5-5c69-4290-9745-7a7f97169468), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IUIAutomationFocusChangedEventHandler : IUnknown { -+ HRESULT HandleFocusChangedEvent([in]IUIAutomationElement *sender); -+ } -+ -+ [ -+ object, -+ uuid(92FAA680-E704-4156-931A-E32D5BB38F3F), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IUIAutomationTextEditTextChangedEventHandler : IUnknown { -+ HRESULT HandleTextEditTextChangedEvent([in]IUIAutomationElement *sender, -+ [in]enum TextEditChangeType textEditChangeType, -+ [in]SAFEARRAY(BSTR) eventStrings); -+ } -+ -+ [ -+ object, -+ uuid(58EDCA55-2C3E-4980-B1B9-56C17F27A2A0), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IUIAutomationChangesEventHandler : IUnknown { -+ HRESULT HandleChangesEvent([in]IUIAutomationElement *sender, -+ [in, size_is(changesCount)]struct UiaChangeInfo *uiaChanges, -+ [in]int changesCount); -+ } -+ -+ [ -+ object, -+ uuid(fb377fbe-8ea6-46d5-9c73-6499642d3059), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationInvokePattern : IUnknown { -+ HRESULT Invoke(); -+ } -+ -+ [ -+ object, -+ uuid(fde5ef97-1464-48f6-90bf-43d0948e86ec), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationDockPattern : IUnknown { -+ HRESULT SetDockPosition([in]enum DockPosition dockPos); -+ -+ [propget]HRESULT CurrentDockPosition([out, retval]enum DockPosition *retVal); -+ [propget]HRESULT CachedDockPosition([out, retval]enum DockPosition *retVal); -+ } -+ -+ [ -+ object, -+ uuid(619be086-1f4e-4ee4-bafa-210128738730), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationExpandCollapsePattern : IUnknown { -+ HRESULT Expand(); -+ HRESULT Collapse(); -+ -+ [propget]HRESULT CurrentExpandCollapseState([out, retval]enum ExpandCollapseState *retVal); -+ [propget]HRESULT CachedExpandCollapseState([out, retval]enum ExpandCollapseState *retVal); -+ } -+ -+ [ -+ object, -+ uuid(414c3cdc-856b-4f5b-8538-3131c6302550), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationGridPattern : IUnknown { -+ HRESULT GetItem([in]int row, -+ [in]int column, -+ [out, retval]IUIAutomationElement **element); -+ -+ [propget]HRESULT CurrentRowCount([out, retval]int *retVal); -+ [propget]HRESULT CurrentColumnCount([out, retval]int *retVal); -+ [propget]HRESULT CachedRowCount([out, retval]int *retVal); -+ [propget]HRESULT CachedColumnCount([out, retval]int *retVal); -+ } -+ -+ [ -+ object, -+ uuid(78f8ef57-66c3-4e09-bd7c-e79b2004894d), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationGridItemPattern : IUnknown { -+ [propget]HRESULT CurrentContainingGrid([out, retval]IUIAutomationElement **retVal); -+ [propget]HRESULT CurrentRow([out, retval]int *retVal); -+ [propget]HRESULT CurrentColumn([out, retval]int *retVal); -+ [propget]HRESULT CurrentRowSpan([out, retval]int *retVal); -+ [propget]HRESULT CurrentColumnSpan([out, retval]int *retVal); -+ [propget]HRESULT CachedContainingGrid([out, retval]IUIAutomationElement **retVal); -+ [propget]HRESULT CachedRow([out, retval]int *retVal); -+ [propget]HRESULT CachedColumn([out, retval]int *retVal); -+ [propget]HRESULT CachedRowSpan([out, retval]int *retVal); -+ [propget]HRESULT CachedColumnSpan([out, retval]int *retVal); -+ } -+ -+ [ -+ object, -+ uuid(8d253c91-1dc5-4bb5-b18f-ade16fa495e8), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationMultipleViewPattern : IUnknown { -+ HRESULT GetViewName([in]int view, -+ [out, retval]BSTR *name); -+ -+ HRESULT SetCurrentView([in]int view); -+ -+ [propget]HRESULT CurrentCurrentView([out, retval]int *retVal); -+ -+ HRESULT GetCurrentSupportedViews([out, retval]SAFEARRAY(int) *retVal); -+ -+ [propget]HRESULT CachedCurrentView([out, retval]int *retVal); -+ -+ HRESULT GetCachedSupportedViews([out, retval]SAFEARRAY(int) *retVal); -+ } -+ -+ [ -+ object, -+ uuid(71c284b3-c14d-4d14-981e-19751b0d756d), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationObjectModelPattern : IUnknown { -+ HRESULT GetUnderlyingObjectModel([out, retval]IUnknown **retVal); -+ } -+ -+ [ -+ object, -+ uuid(59213f4f-7346-49e5-b120-80555987a148), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationRangeValuePattern : IUnknown { -+ HRESULT SetValue([in]double val); -+ -+ [propget]HRESULT CurrentValue([out, retval]double *retVal); -+ [propget]HRESULT CurrentIsReadOnly([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentMaximum([out, retval]double *retVal); -+ [propget]HRESULT CurrentMinimum([out, retval]double *retVal); -+ [propget]HRESULT CurrentLargeChange([out, retval]double *retVal); -+ [propget]HRESULT CurrentSmallChange([out, retval]double *retVal); -+ [propget]HRESULT CachedValue([out, retval]double *retVal); -+ [propget]HRESULT CachedIsReadOnly([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedMaximum([out, retval]double *retVal); -+ [propget]HRESULT CachedMinimum([out, retval]double *retVal); -+ [propget]HRESULT CachedLargeChange([out, retval]double *retVal); -+ [propget]HRESULT CachedSmallChange([out, retval]double *retVal); -+ } -+ -+ [ -+ object, -+ uuid(88f4d42a-e881-459d-a77c-73bbbb7e02dc), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationScrollPattern : IUnknown { -+ HRESULT Scroll([in]enum ScrollAmount horizontalAmount, -+ [in]enum ScrollAmount verticalAmount); -+ -+ HRESULT SetScrollPercent([in]double horizontalPercent, -+ [in]double verticalPercent); -+ -+ [propget]HRESULT CurrentHorizontalScrollPercent ([out, retval]double *retVal); -+ [propget]HRESULT CurrentVerticalScrollPercent ([out, retval]double *retVal); -+ [propget]HRESULT CurrentHorizontalViewSize ([out, retval]double *retVal); -+ [propget]HRESULT CurrentVerticalViewSize ([out, retval]double *retVal); -+ [propget]HRESULT CurrentHorizontallyScrollable ([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentVerticallyScrollable ([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedHorizontalScrollPercent ([out, retval]double *retVal); -+ [propget]HRESULT CachedVerticalScrollPercent ([out, retval]double *retVal); -+ [propget]HRESULT CachedHorizontalViewSize ([out, retval]double *retVal); -+ [propget]HRESULT CachedVerticalViewSize([out, retval]double *retVal); -+ [propget]HRESULT CachedHorizontallyScrollable([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedVerticallyScrollable([out, retval]BOOL *retVal); -+ } -+ -+ [ -+ object, -+ uuid(b488300f-d015-4f19-9c29-bb595e3645ef), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationScrollItemPattern : IUnknown { -+ HRESULT ScrollIntoView(); -+ } -+ -+ [ -+ object, -+ uuid(5ed5202e-b2ac-47a6-b638-4b0bf140d78e), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationSelectionPattern : IUnknown { -+ HRESULT GetCurrentSelection([out, retval]IUIAutomationElementArray **retVal); -+ -+ [propget]HRESULT CurrentCanSelectMultiple([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentIsSelectionRequired([out, retval]BOOL *retVal); -+ -+ HRESULT GetCachedSelection([out, retval]IUIAutomationElementArray **retVal); -+ -+ [propget]HRESULT CachedCanSelectMultiple([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedIsSelectionRequired([out, retval]BOOL *retVal); -+ } -+ -+ [ -+ object, -+ uuid(a8efa66a-0fda-421a-9194-38021f3578ea), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationSelectionItemPattern : IUnknown { -+ HRESULT Select(); -+ HRESULT AddToSelection(); -+ HRESULT RemoveFromSelection(); -+ -+ [propget]HRESULT CurrentIsSelected([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentSelectionContainer([out, retval]IUIAutomationElement **retVal); -+ [propget]HRESULT CachedIsSelected([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedSelectionContainer([out, retval]IUIAutomationElement **retVal); -+ } -+ -+ [ -+ object, -+ uuid(2233be0b-afb7-448b-9fda-3b378aa5eae1), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationSynchronizedInputPattern : IUnknown { -+ HRESULT StartListening([in]enum SynchronizedInputType inputType); -+ HRESULT Cancel(); -+ } -+ -+ [ -+ object, -+ uuid(620e691c-ea96-4710-a850-754b24ce2417), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTablePattern : IUnknown { -+ HRESULT GetCurrentRowHeaders([out, retval]IUIAutomationElementArray **retVal); -+ HRESULT GetCurrentColumnHeaders([out, retval]IUIAutomationElementArray **retVal); -+ -+ [propget]HRESULT CurrentRowOrColumnMajor([out, retval]enum RowOrColumnMajor *retVal); -+ -+ HRESULT GetCachedRowHeaders([out, retval]IUIAutomationElementArray **retVal); -+ HRESULT GetCachedColumnHeaders([out, retval]IUIAutomationElementArray **retVal); -+ -+ [propget]HRESULT CachedRowOrColumnMajor([out, retval]enum RowOrColumnMajor *retVal); -+ } -+ -+ [ -+ object, -+ uuid(0b964eb3-ef2e-4464-9c79-61d61737a27e), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTableItemPattern : IUnknown { -+ HRESULT GetCurrentRowHeaderItems([out, retval]IUIAutomationElementArray **retVal); -+ HRESULT GetCurrentColumnHeaderItems([out, retval]IUIAutomationElementArray **retVal); -+ HRESULT GetCachedRowHeaderItems([out, retval]IUIAutomationElementArray **retVal); -+ HRESULT GetCachedColumnHeaderItems([out, retval]IUIAutomationElementArray **retVal); -+ } -+ -+ [ -+ object, -+ uuid(94cf8058-9b8d-4ab9-8bfd-4cd0a33c8c70), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTogglePattern : IUnknown { -+ HRESULT Toggle(); -+ -+ [propget]HRESULT CurrentToggleState([out, retval]enum ToggleState *retVal); -+ [propget]HRESULT CachedToggleState([out, retval]enum ToggleState *retVal); -+ } -+ -+ [ -+ object, -+ uuid(a9b55844-a55d-4ef0-926d-569c16ff89bb), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTransformPattern : IUnknown { -+ HRESULT Move([in]double x, [in]double y); -+ HRESULT Resize([in]double width, [in]double height); -+ HRESULT Rotate([in]double degrees); -+ -+ [propget]HRESULT CurrentCanMove([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentCanResize([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentCanRotate([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedCanMove([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedCanResize([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedCanRotate([out, retval]BOOL *retVal); -+ } -+ -+ [ -+ object, -+ uuid(a94cd8b1-0844-4cd6-9d2d-640537ab39e9), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationValuePattern : IUnknown { -+ HRESULT SetValue([in]BSTR val); -+ -+ [propget]HRESULT CurrentValue([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentIsReadOnly([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedValue([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedIsReadOnly([out, retval]BOOL *retVal); -+ } -+ -+ [ -+ object, -+ uuid(0faef453-9208-43ef-bbb2-3b485177864f), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationWindowPattern : IUnknown { -+ HRESULT Close(); -+ HRESULT WaitForInputIdle([in]int milliseconds, -+ [out, retval]BOOL *success); -+ HRESULT SetWindowVisualState([in]enum WindowVisualState state); -+ -+ [propget]HRESULT CurrentCanMaximize([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentCanMinimize([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentIsModal([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentIsTopmost([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentWindowVisualState([out, retval]enum WindowVisualState *retVal); -+ [propget]HRESULT CurrentWindowInteractionState([out, retval]enum WindowInteractionState *retVal); -+ [propget]HRESULT CachedCanMaximize([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedCanMinimize([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedIsModal([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedIsTopmost([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedWindowVisualState([out, retval]enum WindowVisualState *retVal); -+ [propget]HRESULT CachedWindowInteractionState([out, retval]enum WindowInteractionState *retVal); -+ } -+ -+ [ -+ object, -+ uuid(a543cc6a-f4ae-494b-8239-c814481187a8), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTextRange : IUnknown { -+ HRESULT Clone([out, retval]IUIAutomationTextRange **clonedRange); -+ HRESULT Compare([in]IUIAutomationTextRange *range, [out, retval]BOOL *areSame); -+ HRESULT CompareEndpoints([in]enum TextPatternRangeEndpoint srcEndPoint, -+ [in]IUIAutomationTextRange *range, -+ [in]enum TextPatternRangeEndpoint targetEndPoint, -+ [out, retval]int *compValue); -+ HRESULT ExpandToEnclosingUnit([in]enum TextUnit textUnit); -+ -+ HRESULT FindAttribute([in]TEXTATTRIBUTEID attr, -+ [in]VARIANT val, -+ [in]BOOL backward, -+ [out, retval]IUIAutomationTextRange **found); -+ -+ HRESULT FindText([in]BSTR text, -+ [in]BOOL backward, -+ [in]BOOL ignoreCase, -+ [out, retval]IUIAutomationTextRange **found); -+ -+ HRESULT GetAttributeValue([in]TEXTATTRIBUTEID attr, -+ [out, retval]VARIANT *value); -+ -+ HRESULT GetBoundingRectangles([out, retval]SAFEARRAY(double) *boundingRects); -+ HRESULT GetEnclosingElement([out, retval]IUIAutomationElement **enclosingElement); -+ -+ HRESULT GetText([in]int maxLength, -+ [out, retval]BSTR *text); -+ -+ HRESULT Move([in]enum TextUnit unit, -+ [in]int count, -+ [out, retval]int *moved); -+ -+ HRESULT MoveEndpointByUnit([in]enum TextPatternRangeEndpoint endpoint, -+ [in]enum TextUnit unit, -+ [in]int count, -+ [out, retval]int *moved); -+ -+ HRESULT MoveEndpointByRange([in]enum TextPatternRangeEndpoint srcEndPoint, -+ [in]IUIAutomationTextRange *range, -+ [in]enum TextPatternRangeEndpoint targetEndPoint); -+ -+ HRESULT Select(); -+ HRESULT AddToSelection(); -+ HRESULT RemoveFromSelection(); -+ HRESULT ScrollIntoView([in]BOOL alignToTop); -+ HRESULT GetChildren([out, retval]IUIAutomationElementArray **children); -+ } -+ -+ [ -+ object, -+ uuid(BB9B40E0-5E04-46BD-9BE0-4B601B9AFAD4), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTextRange2 : IUIAutomationTextRange { -+ HRESULT ShowContextMenu(); -+ } -+ -+ [ -+ object, -+ uuid(ce4ae76a-e717-4c98-81ea-47371d028eb6), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTextRangeArray : IUnknown { -+ [propget]HRESULT Length([out, retval]int *length); -+ -+ HRESULT GetElement([in]int index, -+ [out, retval]IUIAutomationTextRange **element); -+ } -+ -+ [ -+ object, -+ uuid(32eba289-3583-42c9-9c59-3b6d9a1e9b6a), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTextPattern : IUnknown { -+ HRESULT RangeFromPoint([in]POINT pt, -+ [out, retval]IUIAutomationTextRange **range); -+ -+ HRESULT RangeFromChild([in]IUIAutomationElement *child, -+ [out, retval]IUIAutomationTextRange **range); -+ -+ HRESULT GetSelection([out, retval]IUIAutomationTextRangeArray **ranges); -+ HRESULT GetVisibleRanges([out, retval]IUIAutomationTextRangeArray **ranges); -+ -+ [propget]HRESULT DocumentRange([out, retval]IUIAutomationTextRange **range); -+ [propget]HRESULT SupportedTextSelection([out, retval]enum SupportedTextSelection *supportedTextSelection); -+ } -+ -+ [ -+ object, -+ uuid(506a921a-fcc9-409f-b23b-37eb74106872), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTextPattern2 : IUIAutomationTextPattern { -+ HRESULT RangeFromAnnotation([in]IUIAutomationElement *annotation, -+ [out, retval]IUIAutomationTextRange **range); -+ -+ HRESULT GetCaretRange([out]BOOL *isActive, -+ [out, retval]IUIAutomationTextRange **range); -+ } -+ -+ [ -+ object, -+ uuid(17E21576-996C-4870-99D9-BFF323380C06), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTextEditPattern : IUIAutomationTextPattern { -+ HRESULT GetActiveComposition([out, retval]IUIAutomationTextRange **range); -+ HRESULT GetConversionTarget([out, retval]IUIAutomationTextRange **range); -+ } -+ -+ [ -+ object, -+ uuid(01EA217A-1766-47ED-A6CC-ACF492854B1F), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationCustomNavigationPattern : IUnknown { -+ HRESULT Navigate([in]enum NavigateDirection direction, -+ [out, retval]IUIAutomationElement **pRetVal); -+ } -+ -+ [ -+ object, -+ uuid(828055ad-355b-4435-86d5-3b51c14a9b1b), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationLegacyIAccessiblePattern: IUnknown { -+ HRESULT Select (long flagsSelect); -+ HRESULT DoDefaultAction(); -+ HRESULT SetValue(LPCWSTR szValue); -+ -+ [propget]HRESULT CurrentChildId([out, retval]int *pRetVal); -+ [propget]HRESULT CurrentName([out, retval]BSTR *pszName); -+ [propget]HRESULT CurrentValue([out, retval]BSTR *pszValue); -+ [propget]HRESULT CurrentDescription([out, retval]BSTR *pszDescription); -+ [propget]HRESULT CurrentRole([out, retval]DWORD *pdwRole); -+ [propget]HRESULT CurrentState([out, retval]DWORD *pdwState); -+ [propget]HRESULT CurrentHelp([out, retval]BSTR *pszHelp); -+ [propget]HRESULT CurrentKeyboardShortcut([out, retval]BSTR *pszKeyboardShortcut); -+ -+ HRESULT GetCurrentSelection([out, retval]IUIAutomationElementArray **pvarSelectedChildren); -+ -+ [propget]HRESULT CurrentDefaultAction([out, retval]BSTR *pszDefaultAction); -+ [propget]HRESULT CachedChildId([out, retval]int *pRetVal); -+ [propget]HRESULT CachedName([out, retval]BSTR *pszName); -+ [propget]HRESULT CachedValue([out, retval]BSTR *pszValue); -+ [propget]HRESULT CachedDescription([out, retval]BSTR *pszDescription); -+ [propget]HRESULT CachedRole([out, retval]DWORD *pdwRole); -+ [propget]HRESULT CachedState([out, retval]DWORD *pdwState); -+ [propget]HRESULT CachedHelp([out, retval]BSTR *pszHelp); -+ [propget]HRESULT CachedKeyboardShortcut([out, retval]BSTR *pszKeyboardShortcut); -+ -+ HRESULT GetCachedSelection([out, retval]IUIAutomationElementArray **pvarSelectedChildren); -+ -+ [propget]HRESULT CachedDefaultAction([out, retval]BSTR *pszDefaultAction); -+ -+ HRESULT GetIAccessible([out, retval]IAccessible **ppAccessible); -+ }; -+ -+ [ -+ object, -+ uuid(c690fdb2-27a8-423c-812d-429773c9084e), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationItemContainerPattern : IUnknown { -+ HRESULT FindItemByProperty([in]IUIAutomationElement *pStartAfter, -+ [in]PROPERTYID propertyId, -+ [in]VARIANT value, -+ [out, retval]IUIAutomationElement **pFound); -+ }; -+ -+ [ -+ object, -+ uuid(6ba3d7a6-04cf-4f11-8793-a8d1cde9969f), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationVirtualizedItemPattern : IUnknown { -+ HRESULT Realize(); -+ }; -+ -+ [ -+ object, -+ uuid(9a175b21-339e-41b1-8e8b-623f6b681098), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationAnnotationPattern : IUnknown { -+ [propget]HRESULT CurrentAnnotationTypeId([out, retval]int *retVal); -+ [propget]HRESULT CurrentAnnotationTypeName([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentAuthor([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentDateTime([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentTarget([out, retval]IUIAutomationElement **retVal); -+ [propget]HRESULT CachedAnnotationTypeId([out, retval]int *retVal); -+ [propget]HRESULT CachedAnnotationTypeName([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedAuthor([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedDateTime([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedTarget([out, retval]IUIAutomationElement **retVal); -+ }; -+ -+ [ -+ object, -+ uuid(85b5f0a2-bd79-484a-ad2b-388c9838d5fb), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationStylesPattern : IUnknown { -+ [propget]HRESULT CurrentStyleId([out, retval]int *retVal); -+ [propget]HRESULT CurrentStyleName([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentFillColor([out, retval]int *retVal); -+ [propget]HRESULT CurrentFillPatternStyle([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentShape([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentFillPatternColor([out, retval]int *retVal); -+ [propget]HRESULT CurrentExtendedProperties([out, retval]BSTR *retVal); -+ -+ HRESULT GetCurrentExtendedPropertiesAsArray([out, size_is( , *propertyCount)]struct ExtendedProperty **propertyArray, -+ [out]int *propertyCount); -+ -+ [propget]HRESULT CachedStyleId([out, retval]int *retVal); -+ [propget]HRESULT CachedStyleName([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedFillColor([out, retval]int *retVal); -+ [propget]HRESULT CachedFillPatternStyle([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedShape([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedFillPatternColor([out, retval]int *retVal); -+ [propget]HRESULT CachedExtendedProperties([out, retval]BSTR *retVal); -+ -+ HRESULT GetCachedExtendedPropertiesAsArray([out, size_is( , *propertyCount)]struct ExtendedProperty **propertyArray, -+ [out]int *propertyCount); -+ }; -+ -+ [ -+ object, -+ uuid(7517a7c8-faae-4de9-9f08-29b91e8595c1), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationSpreadsheetPattern : IUnknown { -+ HRESULT GetItemByName([in]BSTR name, -+ [out, retval]IUIAutomationElement **element); -+ }; -+ -+ [ -+ object, -+ uuid(7d4fb86c-8d34-40e1-8e83-62c15204e335), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationSpreadsheetItemPattern : IUnknown { -+ [propget]HRESULT CurrentFormula([out, retval]BSTR *retVal); -+ -+ HRESULT GetCurrentAnnotationObjects([out, retval]IUIAutomationElementArray **retVal); -+ HRESULT GetCurrentAnnotationTypes([out, retval]SAFEARRAY(int) *retVal); -+ -+ [propget]HRESULT CachedFormula([out, retval]BSTR *retVal); -+ -+ HRESULT GetCachedAnnotationObjects([out, retval]IUIAutomationElementArray **retVal); -+ HRESULT GetCachedAnnotationTypes([out, retval]SAFEARRAY(int) *retVal); -+ }; -+ -+ [ -+ object, -+ uuid(6d74d017-6ecb-4381-b38b-3c17a48ff1c2), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTransformPattern2 : IUIAutomationTransformPattern { -+ HRESULT Zoom([in]double zoomValue); -+ HRESULT ZoomByUnit([in]enum ZoomUnit zoomUnit); -+ -+ [propget]HRESULT CurrentCanZoom([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedCanZoom([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentZoomLevel([out, retval]double *retVal); -+ [propget]HRESULT CachedZoomLevel([out, retval]double *retVal); -+ [propget]HRESULT CurrentZoomMinimum([out, retval]double *retVal); -+ [propget]HRESULT CachedZoomMinimum([out, retval]double *retVal); -+ [propget]HRESULT CurrentZoomMaximum([out, retval]double *retVal); -+ [propget]HRESULT CachedZoomMaximum([out, retval]double *retVal); -+ } -+ -+ [ -+ object, -+ uuid(6552b038-ae05-40c8-abfd-aa08352aab86), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationTextChildPattern : IUnknown { -+ [propget]HRESULT TextContainer([out, retval]IUIAutomationElement **container); -+ [propget]HRESULT TextRange([out, retval]IUIAutomationTextRange **range); -+ } -+ -+ [ -+ object, -+ uuid(1dc7b570-1f54-4bad-bcda-d36a722fb7bd), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationDragPattern : IUnknown { -+ [propget]HRESULT CurrentIsGrabbed([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedIsGrabbed([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentDropEffect([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedDropEffect([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentDropEffects([out, retval]SAFEARRAY(BSTR) *retVal); -+ [propget]HRESULT CachedDropEffects([out, retval]SAFEARRAY(BSTR) *retVal); -+ -+ HRESULT GetCurrentGrabbedItems([out, retval]IUIAutomationElementArray **retVal); -+ HRESULT GetCachedGrabbedItems([out, retval]IUIAutomationElementArray **retVal); -+ } -+ -+ [ -+ object, -+ uuid(69a095f7-eee4-430e-a46b-fb73b1ae39a5), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationDropTargetPattern : IUnknown { -+ [propget]HRESULT CurrentDropTargetEffect([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedDropTargetEffect([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentDropTargetEffects([out, retval]SAFEARRAY(BSTR) *retVal); -+ [propget]HRESULT CachedDropTargetEffects([out, retval]SAFEARRAY(BSTR) *retVal); -+ } -+ -+ [ -+ object, -+ uuid(d22108aa-8ac5-49a5-837b-37bbb3d7591e), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationElement : IUnknown { -+ HRESULT SetFocus(); -+ HRESULT GetRuntimeId([out, retval]SAFEARRAY(int) *runtimeId); -+ -+ HRESULT FindFirst([in]enum TreeScope scope, -+ [in]IUIAutomationCondition *condition, -+ [out, retval]IUIAutomationElement **found); -+ -+ HRESULT FindAll([in]enum TreeScope scope, -+ [in]IUIAutomationCondition *condition, -+ [out, retval]IUIAutomationElementArray **found); -+ -+ HRESULT FindFirstBuildCache([in]enum TreeScope scope, -+ [in]IUIAutomationCondition *condition, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **found); -+ -+ HRESULT FindAllBuildCache([in]enum TreeScope scope, -+ [in]IUIAutomationCondition *condition, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElementArray **found); -+ -+ HRESULT BuildUpdatedCache([in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **updatedElement); -+ -+ HRESULT GetCurrentPropertyValue([in]PROPERTYID propertyId, -+ [out, retval]VARIANT *retVal); -+ -+ HRESULT GetCurrentPropertyValueEx([in]PROPERTYID propertyId, -+ [in]BOOL ignoreDefaultValue, -+ [out, retval]VARIANT *retVal); -+ -+ HRESULT GetCachedPropertyValue([in]PROPERTYID propertyId, -+ [out, retval]VARIANT *retVal); -+ -+ HRESULT GetCachedPropertyValueEx([in]PROPERTYID propertyId, -+ [in]BOOL ignoreDefaultValue, -+ [out, retval]VARIANT *retVal); -+ -+ HRESULT GetCurrentPatternAs([in]PATTERNID patternId, -+ [in]REFIID riid, -+ [out, iid_is(riid), retval]void **patternObject); -+ -+ HRESULT GetCachedPatternAs([in]PATTERNID patternId, -+ [in]REFIID riid, -+ [out, iid_is(riid), retval]void **patternObject); -+ -+ HRESULT GetCurrentPattern([in]PATTERNID patternId, -+ [out, retval]IUnknown **patternObject); -+ -+ HRESULT GetCachedPattern([in]PATTERNID patternId, -+ [out, retval]IUnknown **patternObject); -+ -+ HRESULT GetCachedParent([out, retval]IUIAutomationElement **parent); -+ HRESULT GetCachedChildren([out, retval]IUIAutomationElementArray **children); -+ -+ [propget]HRESULT CurrentProcessId([out, retval]int *retVal); -+ [propget]HRESULT CurrentControlType([out, retval]CONTROLTYPEID *retVal); -+ [propget]HRESULT CurrentLocalizedControlType([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentName([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentAcceleratorKey([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentAccessKey([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentHasKeyboardFocus([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentIsKeyboardFocusable([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentIsEnabled([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentAutomationId([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentClassName([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentHelpText([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentCulture([out, retval]int *retVal); -+ [propget]HRESULT CurrentIsControlElement([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentIsContentElement([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentIsPassword([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentNativeWindowHandle([out, retval]UIA_HWND *retVal); -+ [propget]HRESULT CurrentItemType([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentIsOffscreen([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentOrientation([out, retval]enum OrientationType *retVal); -+ [propget]HRESULT CurrentFrameworkId([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentIsRequiredForForm([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentItemStatus([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentBoundingRectangle([out, retval]RECT *retVal); -+ [propget]HRESULT CurrentLabeledBy([out, retval]IUIAutomationElement **retVal); -+ [propget]HRESULT CurrentAriaRole([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentAriaProperties([out, retval]BSTR *retVal); -+ [propget]HRESULT CurrentIsDataValidForForm([out, retval]BOOL *retVal); -+ [propget]HRESULT CurrentControllerFor([out, retval]IUIAutomationElementArray **retVal); -+ [propget]HRESULT CurrentDescribedBy([out, retval]IUIAutomationElementArray **retVal); -+ [propget]HRESULT CurrentFlowsTo([out, retval]IUIAutomationElementArray **retVal); -+ [propget]HRESULT CurrentProviderDescription([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedProcessId([out, retval]int *retVal); -+ [propget]HRESULT CachedControlType([out, retval]CONTROLTYPEID *retVal); -+ [propget]HRESULT CachedLocalizedControlType([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedName([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedAcceleratorKey([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedAccessKey([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedHasKeyboardFocus([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedIsKeyboardFocusable([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedIsEnabled([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedAutomationId([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedClassName([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedHelpText([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedCulture([out, retval]int *retVal); -+ [propget]HRESULT CachedIsControlElement([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedIsContentElement([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedIsPassword([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedNativeWindowHandle([out, retval]UIA_HWND *retVal); -+ [propget]HRESULT CachedItemType([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedIsOffscreen([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedOrientation([out, retval]enum OrientationType *retVal); -+ [propget]HRESULT CachedFrameworkId([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedIsRequiredForForm([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedItemStatus([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedBoundingRectangle([out, retval]RECT *retVal); -+ [propget]HRESULT CachedLabeledBy([out, retval]IUIAutomationElement **retVal); -+ [propget]HRESULT CachedAriaRole([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedAriaProperties([out, retval]BSTR *retVal); -+ [propget]HRESULT CachedIsDataValidForForm([out, retval]BOOL *retVal); -+ [propget]HRESULT CachedControllerFor([out, retval]IUIAutomationElementArray **retVal); -+ [propget]HRESULT CachedDescribedBy([out, retval]IUIAutomationElementArray **retVal); -+ [propget]HRESULT CachedFlowsTo([out, retval]IUIAutomationElementArray **retVal); -+ [propget]HRESULT CachedProviderDescription([out, retval]BSTR *retVal); -+ -+ HRESULT GetClickablePoint([out]POINT *clickable, -+ [out, retval]BOOL *gotClickable); -+ } -+ -+ [ -+ object, -+ uuid(14314595-b4bc-4055-95f2-58f2e42c9855), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationElementArray : IUnknown { -+ [propget]HRESULT Length([out, retval]int *length); -+ -+ HRESULT GetElement([in]int index, -+ [out, retval]IUIAutomationElement **element); -+ } -+ -+ [ -+ object, -+ uuid(85b94ecd-849d-42b6-b94d-d6db23fdf5a4), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationProxyFactory : IUnknown { -+ HRESULT CreateProvider([in]UIA_HWND hwnd, -+ [in]LONG idObject, -+ [in]LONG idChild, -+ [out, retval]IRawElementProviderSimple **provider); -+ -+ [propget]HRESULT ProxyFactoryId([out, retval]BSTR *factoryId); -+ } -+ -+ [ -+ object, -+ uuid(d50e472e-b64b-490c-bca1-d30696f9f289), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationProxyFactoryEntry : IUnknown { -+ [propget]HRESULT ProxyFactory([out, retval]IUIAutomationProxyFactory **factory); -+ [propget]HRESULT ClassName([out, retval]BSTR *className); -+ [propget]HRESULT ImageName([out, retval]BSTR *imageName); -+ [propget]HRESULT AllowSubstringMatch([out, retval]BOOL *allowSubstringMatch); -+ [propget]HRESULT CanCheckBaseClass([out, retval]BOOL *canCheckBaseClass); -+ [propget]HRESULT NeedsAdviseEvents([out, retval]BOOL *adviseEvents); -+ [propput]HRESULT ClassName([in]LPCWSTR className); -+ [propput]HRESULT ImageName([in]LPCWSTR imageName); -+ [propput]HRESULT AllowSubstringMatch([in]BOOL allowSubstringMatch); -+ [propput]HRESULT CanCheckBaseClass([in]BOOL canCheckBaseClass); -+ [propput]HRESULT NeedsAdviseEvents([in]BOOL adviseEvents); -+ -+ HRESULT SetWinEventsForAutomationEvent([in]EVENTID eventId, -+ [in]PROPERTYID propertyId, -+ [in]SAFEARRAY(UINT) winEvents); -+ -+ HRESULT GetWinEventsForAutomationEvent([in]EVENTID eventId, -+ [in]PROPERTYID propertyId, -+ [out, retval]SAFEARRAY(UINT) *winEvents); -+ } -+ -+ [ -+ object, -+ uuid(09e31e18-872d-4873-93d1-1e541ec133fd), -+ pointer_default(unique) -+ ] -+ interface IUIAutomationProxyFactoryMapping : IUnknown { -+ [propget]HRESULT Count([out, retval]UINT *count); -+ -+ HRESULT GetTable([out, retval]SAFEARRAY(VARIANT) *table); -+ HRESULT GetEntry([in]UINT index, -+ [out, retval]IUIAutomationProxyFactoryEntry **entry); -+ -+ HRESULT SetTable([in]SAFEARRAY(IUIAutomationProxyFactoryEntry)factoryList); -+ -+ HRESULT InsertEntries(UINT before, -+ [in]SAFEARRAY(IUIAutomationProxyFactoryEntry) factoryList); -+ -+ HRESULT InsertEntry(UINT before, -+ IUIAutomationProxyFactoryEntry *factory); -+ -+ HRESULT RemoveEntry(UINT index); -+ HRESULT ClearTable(); -+ HRESULT RestoreDefaultTable(); -+ } -+ -+ [ -+ object, -+ uuid(30cbe57d-d9d0-452a-ab13-7ac5ac4825ee), -+ pointer_default(unique) -+ ] -+ interface IUIAutomation : IUnknown { -+ HRESULT CompareElements([in]IUIAutomationElement *el1, -+ [in]IUIAutomationElement *el2, -+ [out, retval]BOOL *areSame); -+ -+ HRESULT CompareRuntimeIds([in]SAFEARRAY(int) runtimeId1, -+ [in]SAFEARRAY(int) runtimeId2, -+ [out, retval]BOOL *areSame); -+ -+ HRESULT GetRootElement([out, retval]IUIAutomationElement **root); -+ -+ HRESULT ElementFromHandle([in]UIA_HWND hwnd, -+ [out, retval]IUIAutomationElement **element); -+ -+ HRESULT ElementFromPoint([in]POINT pt, -+ [out, retval]IUIAutomationElement **element); -+ -+ HRESULT GetFocusedElement([out, retval]IUIAutomationElement **element); -+ -+ HRESULT GetRootElementBuildCache([in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **root); -+ -+ HRESULT ElementFromHandleBuildCache([in]UIA_HWND hwnd, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **element); -+ -+ HRESULT ElementFromPointBuildCache([in]POINT pt, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **element); -+ -+ HRESULT GetFocusedElementBuildCache([in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **element); -+ -+ HRESULT CreateTreeWalker([in]IUIAutomationCondition *pCondition, -+ [out, retval]IUIAutomationTreeWalker **walker); -+ -+ [propget]HRESULT ControlViewWalker([out, retval]IUIAutomationTreeWalker **walker); -+ [propget]HRESULT ContentViewWalker([out, retval]IUIAutomationTreeWalker **walker); -+ [propget]HRESULT RawViewWalker([out, retval]IUIAutomationTreeWalker **walker); -+ [propget]HRESULT RawViewCondition([out, retval]IUIAutomationCondition **condition); -+ [propget]HRESULT ControlViewCondition([out, retval]IUIAutomationCondition **condition); -+ [propget]HRESULT ContentViewCondition([out, retval]IUIAutomationCondition **condition); -+ -+ HRESULT CreateCacheRequest([out, retval]IUIAutomationCacheRequest **cacheRequest); -+ HRESULT CreateTrueCondition([out, retval]IUIAutomationCondition **newCondition); -+ HRESULT CreateFalseCondition([out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreatePropertyCondition([in]PROPERTYID propertyId, -+ [in]VARIANT value, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreatePropertyConditionEx([in]PROPERTYID propertyId, -+ [in]VARIANT value, -+ [in]enum PropertyConditionFlags flags, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreateAndCondition([in]IUIAutomationCondition *condition1, -+ [in]IUIAutomationCondition *condition2, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreateAndConditionFromArray([in]SAFEARRAY(IUIAutomationCondition) conditions, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreateAndConditionFromNativeArray([in, size_is(conditionCount)]IUIAutomationCondition **conditions, -+ [in]int conditionCount, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreateOrCondition([in]IUIAutomationCondition *condition1, -+ [in]IUIAutomationCondition *condition2, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreateOrConditionFromArray([in]SAFEARRAY(IUIAutomationCondition) conditions, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreateOrConditionFromNativeArray([in, size_is(conditionCount)]IUIAutomationCondition **conditions, -+ [in]int conditionCount, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT CreateNotCondition([in]IUIAutomationCondition *condition, -+ [out, retval]IUIAutomationCondition **newCondition); -+ -+ HRESULT AddAutomationEventHandler([in]EVENTID eventId, -+ [in]IUIAutomationElement *element, -+ [in]enum TreeScope scope, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [in]IUIAutomationEventHandler *handler); -+ -+ HRESULT RemoveAutomationEventHandler([in]EVENTID eventId, -+ [in]IUIAutomationElement *element, -+ [in]IUIAutomationEventHandler *handler); -+ -+ HRESULT AddPropertyChangedEventHandlerNativeArray([in]IUIAutomationElement *element, -+ [in]enum TreeScope scope, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [in]IUIAutomationPropertyChangedEventHandler *handler, -+ [in, size_is(propertyCount)]PROPERTYID *propertyArray, -+ [in]int propertyCount); -+ -+ HRESULT AddPropertyChangedEventHandler([in]IUIAutomationElement *element, -+ [in]enum TreeScope scope, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [in]IUIAutomationPropertyChangedEventHandler *handler, -+ [in]SAFEARRAY(PROPERTYID) propertyArray); -+ -+ HRESULT RemovePropertyChangedEventHandler([in]IUIAutomationElement *element, -+ [in]IUIAutomationPropertyChangedEventHandler *handler); -+ -+ HRESULT AddStructureChangedEventHandler([in]IUIAutomationElement *element, -+ [in]enum TreeScope scope, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [in]IUIAutomationStructureChangedEventHandler *handler); -+ -+ HRESULT RemoveStructureChangedEventHandler([in]IUIAutomationElement *element, -+ [in]IUIAutomationStructureChangedEventHandler *handler); -+ -+ HRESULT AddFocusChangedEventHandler([in]IUIAutomationCacheRequest *cacheRequest, -+ [in]IUIAutomationFocusChangedEventHandler *handler); -+ -+ HRESULT RemoveFocusChangedEventHandler([in]IUIAutomationFocusChangedEventHandler *handler); -+ HRESULT RemoveAllEventHandlers(); -+ -+ HRESULT IntNativeArrayToSafeArray([in, size_is(arrayCount)]int *array, -+ [in]int arrayCount, -+ [out, retval]SAFEARRAY(int) *safeArray); -+ -+ HRESULT IntSafeArrayToNativeArray([in]SAFEARRAY(int) intArray, -+ [out, size_is( ,*arrayCount)]int **array, -+ [out, retval]int *arrayCount); -+ -+ HRESULT RectToVariant([in]RECT rc, -+ [out, retval]VARIANT *var); -+ -+ HRESULT VariantToRect([in]VARIANT var, -+ [out, retval]RECT *rc); -+ -+ HRESULT SafeArrayToRectNativeArray([in]SAFEARRAY(double) rects, -+ [out, size_is( ,*rectArrayCount)]RECT **rectArray, -+ [out, retval]int *rectArrayCount); -+ -+ HRESULT CreateProxyFactoryEntry([in]IUIAutomationProxyFactory *factory, -+ [out, retval]IUIAutomationProxyFactoryEntry **factoryEntry); -+ -+ [propget]HRESULT ProxyFactoryMapping([out, retval]IUIAutomationProxyFactoryMapping **factoryMapping); -+ -+ HRESULT GetPropertyProgrammaticName([in]PROPERTYID property, -+ [out, retval]BSTR *name); -+ -+ HRESULT GetPatternProgrammaticName([in]PATTERNID pattern, -+ [out, retval]BSTR *name); -+ -+ HRESULT PollForPotentialSupportedPatterns([in]IUIAutomationElement *pElement, -+ [out]SAFEARRAY(int) *patternIds, -+ [out]SAFEARRAY(BSTR) *patternNames); -+ -+ HRESULT PollForPotentialSupportedProperties([in]IUIAutomationElement *pElement, -+ [out]SAFEARRAY(int) *propertyIds, -+ [out]SAFEARRAY(BSTR) *propertyNames); -+ -+ HRESULT CheckNotSupported([in]VARIANT value, -+ [out, retval]BOOL *isNotSupported); -+ -+ [propget]HRESULT ReservedNotSupportedValue([out, retval]IUnknown **notSupportedValue); -+ [propget]HRESULT ReservedMixedAttributeValue([out, retval]IUnknown **mixedAttributeValue); -+ -+ HRESULT ElementFromIAccessible([in]IAccessible *accessible, -+ [in]int childId, -+ [out, retval]IUIAutomationElement **element); -+ -+ HRESULT ElementFromIAccessibleBuildCache([in]IAccessible *accessible, -+ [in]int childId, -+ [in]IUIAutomationCacheRequest *cacheRequest, -+ [out, retval]IUIAutomationElement **element); -+ } -+ -+ [ -+ uuid(ff48dba4-60ef-4201-aa87-54103eef594e), -+ version(1.0), -+ ] -+ coclass CUIAutomation -+ { -+ [default]interface IUIAutomation; -+ } - } -diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl -index 170b0c76de1..10838945b67 100644 ---- a/include/uiautomationcore.idl -+++ b/include/uiautomationcore.idl -@@ -40,6 +40,118 @@ enum ProviderOptions { - ProviderOptions_UseClientCoordinates = 0x0100, - }; - -+enum StructureChangeType { -+ StructureChangeType_ChildAdded = 0x0000, -+ StructureChangeType_ChildRemoved = 0x0001, -+ StructureChangeType_ChildrenInvalidated = 0x0002, -+ StructureChangeType_ChildrenBulkAdded = 0x0003, -+ StructureChangeType_ChildrenBulkRemoved = 0x0004, -+ StructureChangeType_ChildrenReordered = 0x0005, -+}; -+ -+enum TextEditChangeType { -+ TextEditChangeType_None = 0x0000, -+ TextEditChangeType_AutoCorrect = 0x0001, -+ TextEditChangeType_Composition = 0x0002, -+ TextEditChangeType_CompositionFinalized = 0x0003, -+ TextEditChangeType_AutoComplete = 0x0004, -+}; -+ -+enum OrientationType { -+ OrientationType_None = 0x0000, -+ OrientationType_Horizontal = 0x0001, -+ OrientationType_Vertical = 0x0002, -+}; -+ -+enum DockPosition -+{ -+ DockPosition_Top = 0x0000, -+ DockPosition_Left = 0x0001, -+ DockPosition_Bottom = 0x0002, -+ DockPosition_Right = 0x0003, -+ DockPosition_Fill = 0x0004, -+ DockPosition_None = 0x0005, -+}; -+ -+enum ExpandCollapseState { -+ ExpandCollapseState_Collapsed = 0x0000, -+ ExpandCollapseState_Expanded = 0x0001, -+ ExpandCollapseState_PartiallyExpanded = 0x0002, -+ ExpandCollapseState_LeafNode = 0x0003, -+}; -+ -+enum ScrollAmount { -+ ScrollAmount_LargeDecrement = 0x0000, -+ ScrollAmount_SmallDecrement = 0x0001, -+ ScrollAmount_NoAmount = 0x0002, -+ ScrollAmount_LargeIncrement = 0x0003, -+ ScrollAmount_SmallIncrement = 0x0004, -+}; -+ -+enum RowOrColumnMajor { -+ RowOrColumnMajor_RowMajor = 0x0000, -+ RowOrColumnMajor_ColumnMajor = 0x0001, -+ RowOrColumnMajor_Indeterminate = 0x0002, -+}; -+ -+enum ToggleState { -+ ToggleState_Off = 0x0000, -+ ToggleState_On = 0x0001, -+ ToggleState_Indeterminate = 0x0002, -+}; -+ -+enum WindowVisualState { -+ WindowVisualState_Normal = 0x0000, -+ WindowVisualState_Maximized = 0x0001, -+ WindowVisualState_Minimized = 0x0002, -+}; -+ -+enum SynchronizedInputType { -+ SynchronizedInputType_KeyUp = 0x0001, -+ SynchronizedInputType_KeyDown = 0x0002, -+ SynchronizedInputType_LeftMouseUp = 0x0004, -+ SynchronizedInputType_LeftMouseDown = 0x0008, -+ SynchronizedInputType_RightMouseUp = 0x0010, -+ SynchronizedInputType_RightMouseDown = 0x0020, -+}; -+ -+enum WindowInteractionState { -+ WindowInteractionState_Running = 0x0000, -+ WindowInteractionState_Closing = 0x0001, -+ WindowInteractionState_ReadyForUserInteraction = 0x0002, -+ WindowInteractionState_BlockedByModalWindow = 0x0003, -+ WindowInteractionState_NotResponding = 0x0004, -+}; -+ -+enum TextUnit { -+ TextUnit_Character = 0x0000, -+ TextUnit_Format = 0x0001, -+ TextUnit_Word = 0x0002, -+ TextUnit_Line = 0x0003, -+ TextUnit_Paragraph = 0x0004, -+ TextUnit_Page = 0x0005, -+ TextUnit_Document = 0x0006, -+}; -+ -+enum TextPatternRangeEndpoint { -+ TextPatternRangeEndpoint_Start = 0x0000, -+ TextPatternRangeEndpoint_End = 0x0001, -+}; -+ -+enum SupportedTextSelection { -+ SupportedTextSelection_None = 0x0000, -+ SupportedTextSelection_Single = 0x0001, -+ SupportedTextSelection_Multiple = 0x0002, -+}; -+ -+enum ZoomUnit { -+ ZoomUnit_NoAmount = 0x0000, -+ ZoomUnit_LargeDecrement = 0x0001, -+ ZoomUnit_SmallDecrement = 0x0002, -+ ZoomUnit_LargeIncrement = 0x0003, -+ ZoomUnit_SmallIncrement = 0x0004, -+}; -+ - typedef int PROPERTYID; - typedef int PATTERNID; - typedef int EVENTID; -@@ -53,6 +165,17 @@ struct UiaRect { - double height; - }; - -+struct UiaPoint { -+ double x; -+ double y; -+}; -+ -+struct UiaChangeInfo { -+ int uiaId; -+ VARIANT payload; -+ VARIANT extraInfo; -+}; -+ - [ - version(1.0), - uuid(930299ce-9965-4dec-b0f4-a54848d4b667), -@@ -136,6 +259,19 @@ library UIA - [propget] HRESULT FragmentRoot([out, retval] IRawElementProviderFragmentRoot **pRetVal); - } - -+ [ -+ object, -+ uuid(a407b27b-0f6d-4427-9292-473c7bf93258), -+ pointer_default(unique) -+ ] -+ interface IRawElementProviderAdviseEvents : IUnknown { -+ HRESULT AdviseEventAdded([in]EVENTID eventId, -+ [in]SAFEARRAY(PROPERTYID) propertyIDs); -+ -+ HRESULT AdviseEventRemoved([in]EVENTID eventId, -+ [in]SAFEARRAY(PROPERTYID) propertyIDs); -+ } -+ - [ - object, - uuid(620ce2a5-ab8f-40a9-86cb-de3c75599b58), -From e74f8e12b158decc0e644d1ea893356033840d8d Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Thu, 22 Jul 2021 14:42:12 -0400 -Subject: [PATCH] uiautomationcore: Add stub IUIAutomation interface. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/Makefile.in | 5 +- - dlls/uiautomationcore/uia_classes.idl | 21 + - dlls/uiautomationcore/uia_client.c | 618 ++++++++++++++++++++ - dlls/uiautomationcore/uia_main.c | 146 ++++- - dlls/uiautomationcore/uia_private.h | 21 + - dlls/uiautomationcore/uiautomationcore.spec | 2 +- - include/uiautomationclient.idl | 3 + - 7 files changed, 812 insertions(+), 4 deletions(-) - create mode 100644 dlls/uiautomationcore/uia_classes.idl - create mode 100644 dlls/uiautomationcore/uia_client.c - create mode 100644 dlls/uiautomationcore/uia_private.h - -diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in -index f0973fdec4c..91611fc11c1 100644 ---- a/dlls/uiautomationcore/Makefile.in -+++ b/dlls/uiautomationcore/Makefile.in -@@ -5,4 +5,7 @@ IMPORTS = uuid ole32 oleaut32 user32 - EXTRADLLFLAGS = -Wb,--prefer-native - - C_SRCS = \ -- uia_main.c -+ uia_main.c \ -+ uia_client.c -+ -+IDL_SRCS = uia_classes.idl -diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl -new file mode 100644 -index 00000000000..174c41cee2a ---- /dev/null -+++ b/dlls/uiautomationcore/uia_classes.idl -@@ -0,0 +1,21 @@ -+/* -+ * Copyright 2021 Connor Mcadams 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 regtypelib -+ -+#include "uiautomationclient.idl" -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -new file mode 100644 -index 00000000000..e63702e26fa ---- /dev/null -+++ b/dlls/uiautomationcore/uia_client.c -@@ -0,0 +1,618 @@ -+/* -+ * Copyright 2021 Connor Mcadams for CodeWeavers -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#define COBJMACROS -+#include "uia_private.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); -+ -+struct uia_data { -+ IUIAutomation IUIAutomation_iface; -+ LONG ref; -+}; -+ -+static inline struct uia_data *impl_from_IUIAutomation(IUIAutomation *iface) -+{ -+ return CONTAINING_RECORD(iface, struct uia_data, IUIAutomation_iface); -+} -+ -+static HRESULT WINAPI uia_QueryInterface(IUIAutomation *iface, REFIID riid, -+ void **ppvObject) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ -+ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); -+ -+ if (IsEqualIID(riid, &IID_IUIAutomation) || -+ IsEqualIID(riid, &IID_IUnknown)) -+ *ppvObject = iface; -+ else -+ { -+ WARN("no interface: %s\n", debugstr_guid(riid)); -+ *ppvObject = NULL; -+ return E_NOINTERFACE; -+ } -+ -+ IUIAutomation_AddRef(iface); -+ -+ return S_OK; -+} -+ -+static ULONG WINAPI uia_AddRef(IUIAutomation *iface) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ ULONG ref = InterlockedIncrement(&This->ref); -+ -+ TRACE("(%p) ref = %u\n", This, ref); -+ return ref; -+} -+ -+static FORCEINLINE ULONG WINAPI uia_Release(IUIAutomation *iface) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ ULONG ref = InterlockedDecrement(&This->ref); -+ -+ TRACE("(%p) ref = %u\n", This, ref); -+ -+ if(!ref) -+ heap_free(This); -+ -+ return ref; -+} -+ -+/* -+ * IUIAutomation methods. -+ */ -+static HRESULT WINAPI uia_CompareElements(IUIAutomation *iface, -+ IUIAutomationElement *el1, IUIAutomationElement *el2, BOOL *areSame) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CompareRuntimeIds(IUIAutomation *iface, -+ SAFEARRAY *runtimeId1, SAFEARRAY *runtimeId2, BOOL *areSame) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_GetRootElement(IUIAutomation *iface, -+ IUIAutomationElement **root) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ElementFromHandle(IUIAutomation *iface, UIA_HWND hwnd, -+ IUIAutomationElement **element) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ElementFromPoint(IUIAutomation *iface, POINT pt, -+ IUIAutomationElement **element) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_GetFocusedElement(IUIAutomation *iface, -+ IUIAutomationElement **element) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_GetRootElementBuildCache(IUIAutomation *iface, -+ IUIAutomationCacheRequest *cacheRequest,IUIAutomationElement **root) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ElementFromHandleBuildCache(IUIAutomation *iface, -+ UIA_HWND hwnd, IUIAutomationCacheRequest *cacheRequest, -+ IUIAutomationElement **root) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ElementFromPointBuildCache(IUIAutomation *iface, POINT pt, -+ IUIAutomationCacheRequest *cacheRequest, IUIAutomationElement **element) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_GetFocusedElementBuildCache(IUIAutomation *iface, -+ IUIAutomationCacheRequest *cacheRequest, IUIAutomationElement **element) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateTreeWalker(IUIAutomation *iface, -+ IUIAutomationCondition *pCondition, IUIAutomationTreeWalker **walker) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ControlViewWalker(IUIAutomation *iface, -+ IUIAutomationTreeWalker **walker) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ContentViewWalker(IUIAutomation *iface, -+ IUIAutomationTreeWalker **walker) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_RawViewWalker(IUIAutomation *iface, -+ IUIAutomationTreeWalker **walker) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_RawViewCondition(IUIAutomation *iface, -+ IUIAutomationCondition **condition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ControlViewCondition(IUIAutomation *iface, -+ IUIAutomationCondition **condition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ContentViewCondition(IUIAutomation *iface, -+ IUIAutomationCondition **condition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateCacheRequest(IUIAutomation *iface, -+ IUIAutomationCacheRequest **cacheRequest) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateTrueCondition(IUIAutomation *iface, -+ IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateFalseCondition(IUIAutomation *iface, -+ IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreatePropertyCondition(IUIAutomation *iface, -+ PROPERTYID propertyId, VARIANT value, IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreatePropertyConditionEx(IUIAutomation *iface, -+ PROPERTYID propertyId, VARIANT value, enum PropertyConditionFlags flags, -+ IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateAndCondition(IUIAutomation *iface, -+ IUIAutomationCondition *condition1, IUIAutomationCondition *condition2, -+ IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateAndConditionFromArray(IUIAutomation *iface, -+ SAFEARRAY *conditions, IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateAndConditionFromNativeArray(IUIAutomation *iface, -+ IUIAutomationCondition **conditions, int conditionCount, -+ IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateOrCondition(IUIAutomation *iface, -+ IUIAutomationCondition *condition1, IUIAutomationCondition *condition2, -+ IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateOrConditionFromArray(IUIAutomation *iface, -+ SAFEARRAY *conditions, IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateOrConditionFromNativeArray(IUIAutomation *iface, -+ IUIAutomationCondition **conditions, int conditionCount, -+ IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateNotCondition(IUIAutomation *iface, -+ IUIAutomationCondition *condition, IUIAutomationCondition **newCondition) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_AddAutomationEventHandler(IUIAutomation *iface, -+ EVENTID eventId, IUIAutomationElement *element, enum TreeScope scope, -+ IUIAutomationCacheRequest *cacheRequest, IUIAutomationEventHandler *handler) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_RemoveAutomationEventHandler(IUIAutomation *iface, -+ EVENTID eventId, IUIAutomationElement *element, -+ IUIAutomationEventHandler *handler) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_AddPropertyChangedEventHandlerNativeArray(IUIAutomation *iface, -+ IUIAutomationElement *element, enum TreeScope scope, -+ IUIAutomationCacheRequest *cacheRequest, -+ IUIAutomationPropertyChangedEventHandler *handler, -+ PROPERTYID *propertyArray, int propertyCount) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_AddPropertyChangedEventHandler(IUIAutomation *iface, -+ IUIAutomationElement *element, enum TreeScope scope, -+ IUIAutomationCacheRequest *cacheRequest, -+ IUIAutomationPropertyChangedEventHandler *handler, -+ SAFEARRAY *propertyArray) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_RemovePropertyChangedEventHandler(IUIAutomation *iface, -+ IUIAutomationElement *element, -+ IUIAutomationPropertyChangedEventHandler *handler) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_AddStructureChangedEventHandler(IUIAutomation *iface, -+ IUIAutomationElement *element, enum TreeScope scope, -+ IUIAutomationCacheRequest *cacheRequest, -+ IUIAutomationStructureChangedEventHandler *handler) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_RemoveStructureChangedEventHandler(IUIAutomation *iface, -+ IUIAutomationElement *element, IUIAutomationStructureChangedEventHandler *handler) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_AddFocusChangedEventHandler(IUIAutomation *iface, -+ IUIAutomationCacheRequest *cacheRequest, -+ IUIAutomationFocusChangedEventHandler *handler) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_RemoveFocusChangedEventHandler(IUIAutomation *iface, -+ IUIAutomationFocusChangedEventHandler *handler) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_RemoveAllEventHandlers(IUIAutomation *iface) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_IntNativeArrayToSafeArray(IUIAutomation *iface, -+ int *array, int arrayCount, SAFEARRAY **safeArray) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_IntSafeArrayToNativeArray(IUIAutomation *iface, -+ SAFEARRAY *intArray, int **array, int *arrayCount) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_RectToVariant(IUIAutomation *iface, RECT rc, -+ VARIANT *var) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_VariantToRect(IUIAutomation *iface, VARIANT var, -+ RECT *rc) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_SafeArrayToRectNativeArray(IUIAutomation *iface, -+ SAFEARRAY *rects, RECT **rectArray, int *rectArrayCount) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CreateProxyFactoryEntry(IUIAutomation *iface, -+ IUIAutomationProxyFactory *factory, IUIAutomationProxyFactoryEntry **factoryEntry) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_get_ProxyFactoryMapping(IUIAutomation *iface, -+ IUIAutomationProxyFactoryMapping **factoryMapping) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_GetPropertyProgrammaticName(IUIAutomation *iface, -+ PROPERTYID property,BSTR *name) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_GetPatternProgrammaticName(IUIAutomation *iface, -+ PATTERNID pattern, BSTR *name) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_PollForPotentialSupportedPatterns(IUIAutomation *iface, -+ IUIAutomationElement *pElement, SAFEARRAY **patternIds, -+ SAFEARRAY **patternNames) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_PollForPotentialSupportedProperties(IUIAutomation *iface, -+ IUIAutomationElement *pElement, SAFEARRAY **propertyIds, -+ SAFEARRAY **propertyNames) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_CheckNotSupported(IUIAutomation *iface, VARIANT value, -+ BOOL *isNotSupported) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_get_ReservedNotSupportedValue(IUIAutomation *iface, -+ IUnknown **notSupportedValue) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_get_ReservedMixedAttributeValue(IUIAutomation *iface, -+ IUnknown **mixedAttributeValue) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ElementFromIAccessible(IUIAutomation *iface, -+ IAccessible *accessible, int childId, IUIAutomationElement **element) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_ElementFromIAccessibleBuildCache(IUIAutomation *iface, -+ IAccessible *accessible, int childId, -+ IUIAutomationCacheRequest *cacheRequest, IUIAutomationElement **element) -+{ -+ struct uia_data *This = impl_from_IUIAutomation(iface); -+ FIXME("This %p\n", This); -+ return E_NOTIMPL; -+} -+ -+static const IUIAutomationVtbl uia_vtbl = { -+ uia_QueryInterface, -+ uia_AddRef, -+ uia_Release, -+ uia_CompareElements, -+ uia_CompareRuntimeIds, -+ uia_GetRootElement, -+ uia_ElementFromHandle, -+ uia_ElementFromPoint, -+ uia_GetFocusedElement, -+ uia_GetRootElementBuildCache, -+ uia_ElementFromHandleBuildCache, -+ uia_ElementFromPointBuildCache, -+ uia_GetFocusedElementBuildCache, -+ uia_CreateTreeWalker, -+ uia_ControlViewWalker, -+ uia_ContentViewWalker, -+ uia_RawViewWalker, -+ uia_RawViewCondition, -+ uia_ControlViewCondition, -+ uia_ContentViewCondition, -+ uia_CreateCacheRequest, -+ uia_CreateTrueCondition, -+ uia_CreateFalseCondition, -+ uia_CreatePropertyCondition, -+ uia_CreatePropertyConditionEx, -+ uia_CreateAndCondition, -+ uia_CreateAndConditionFromArray, -+ uia_CreateAndConditionFromNativeArray, -+ uia_CreateOrCondition, -+ uia_CreateOrConditionFromArray, -+ uia_CreateOrConditionFromNativeArray, -+ uia_CreateNotCondition, -+ uia_AddAutomationEventHandler, -+ uia_RemoveAutomationEventHandler, -+ uia_AddPropertyChangedEventHandlerNativeArray, -+ uia_AddPropertyChangedEventHandler, -+ uia_RemovePropertyChangedEventHandler, -+ uia_AddStructureChangedEventHandler, -+ uia_RemoveStructureChangedEventHandler, -+ uia_AddFocusChangedEventHandler, -+ uia_RemoveFocusChangedEventHandler, -+ uia_RemoveAllEventHandlers, -+ uia_IntNativeArrayToSafeArray, -+ uia_IntSafeArrayToNativeArray, -+ uia_RectToVariant, -+ uia_VariantToRect, -+ uia_SafeArrayToRectNativeArray, -+ uia_CreateProxyFactoryEntry, -+ uia_get_ProxyFactoryMapping, -+ uia_GetPropertyProgrammaticName, -+ uia_GetPatternProgrammaticName, -+ uia_PollForPotentialSupportedPatterns, -+ uia_PollForPotentialSupportedProperties, -+ uia_CheckNotSupported, -+ uia_get_ReservedNotSupportedValue, -+ uia_get_ReservedMixedAttributeValue, -+ uia_ElementFromIAccessible, -+ uia_ElementFromIAccessibleBuildCache, -+}; -+ -+HRESULT create_uia_iface(IUIAutomation **iface) -+{ -+ struct uia_data *uia; -+ -+ uia = heap_alloc_zero(sizeof(*uia)); -+ if (!uia) -+ return E_OUTOFMEMORY; -+ -+ uia->IUIAutomation_iface.lpVtbl = &uia_vtbl; -+ uia->ref = 1; -+ *iface = &uia->IUIAutomation_iface; -+ -+ return S_OK; -+} -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index f1cf06ed4f5..95dfc359043 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -17,9 +17,11 @@ - */ - - #define COBJMACROS -+#include - --#include "initguid.h" --#include "uiautomation.h" -+#include "uia_private.h" -+#include "ole2.h" -+#include "rpcproxy.h" - - #include "wine/debug.h" - #include "wine/heap.h" -@@ -367,3 +369,143 @@ HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *provider) - FIXME("(%p): stub\n", provider); - return E_NOTIMPL; - } -+ -+/* UIAutomation ClassFactory */ -+struct uia_cf { -+ IClassFactory IClassFactory_iface; -+ LONG ref; -+}; -+ -+static struct uia_cf *impl_from_IClassFactory(IClassFactory *iface) -+{ -+ return CONTAINING_RECORD(iface, struct uia_cf, IClassFactory_iface); -+} -+ -+static HRESULT WINAPI uia_cf_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj) -+{ -+ if(IsEqualGUID(riid, &IID_IUnknown) -+ || IsEqualGUID(riid, &IID_IClassFactory)) -+ { -+ IClassFactory_AddRef(iface); -+ *ppobj = iface; -+ return S_OK; -+ } -+ -+ *ppobj = NULL; -+ WARN("(%p)->(%s, %p): interface not found\n", iface, debugstr_guid(riid), ppobj); -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI uia_cf_AddRef(IClassFactory *iface) -+{ -+ struct uia_cf *This = impl_from_IClassFactory(iface); -+ ULONG ref = InterlockedIncrement(&This->ref); -+ TRACE("(%p)->(): Refcount now %u\n", This, ref); -+ return ref; -+} -+ -+static ULONG WINAPI uia_cf_Release(IClassFactory *iface) -+{ -+ struct uia_cf *This = impl_from_IClassFactory(iface); -+ ULONG ref = InterlockedDecrement(&This->ref); -+ TRACE("(%p)->(): Refcount now %u\n", This, ref); -+ if (!ref) -+ HeapFree(GetProcessHeap(), 0, This); -+ return ref; -+} -+ -+static HRESULT WINAPI uia_cf_CreateInstance(IClassFactory *iface, IUnknown *pOuter, -+ REFIID riid, void **ppobj) -+{ -+ struct uia_cf *This = impl_from_IClassFactory(iface); -+ -+ TRACE("(%p)->(%p,%s,%p)\n", This, pOuter, debugstr_guid(riid), ppobj); -+ -+ *ppobj = NULL; -+ -+ if(pOuter) -+ return CLASS_E_NOAGGREGATION; -+ -+ if (!IsEqualGUID(riid, &IID_IUIAutomation)) -+ return E_NOINTERFACE; -+ -+ return create_uia_iface((IUIAutomation **)ppobj); -+} -+ -+static HRESULT WINAPI uia_cf_LockServer(IClassFactory *iface, BOOL dolock) -+{ -+ struct uia_cf *This = impl_from_IClassFactory(iface); -+ FIXME("(%p)->(%d): stub!\n", This, dolock); -+ return S_OK; -+} -+ -+static const IClassFactoryVtbl uia_cf_Vtbl = -+{ -+ uia_cf_QueryInterface, -+ uia_cf_AddRef, -+ uia_cf_Release, -+ uia_cf_CreateInstance, -+ uia_cf_LockServer -+}; -+ -+static inline HRESULT make_uia_factory(REFIID riid, void **ppv) -+{ -+ HRESULT hr; -+ struct uia_cf *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret)); -+ ret->IClassFactory_iface.lpVtbl = &uia_cf_Vtbl; -+ ret->ref = 0; -+ -+ hr = IClassFactory_QueryInterface(&ret->IClassFactory_iface, riid, ppv); -+ if(FAILED(hr)) -+ HeapFree(GetProcessHeap(), 0, ret); -+ -+ return hr; -+} -+ -+HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) -+{ -+ TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); -+ -+ if (IsEqualGUID(rclsid, &CLSID_CUIAutomation)) -+ return make_uia_factory(riid, ppv); -+ -+ return CLASS_E_CLASSNOTAVAILABLE; -+} -+ -+/****************************************************************** -+ * DllCanUnloadNow (uiautomationcore.@) -+ */ -+HRESULT WINAPI DllCanUnloadNow(void) -+{ -+ return S_FALSE; -+} -+ -+/*********************************************************************** -+ * DllRegisterServer (uiautomationcore.@) -+ */ -+HRESULT WINAPI DllRegisterServer(void) -+{ -+ return __wine_register_resources(); -+} -+ -+/*********************************************************************** -+ * DllUnregisterServer (uiautomationcore.@) -+ */ -+HRESULT WINAPI DllUnregisterServer(void) -+{ -+ return __wine_unregister_resources(); -+} -+ -+BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved) -+{ -+ TRACE("%p,%u,%p\n", hinst, reason, reserved); -+ -+ switch (reason) -+ { -+ case DLL_PROCESS_ATTACH: -+ DisableThreadLibraryCalls(hinst); -+ break; -+ } -+ -+ return TRUE; -+} -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -new file mode 100644 -index 00000000000..4b41ff94568 ---- /dev/null -+++ b/dlls/uiautomationcore/uia_private.h -@@ -0,0 +1,21 @@ -+/* -+ * Copyright 2021 Connor McAdams 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 "uiautomation.h" -+ -+HRESULT create_uia_iface(IUIAutomation **) DECLSPEC_HIDDEN; -diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec -index 82071bd2317..93d4e130799 100644 ---- a/dlls/uiautomationcore/uiautomationcore.spec -+++ b/dlls/uiautomationcore/uiautomationcore.spec -@@ -1,5 +1,5 @@ - @ stdcall -private DllCanUnloadNow() --@ stub DllGetClassObject -+@ stdcall -private DllGetClassObject(ptr ptr ptr) - @ stdcall -private DllRegisterServer() - @ stdcall -private DllUnregisterServer() - @ stub DockPattern_SetDockPosition -diff --git a/include/uiautomationclient.idl b/include/uiautomationclient.idl -index 0079f5316b9..d459aaed361 100644 ---- a/include/uiautomationclient.idl -+++ b/include/uiautomationclient.idl -@@ -1583,6 +1583,9 @@ library UIAutomationClient { - - [ - uuid(ff48dba4-60ef-4201-aa87-54103eef594e), -+#ifdef __WIDL__ -+ threading(both), -+#endif - version(1.0), - ] - coclass CUIAutomation -From f0c9965ed2679f536c6f72900326a46bb1d26ee4 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Wed, 16 Jun 2021 18:27:05 -0400 -Subject: [PATCH] uiautomationcore: Add stub IUIAutomationElement interface. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_client.c | 819 +++++++++++++++++++++++++++++ - 1 file changed, 819 insertions(+) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index e63702e26fa..d2ec5d7ab67 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -29,6 +29,13 @@ struct uia_data { - LONG ref; - }; - -+struct uia_elem_data { -+ IUIAutomationElement IUIAutomationElement_iface; -+ LONG ref; -+}; -+ -+static inline struct uia_elem_data *impl_from_IUIAutomationElement(IUIAutomationElement *iface); -+ - static inline struct uia_data *impl_from_IUIAutomation(IUIAutomation *iface) - { - return CONTAINING_RECORD(iface, struct uia_data, IUIAutomation_iface); -@@ -616,3 +623,815 @@ HRESULT create_uia_iface(IUIAutomation **iface) - - return S_OK; - } -+ -+static inline struct uia_elem_data *impl_from_IUIAutomationElement(IUIAutomationElement *iface) -+{ -+ return CONTAINING_RECORD(iface, struct uia_elem_data, IUIAutomationElement_iface); -+} -+ -+static HRESULT WINAPI uia_elem_QueryInterface(IUIAutomationElement *iface, REFIID riid, -+ void **ppvObject) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ -+ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); -+ -+ if (IsEqualIID(riid, &IID_IUIAutomationElement) || -+ IsEqualIID(riid, &IID_IUnknown)) -+ *ppvObject = iface; -+ else -+ { -+ WARN("no interface: %s\n", debugstr_guid(riid)); -+ *ppvObject = NULL; -+ return E_NOINTERFACE; -+ } -+ -+ IUIAutomationElement_AddRef(iface); -+ -+ return S_OK; -+} -+ -+static ULONG WINAPI uia_elem_AddRef(IUIAutomationElement *iface) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ ULONG ref = InterlockedIncrement(&This->ref); -+ -+ TRACE("(%p) ref = %u\n", This, ref); -+ return ref; -+} -+ -+static ULONG WINAPI uia_elem_Release(IUIAutomationElement *iface) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ ULONG ref = InterlockedDecrement(&This->ref); -+ -+ TRACE("(%p) ref = %u\n", This, ref); -+ -+ if(!ref) -+ heap_free(This); -+ -+ return ref; -+} -+ -+static HRESULT WINAPI uia_elem_SetFocus(IUIAutomationElement *iface) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetRuntimeId(IUIAutomationElement *iface, -+ SAFEARRAY **runtimeId) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_FindFirst(IUIAutomationElement *iface, -+ enum TreeScope scope, IUIAutomationCondition *condition, -+ IUIAutomationElement **found) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_FindAll(IUIAutomationElement *iface, -+ enum TreeScope scope, IUIAutomationCondition *condition, -+ IUIAutomationElementArray **found) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_FindFirstBuildCache(IUIAutomationElement *iface, -+ enum TreeScope scope, IUIAutomationCondition *condition, -+ IUIAutomationCacheRequest *cacheRequest, -+ IUIAutomationElement **found) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_FindAllBuildCache(IUIAutomationElement *iface, -+ enum TreeScope scope, IUIAutomationCondition *condition, -+ IUIAutomationCacheRequest *cacheRequest, IUIAutomationElementArray **found) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_BuildUpdatedCache(IUIAutomationElement *iface, -+ IUIAutomationCacheRequest *cacheRequest, IUIAutomationElement **updatedElement) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCurrentPropertyValue(IUIAutomationElement *iface, -+ PROPERTYID propertyId, VARIANT *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCurrentPropertyValueEx(IUIAutomationElement *iface, -+ PROPERTYID propertyId, BOOL ignoreDefaultValue, VARIANT *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCachedPropertyValue(IUIAutomationElement *iface, -+ PROPERTYID propertyId, VARIANT *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCachedPropertyValueEx(IUIAutomationElement *iface, -+ PROPERTYID propertyId, BOOL ignoreDefaultValue, VARIANT *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCurrentPatternAs(IUIAutomationElement *iface, -+ PATTERNID patternId, REFIID riid, void **patternObject) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCachedPatternAs(IUIAutomationElement *iface, -+ PATTERNID patternId, REFIID riid, void **patternObject) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCurrentPattern(IUIAutomationElement *iface, -+ PATTERNID patternId, IUnknown **patternObject) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCachedPattern(IUIAutomationElement *iface, -+ PATTERNID patternId, IUnknown **patternObject) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCachedParent(IUIAutomationElement *iface, -+ IUIAutomationElement **parent) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetCachedChildren(IUIAutomationElement *iface, -+ IUIAutomationElementArray **children) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentProcessId(IUIAutomationElement *iface, -+ int *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentControlType(IUIAutomationElement *iface, -+ CONTROLTYPEID *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentLocalizedControlType(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentName(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentAcceleratorKey(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentAccessKey(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentHasKeyboardFocus(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentIsKeyboardFocusable(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentIsEnabled(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentAutomationId(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentClassName(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentHelpText(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentCulture(IUIAutomationElement *iface, -+ int *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentIsControlElement(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentIsContentElement(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentIsPassword(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentNativeWindowHandle(IUIAutomationElement *iface, -+ UIA_HWND *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentItemType(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentIsOffscreen(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentOrientation(IUIAutomationElement *iface, -+ enum OrientationType *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentFrameworkId(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentIsRequiredForForm(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentItemStatus(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentBoundingRectangle(IUIAutomationElement *iface, -+ RECT *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentLabeledBy(IUIAutomationElement *iface, -+ IUIAutomationElement **retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentAriaRole(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentAriaProperties(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentIsDataValidForForm(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentControllerFor(IUIAutomationElement *iface, -+ IUIAutomationElementArray **retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentDescribedBy(IUIAutomationElement *iface, -+ IUIAutomationElementArray **retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentFlowsTo(IUIAutomationElement *iface, -+ IUIAutomationElementArray **retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CurrentProviderDescription(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedProcessId(IUIAutomationElement *iface, -+ int *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedControlType(IUIAutomationElement *iface, -+ CONTROLTYPEID *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedLocalizedControlType(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedName(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedAcceleratorKey(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedAccessKey(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedHasKeyboardFocus(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedIsKeyboardFocusable(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedIsEnabled(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedAutomationId(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedClassName(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedHelpText(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedCulture(IUIAutomationElement *iface, -+ int *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedIsControlElement(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedIsContentElement(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedIsPassword(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedNativeWindowHandle(IUIAutomationElement *iface, -+ UIA_HWND *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedItemType(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedIsOffscreen(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedOrientation(IUIAutomationElement *iface, -+ enum OrientationType *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedFrameworkId(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedIsRequiredForForm(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedItemStatus(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedBoundingRectangle(IUIAutomationElement *iface, -+ RECT *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedLabeledBy(IUIAutomationElement *iface, -+ IUIAutomationElement **retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedAriaRole(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedAriaProperties(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedIsDataValidForForm(IUIAutomationElement *iface, -+ BOOL *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedControllerFor(IUIAutomationElement *iface, -+ IUIAutomationElementArray **retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedDescribedBy(IUIAutomationElement *iface, -+ IUIAutomationElementArray **retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedFlowsTo(IUIAutomationElement *iface, -+ IUIAutomationElementArray **retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_get_CachedProviderDescription(IUIAutomationElement *iface, -+ BSTR *retVal) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI uia_elem_GetClickablePoint(IUIAutomationElement *iface, -+ POINT *clickable, BOOL *gotClickable) -+{ -+ struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -+ FIXME("%p\n", This); -+ return E_NOTIMPL; -+} -+ -+static const IUIAutomationElementVtbl uia_elem_vtbl = { -+ uia_elem_QueryInterface, -+ uia_elem_AddRef, -+ uia_elem_Release, -+ uia_elem_SetFocus, -+ uia_elem_GetRuntimeId, -+ uia_elem_FindFirst, -+ uia_elem_FindAll, -+ uia_elem_FindFirstBuildCache, -+ uia_elem_FindAllBuildCache, -+ uia_elem_BuildUpdatedCache, -+ uia_elem_GetCurrentPropertyValue, -+ uia_elem_GetCurrentPropertyValueEx, -+ uia_elem_GetCachedPropertyValue, -+ uia_elem_GetCachedPropertyValueEx, -+ uia_elem_GetCurrentPatternAs, -+ uia_elem_GetCachedPatternAs, -+ uia_elem_GetCurrentPattern, -+ uia_elem_GetCachedPattern, -+ uia_elem_GetCachedParent, -+ uia_elem_GetCachedChildren, -+ uia_elem_get_CurrentProcessId, -+ uia_elem_get_CurrentControlType, -+ uia_elem_get_CurrentLocalizedControlType, -+ uia_elem_get_CurrentName, -+ uia_elem_get_CurrentAcceleratorKey, -+ uia_elem_get_CurrentAccessKey, -+ uia_elem_get_CurrentHasKeyboardFocus, -+ uia_elem_get_CurrentIsKeyboardFocusable, -+ uia_elem_get_CurrentIsEnabled, -+ uia_elem_get_CurrentAutomationId, -+ uia_elem_get_CurrentClassName, -+ uia_elem_get_CurrentHelpText, -+ uia_elem_get_CurrentCulture, -+ uia_elem_get_CurrentIsControlElement, -+ uia_elem_get_CurrentIsContentElement, -+ uia_elem_get_CurrentIsPassword, -+ uia_elem_get_CurrentNativeWindowHandle, -+ uia_elem_get_CurrentItemType, -+ uia_elem_get_CurrentIsOffscreen, -+ uia_elem_get_CurrentOrientation, -+ uia_elem_get_CurrentFrameworkId, -+ uia_elem_get_CurrentIsRequiredForForm, -+ uia_elem_get_CurrentItemStatus, -+ uia_elem_get_CurrentBoundingRectangle, -+ uia_elem_get_CurrentLabeledBy, -+ uia_elem_get_CurrentAriaRole, -+ uia_elem_get_CurrentAriaProperties, -+ uia_elem_get_CurrentIsDataValidForForm, -+ uia_elem_get_CurrentControllerFor, -+ uia_elem_get_CurrentDescribedBy, -+ uia_elem_get_CurrentFlowsTo, -+ uia_elem_get_CurrentProviderDescription, -+ uia_elem_get_CachedProcessId, -+ uia_elem_get_CachedControlType, -+ uia_elem_get_CachedLocalizedControlType, -+ uia_elem_get_CachedName, -+ uia_elem_get_CachedAcceleratorKey, -+ uia_elem_get_CachedAccessKey, -+ uia_elem_get_CachedHasKeyboardFocus, -+ uia_elem_get_CachedIsKeyboardFocusable, -+ uia_elem_get_CachedIsEnabled, -+ uia_elem_get_CachedAutomationId, -+ uia_elem_get_CachedClassName, -+ uia_elem_get_CachedHelpText, -+ uia_elem_get_CachedCulture, -+ uia_elem_get_CachedIsControlElement, -+ uia_elem_get_CachedIsContentElement, -+ uia_elem_get_CachedIsPassword, -+ uia_elem_get_CachedNativeWindowHandle, -+ uia_elem_get_CachedItemType, -+ uia_elem_get_CachedIsOffscreen, -+ uia_elem_get_CachedOrientation, -+ uia_elem_get_CachedFrameworkId, -+ uia_elem_get_CachedIsRequiredForForm, -+ uia_elem_get_CachedItemStatus, -+ uia_elem_get_CachedBoundingRectangle, -+ uia_elem_get_CachedLabeledBy, -+ uia_elem_get_CachedAriaRole, -+ uia_elem_get_CachedAriaProperties, -+ uia_elem_get_CachedIsDataValidForForm, -+ uia_elem_get_CachedControllerFor, -+ uia_elem_get_CachedDescribedBy, -+ uia_elem_get_CachedFlowsTo, -+ uia_elem_get_CachedProviderDescription, -+ uia_elem_GetClickablePoint, -+}; -+ -+static HRESULT create_uia_elem_iface(IUIAutomationElement **iface) -+{ -+ struct uia_elem_data *uia; -+ -+ uia = heap_alloc_zero(sizeof(*uia)); -+ if (!uia) -+ return E_OUTOFMEMORY; -+ -+ uia->IUIAutomationElement_iface.lpVtbl = &uia_elem_vtbl; -+ uia->ref = 1; -+ *iface = &uia->IUIAutomationElement_iface; -+ -+ return S_OK; -+} -From 1c5f1f46342c9ccbec2a1153574ad73d610a6961 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Fri, 16 Jul 2021 14:31:11 -0500 -Subject: [PATCH] uiautomationcore: Implement UiaReturnRawElementProvider. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/Makefile.in | 5 +++-- - dlls/uiautomationcore/uia_classes_core.idl | 21 +++++++++++++++++++++ - dlls/uiautomationcore/uia_main.c | 11 +++++++++-- - dlls/uiautomationcore/uia_private.h | 1 + - include/uiautomationcore.idl | 6 +++++- - 5 files changed, 39 insertions(+), 5 deletions(-) - create mode 100644 dlls/uiautomationcore/uia_classes_core.idl - -diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in -index 91611fc11c1..216f083e03d 100644 ---- a/dlls/uiautomationcore/Makefile.in -+++ b/dlls/uiautomationcore/Makefile.in -@@ -1,6 +1,6 @@ - MODULE = uiautomationcore.dll - IMPORTLIB = uiautomationcore --IMPORTS = uuid ole32 oleaut32 user32 -+IMPORTS = uuid ole32 oleaut32 user32 oleacc rpcrt4 - - EXTRADLLFLAGS = -Wb,--prefer-native - -@@ -8,4 +8,5 @@ C_SRCS = \ - uia_main.c \ - uia_client.c - --IDL_SRCS = uia_classes.idl -+IDL_SRCS = uia_classes.idl \ -+ uia_classes_core.idl -diff --git a/dlls/uiautomationcore/uia_classes_core.idl b/dlls/uiautomationcore/uia_classes_core.idl -new file mode 100644 -index 00000000000..8e29d7aa228 ---- /dev/null -+++ b/dlls/uiautomationcore/uia_classes_core.idl -@@ -0,0 +1,21 @@ -+/* -+ * Copyright 2021 Connor Mcadams 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 regtypelib -+ -+#include "uiautomationcore.idl" -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index 95dfc359043..c8a3795ed1b 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -313,8 +313,15 @@ int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid) - LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, - LPARAM lParam, IRawElementProviderSimple *elprov) - { -- FIXME("(%p, %Ix, %Ix, %p) stub!\n", hwnd, wParam, lParam, elprov); -- return 0; -+ TRACE("(%p, %Ix, %Ix, %p)\n", hwnd, wParam, lParam, elprov); -+ -+ if (lParam != UiaRootObjectId) -+ { -+ FIXME("Unsupported object id %ld\n", lParam); -+ return 0; -+ } -+ -+ return LresultFromObject(&IID_IRawElementProviderSimple, wParam, (IUnknown *)elprov); - } - - /*********************************************************************** -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index 4b41ff94568..17ff04b5055 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -17,5 +17,6 @@ - */ - - #include "uiautomation.h" -+#include "oleacc.h" - - HRESULT create_uia_iface(IUIAutomation **) DECLSPEC_HIDDEN; -diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl -index 10838945b67..e10c2316ceb 100644 ---- a/include/uiautomationcore.idl -+++ b/include/uiautomationcore.idl -@@ -179,6 +179,9 @@ struct UiaChangeInfo { - [ - version(1.0), - uuid(930299ce-9965-4dec-b0f4-a54848d4b667), -+#ifdef __WIDL__ -+ id(2), -+#endif - lcid(0), - hidden - ] -@@ -262,7 +265,8 @@ library UIA - [ - object, - uuid(a407b27b-0f6d-4427-9292-473c7bf93258), -- pointer_default(unique) -+ pointer_default(unique), -+ oleautomation - ] - interface IRawElementProviderAdviseEvents : IUnknown { - HRESULT AdviseEventAdded([in]EVENTID eventId, -From 15d6b2743a6b3484d88713c23daae6b4c0bbd7b1 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Fri, 16 Jul 2021 14:42:01 -0500 -Subject: [PATCH] uiautomationcore: Implement IUIAutomation::ElementFromHandle. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_client.c | 100 +++++++++++++++++++++++++++- - dlls/uiautomationcore/uia_private.h | 5 ++ - 2 files changed, 102 insertions(+), 3 deletions(-) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index d2ec5d7ab67..6a54ffb9ba2 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -18,6 +18,7 @@ - - #define COBJMACROS - #include "uia_private.h" -+#include "winuser.h" - - #include "wine/debug.h" - #include "wine/heap.h" -@@ -32,6 +33,11 @@ struct uia_data { - struct uia_elem_data { - IUIAutomationElement IUIAutomationElement_iface; - LONG ref; -+ -+ IRawElementProviderSimple *elem_prov; -+ -+ IAccessible *acc; -+ VARIANT child_id; - }; - - static inline struct uia_elem_data *impl_from_IUIAutomationElement(IUIAutomationElement *iface); -@@ -115,9 +121,54 @@ static HRESULT WINAPI uia_GetRootElement(IUIAutomation *iface, - static HRESULT WINAPI uia_ElementFromHandle(IUIAutomation *iface, UIA_HWND hwnd, - IUIAutomationElement **element) - { -- struct uia_data *This = impl_from_IUIAutomation(iface); -- FIXME("This %p\n", This); -- return E_NOTIMPL; -+ IUIAutomationElement *elem; -+ LRESULT lres; -+ HRESULT hr; -+ -+ TRACE("iface %p, hwnd %p, element %p\n", iface, hwnd, element); -+ -+ /* FIXME: Is this what actually gets returned? */ -+ if (!IsWindow(hwnd)) -+ return E_FAIL; -+ -+ lres = SendMessageW(hwnd, WM_GETOBJECT, 0, UiaRootObjectId); -+ if (FAILED(lres)) -+ return lres; -+ -+ /* -+ * If lres is 0, this is probably not a UIA provider, but instead an -+ * MSAA server. -+ */ -+ if (!lres) -+ { -+ IAccessible *acc; -+ -+ hr = AccessibleObjectFromWindow((HWND)hwnd, OBJID_CLIENT, -+ &IID_IAccessible, (void **)&acc); -+ if (FAILED(hr)) -+ return hr; -+ -+ hr = create_uia_elem_from_msaa_acc(&elem, acc, CHILDID_SELF); -+ if (FAILED(hr)) -+ return hr; -+ } -+ else -+ { -+ IRawElementProviderSimple *elem_prov; -+ -+ hr = ObjectFromLresult(lres, &IID_IRawElementProviderSimple, 0, -+ (void **)&elem_prov); -+ if (FAILED(hr)) -+ return hr; -+ -+ hr = create_uia_elem_from_raw_provider(&elem, elem_prov); -+ if (FAILED(hr)) -+ return hr; -+ } -+ -+ *element = elem; -+ -+ return S_OK; - } - - static HRESULT WINAPI uia_ElementFromPoint(IUIAutomation *iface, POINT pt, -@@ -668,7 +719,14 @@ static ULONG WINAPI uia_elem_Release(IUIAutomationElement *iface) - TRACE("(%p) ref = %u\n", This, ref); - - if(!ref) -+ { -+ if (This->elem_prov) -+ IRawElementProviderSimple_Release(This->elem_prov); -+ else if (This->acc) -+ IAccessible_Release(This->acc); -+ - heap_free(This); -+ } - - return ref; - } -@@ -1435,3 +1493,39 @@ static HRESULT create_uia_elem_iface(IUIAutomationElement **iface) - - return S_OK; - } -+ -+HRESULT create_uia_elem_from_raw_provider(IUIAutomationElement **iface, -+ IRawElementProviderSimple *wrap) -+{ -+ struct uia_elem_data *uia; -+ HRESULT hr; -+ -+ hr = create_uia_elem_iface(iface); -+ if (FAILED(hr)) -+ return hr; -+ -+ uia = impl_from_IUIAutomationElement(*iface); -+ uia->elem_prov = wrap; -+ uia->acc = NULL; -+ -+ return S_OK; -+} -+ -+HRESULT create_uia_elem_from_msaa_acc(IUIAutomationElement **iface, -+ IAccessible *wrap, INT child_id) -+{ -+ struct uia_elem_data *uia; -+ HRESULT hr; -+ -+ hr = create_uia_elem_iface(iface); -+ if (FAILED(hr)) -+ return hr; -+ -+ uia = impl_from_IUIAutomationElement(*iface); -+ uia->elem_prov = NULL; -+ uia->acc = wrap; -+ V_VT(&uia->child_id) = VT_I4; -+ V_I4(&uia->child_id) = child_id; -+ -+ return S_OK; -+} -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index 17ff04b5055..5e60ecc1151 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -20,3 +20,8 @@ - #include "oleacc.h" - - HRESULT create_uia_iface(IUIAutomation **) DECLSPEC_HIDDEN; -+ -+HRESULT create_uia_elem_from_raw_provider(IUIAutomationElement **, -+ IRawElementProviderSimple *) DECLSPEC_HIDDEN; -+HRESULT create_uia_elem_from_msaa_acc(IUIAutomationElement **, -+ IAccessible *, INT) DECLSPEC_HIDDEN; -From ee5da6ebbad53e9205b4a88d0953260eced3a77a Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 26 Jul 2021 10:47:48 -0400 -Subject: [PATCH] uiautomationcore: Implement - IUIAutomationElement::get_CurrentControlType. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_client.c | 174 +++++++++++++++++++++++++++-- - 1 file changed, 166 insertions(+), 8 deletions(-) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index 6a54ffb9ba2..008aeae62c9 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -34,6 +34,8 @@ struct uia_elem_data { - IUIAutomationElement IUIAutomationElement_iface; - LONG ref; - -+ BOOL elem_disconnected; -+ - IRawElementProviderSimple *elem_prov; - - IAccessible *acc; -@@ -675,6 +677,129 @@ HRESULT create_uia_iface(IUIAutomation **iface) - return S_OK; - } - -+/* -+ * IUIAutomationElement helper functions. -+ */ -+static BOOL uia_hresult_is_obj_disconnected(HRESULT hr) -+{ -+ if ((hr == CO_E_OBJNOTCONNECTED) || (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))) -+ return TRUE; -+ -+ return FALSE; -+} -+ -+static INT uia_msaa_role_to_uia_control_type(INT role) -+{ -+ switch (role) -+ { -+ -+ case ROLE_SYSTEM_PUSHBUTTON: return UIA_ButtonControlTypeId; -+ case ROLE_SYSTEM_CLIENT: return UIA_CalendarControlTypeId; -+ case ROLE_SYSTEM_CHECKBUTTON: return UIA_CheckBoxControlTypeId; -+ case ROLE_SYSTEM_COMBOBOX: return UIA_ComboBoxControlTypeId; -+ case ROLE_SYSTEM_DOCUMENT: return UIA_DocumentControlTypeId; -+ case ROLE_SYSTEM_TEXT: return UIA_EditControlTypeId; -+ case ROLE_SYSTEM_GROUPING: return UIA_GroupControlTypeId; -+ case ROLE_SYSTEM_COLUMNHEADER: return UIA_HeaderItemControlTypeId; -+ case ROLE_SYSTEM_LINK: return UIA_HyperlinkControlTypeId; -+ case ROLE_SYSTEM_GRAPHIC: return UIA_ImageControlTypeId; -+ case ROLE_SYSTEM_LIST: return UIA_ListControlTypeId; -+ case ROLE_SYSTEM_LISTITEM: return UIA_ListItemControlTypeId; -+ case ROLE_SYSTEM_MENUPOPUP: return UIA_MenuControlTypeId; -+ case ROLE_SYSTEM_MENUBAR: return UIA_MenuBarControlTypeId; -+ case ROLE_SYSTEM_MENUITEM: return UIA_MenuItemControlTypeId; -+ case ROLE_SYSTEM_PANE: return UIA_PaneControlTypeId; -+ case ROLE_SYSTEM_PROGRESSBAR: return UIA_ProgressBarControlTypeId; -+ case ROLE_SYSTEM_RADIOBUTTON: return UIA_RadioButtonControlTypeId; -+ case ROLE_SYSTEM_SCROLLBAR: return UIA_ScrollBarControlTypeId; -+ case ROLE_SYSTEM_SEPARATOR: return UIA_SeparatorControlTypeId; -+ case ROLE_SYSTEM_SLIDER: return UIA_SliderControlTypeId; -+ case ROLE_SYSTEM_SPINBUTTON: return UIA_SpinnerControlTypeId; -+ case ROLE_SYSTEM_SPLITBUTTON: return UIA_SplitButtonControlTypeId; -+ case ROLE_SYSTEM_STATUSBAR: return UIA_StatusBarControlTypeId; -+ case ROLE_SYSTEM_PAGETABLIST: return UIA_TabControlTypeId; -+ case ROLE_SYSTEM_PAGETAB: return UIA_TabItemControlTypeId; -+ case ROLE_SYSTEM_TABLE: return UIA_TableControlTypeId; -+ case ROLE_SYSTEM_STATICTEXT: return UIA_TextControlTypeId; -+ case ROLE_SYSTEM_INDICATOR: return UIA_ThumbControlTypeId; -+ case ROLE_SYSTEM_TITLEBAR: return UIA_TitleBarControlTypeId; -+ case ROLE_SYSTEM_TOOLBAR: return UIA_ToolBarControlTypeId; -+ case ROLE_SYSTEM_TOOLTIP: return UIA_ToolTipControlTypeId; -+ case ROLE_SYSTEM_OUTLINE: return UIA_TreeControlTypeId; -+ case ROLE_SYSTEM_OUTLINEITEM: return UIA_TreeItemControlTypeId; -+ case ROLE_SYSTEM_WINDOW: return UIA_WindowControlTypeId; -+ default: -+ FIXME("Unhandled MSAA role %#x, defaulting to UIA_ButtonControlTypeId.\n", -+ role); -+ break; -+ } -+ -+ return UIA_ButtonControlTypeId; -+} -+ -+static void uia_get_default_property_val(PROPERTYID propertyId, VARIANT *retVal) -+{ -+ switch (propertyId) -+ { -+ case UIA_ControlTypePropertyId: -+ V_VT(retVal) = VT_I4; -+ V_I4(retVal) = UIA_CustomControlTypeId; -+ break; -+ -+ default: -+ FIXME("Unimplemented default value for PropertyId %d!\n", propertyId); -+ V_VT(retVal) = VT_EMPTY; -+ break; -+ } -+} -+ -+static HRESULT uia_get_uia_elem_prov_property_val(IRawElementProviderSimple *elem_prov, -+ PROPERTYID propertyId, BOOL *use_default, VARIANT *retVal) -+{ -+ VARIANT res; -+ HRESULT hr; -+ -+ VariantInit(&res); -+ *use_default = TRUE; -+ hr = IRawElementProviderSimple_GetPropertyValue(elem_prov, propertyId, &res); -+ -+ /* VT_EMPTY means this PropertyId is unimplemented/unsupported. */ -+ if (V_VT(&res) != VT_EMPTY && SUCCEEDED(hr)) -+ { -+ *use_default = FALSE; -+ *retVal = res; -+ } -+ -+ return hr; -+} -+ -+static HRESULT uia_get_msaa_acc_property_val(IAccessible *acc, -+ VARIANT child_id, PROPERTYID propertyId, BOOL *use_default, VARIANT *retVal) -+{ -+ HRESULT hr = S_OK; -+ VARIANT res; -+ -+ *use_default = TRUE; -+ switch (propertyId) -+ { -+ case UIA_ControlTypePropertyId: -+ hr = IAccessible_get_accRole(acc, child_id, &res); -+ if (SUCCEEDED(hr)) -+ { -+ V_VT(retVal) = VT_I4; -+ V_I4(retVal) = uia_msaa_role_to_uia_control_type(V_I4(&res)); -+ *use_default = FALSE; -+ } -+ break; -+ -+ default: -+ FIXME("UIA PropertyId %d unimplemented for IAccessible!\n", propertyId); -+ break; -+ } -+ -+ return hr; -+} -+ - static inline struct uia_elem_data *impl_from_IUIAutomationElement(IUIAutomationElement *iface) - { - return CONTAINING_RECORD(iface, struct uia_elem_data, IUIAutomationElement_iface); -@@ -794,17 +919,39 @@ static HRESULT WINAPI uia_elem_BuildUpdatedCache(IUIAutomationElement *iface, - static HRESULT WINAPI uia_elem_GetCurrentPropertyValue(IUIAutomationElement *iface, - PROPERTYID propertyId, VARIANT *retVal) - { -- struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -- FIXME("%p\n", This); -- return E_NOTIMPL; -+ return IUIAutomationElement_GetCurrentPropertyValueEx(iface, propertyId, FALSE, retVal); - } - - static HRESULT WINAPI uia_elem_GetCurrentPropertyValueEx(IUIAutomationElement *iface, - PROPERTYID propertyId, BOOL ignoreDefaultValue, VARIANT *retVal) - { - struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -- FIXME("%p\n", This); -- return E_NOTIMPL; -+ BOOL use_default; -+ HRESULT hr; -+ -+ TRACE("%p, %d, %d, %p\n", iface, propertyId, ignoreDefaultValue, retVal); -+ -+ VariantInit(retVal); -+ if (This->elem_disconnected) -+ return UIA_E_ELEMENTNOTAVAILABLE; -+ -+ if (This->elem_prov) -+ hr = uia_get_uia_elem_prov_property_val(This->elem_prov, -+ propertyId, &use_default, retVal); -+ else -+ hr = uia_get_msaa_acc_property_val(This->acc, -+ This->child_id, propertyId, &use_default, retVal); -+ -+ if (FAILED(hr) && uia_hresult_is_obj_disconnected(hr)) -+ { -+ This->elem_disconnected = TRUE; -+ return UIA_E_ELEMENTNOTAVAILABLE; -+ } -+ -+ if (SUCCEEDED(hr) && use_default && !ignoreDefaultValue) -+ uia_get_default_property_val(propertyId, retVal); -+ -+ return hr; - } - - static HRESULT WINAPI uia_elem_GetCachedPropertyValue(IUIAutomationElement *iface, -@@ -882,9 +1029,20 @@ static HRESULT WINAPI uia_elem_get_CurrentProcessId(IUIAutomationElement *iface, - static HRESULT WINAPI uia_elem_get_CurrentControlType(IUIAutomationElement *iface, - CONTROLTYPEID *retVal) - { -- struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -- FIXME("%p\n", This); -- return E_NOTIMPL; -+ VARIANT res; -+ HRESULT hr; -+ -+ TRACE("%p %p\n", iface, retVal); -+ -+ hr = IUIAutomationElement_GetCurrentPropertyValue(iface, -+ UIA_ControlTypePropertyId, &res); -+ if (FAILED(hr)) -+ return hr; -+ -+ if (V_VT(&res) == VT_I4) -+ *retVal = V_I4(&res); -+ -+ return S_OK; - } - - static HRESULT WINAPI uia_elem_get_CurrentLocalizedControlType(IUIAutomationElement *iface, -From 219fb1e7927dd91e438171b760deca046fe68211 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 26 Jul 2021 11:10:26 -0400 -Subject: [PATCH] uiautomationcore: Implement - IUIAutomationElement::get_CurrentName. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_client.c | 37 +++++++++++++++++++++++++++--- - 1 file changed, 34 insertions(+), 3 deletions(-) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index 008aeae62c9..af16eab42a7 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -746,6 +746,11 @@ static void uia_get_default_property_val(PROPERTYID propertyId, VARIANT *retVal) - V_I4(retVal) = UIA_CustomControlTypeId; - break; - -+ case UIA_NamePropertyId: -+ V_VT(retVal) = VT_BSTR; -+ V_BSTR(retVal) = SysAllocString(L""); -+ break; -+ - default: - FIXME("Unimplemented default value for PropertyId %d!\n", propertyId); - V_VT(retVal) = VT_EMPTY; -@@ -792,6 +797,20 @@ static HRESULT uia_get_msaa_acc_property_val(IAccessible *acc, - } - break; - -+ case UIA_NamePropertyId: -+ { -+ BSTR name; -+ -+ hr = IAccessible_get_accName(acc, child_id, &name); -+ if (SUCCEEDED(hr) && name) -+ { -+ V_VT(retVal) = VT_BSTR; -+ V_BSTR(retVal) = name; -+ *use_default = FALSE; -+ } -+ break; -+ } -+ - default: - FIXME("UIA PropertyId %d unimplemented for IAccessible!\n", propertyId); - break; -@@ -1056,9 +1075,21 @@ static HRESULT WINAPI uia_elem_get_CurrentLocalizedControlType(IUIAutomationElem - static HRESULT WINAPI uia_elem_get_CurrentName(IUIAutomationElement *iface, - BSTR *retVal) - { -- struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -- FIXME("%p\n", This); -- return E_NOTIMPL; -+ VARIANT res; -+ HRESULT hr; -+ -+ TRACE("%p %p\n", iface, retVal); -+ -+ *retVal = NULL; -+ hr = IUIAutomationElement_GetCurrentPropertyValue(iface, -+ UIA_NamePropertyId, &res); -+ if (FAILED(hr)) -+ return hr; -+ -+ if (V_VT(&res) == VT_BSTR) -+ *retVal = V_BSTR(&res); -+ -+ return S_OK; - } - - static HRESULT WINAPI uia_elem_get_CurrentAcceleratorKey(IUIAutomationElement *iface, -From 1a64f705f4e1dd05df9466dce3ca437333fe17d1 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 26 Jul 2021 11:20:30 -0400 -Subject: [PATCH] uiautomationcore: Implement keyboard focus property IDs. - -Implement MSAA mappings and default values for -UIA_IsKeyboardFocusablePropertyId and UIA_HasKeyboardFocusPropertyId. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_client.c | 34 ++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index af16eab42a7..250ce99e947 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -751,6 +751,12 @@ static void uia_get_default_property_val(PROPERTYID propertyId, VARIANT *retVal) - V_BSTR(retVal) = SysAllocString(L""); - break; - -+ case UIA_IsKeyboardFocusablePropertyId: -+ case UIA_HasKeyboardFocusPropertyId: -+ V_VT(retVal) = VT_BOOL; -+ V_BOOL(retVal) = VARIANT_FALSE; -+ break; -+ - default: - FIXME("Unimplemented default value for PropertyId %d!\n", propertyId); - V_VT(retVal) = VT_EMPTY; -@@ -811,6 +817,34 @@ static HRESULT uia_get_msaa_acc_property_val(IAccessible *acc, - break; - } - -+ case UIA_IsKeyboardFocusablePropertyId: -+ hr = IAccessible_get_accState(acc, child_id, &res); -+ if (SUCCEEDED(hr) && V_VT(&res) == VT_I4) -+ { -+ V_VT(retVal) = VT_BOOL; -+ if (V_I4(&res) & STATE_SYSTEM_FOCUSABLE) -+ V_BOOL(retVal) = VARIANT_TRUE; -+ else -+ V_BOOL(retVal) = VARIANT_FALSE; -+ -+ *use_default = FALSE; -+ } -+ break; -+ -+ case UIA_HasKeyboardFocusPropertyId: -+ hr = IAccessible_get_accState(acc, child_id, &res); -+ if (SUCCEEDED(hr) && V_VT(&res) == VT_I4) -+ { -+ V_VT(retVal) = VT_BOOL; -+ if (V_I4(&res) & STATE_SYSTEM_FOCUSED) -+ V_BOOL(retVal) = VARIANT_TRUE; -+ else -+ V_BOOL(retVal) = VARIANT_FALSE; -+ -+ *use_default = FALSE; -+ } -+ break; -+ - default: - FIXME("UIA PropertyId %d unimplemented for IAccessible!\n", propertyId); - break; -From 7d36b3341ef0d87ea194e34c2a2f40b32f82add9 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 26 Jul 2021 12:43:14 -0400 -Subject: [PATCH] uiautomationcore: uiautomationcore: Add automation event - handler list. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/Makefile.in | 3 +- - dlls/uiautomationcore/uia_client.c | 19 +++---- - dlls/uiautomationcore/uia_event.c | 77 +++++++++++++++++++++++++++++ - dlls/uiautomationcore/uia_private.h | 45 +++++++++++++++++ - 4 files changed, 134 insertions(+), 10 deletions(-) - create mode 100644 dlls/uiautomationcore/uia_event.c - -diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in -index 216f083e03d..cbafa94782c 100644 ---- a/dlls/uiautomationcore/Makefile.in -+++ b/dlls/uiautomationcore/Makefile.in -@@ -6,7 +6,8 @@ EXTRADLLFLAGS = -Wb,--prefer-native - - C_SRCS = \ - uia_main.c \ -- uia_client.c -+ uia_client.c \ -+ uia_event.c - - IDL_SRCS = uia_classes.idl \ - uia_classes_core.idl -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index 250ce99e947..8c83e837b09 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -25,11 +25,6 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); - --struct uia_data { -- IUIAutomation IUIAutomation_iface; -- LONG ref; --}; -- - struct uia_elem_data { - IUIAutomationElement IUIAutomationElement_iface; - LONG ref; -@@ -451,16 +446,22 @@ static HRESULT WINAPI uia_AddFocusChangedEventHandler(IUIAutomation *iface, - IUIAutomationFocusChangedEventHandler *handler) - { - struct uia_data *This = impl_from_IUIAutomation(iface); -- FIXME("This %p\n", This); -- return E_NOTIMPL; -+ -+ TRACE("%p %p %p\n", iface, cacheRequest, handler); -+ if (cacheRequest) -+ FIXME("Cache request unimplemented in event handler!\n"); -+ -+ return uia_evh_add_focus_event_handler(This, handler); - } - - static HRESULT WINAPI uia_RemoveFocusChangedEventHandler(IUIAutomation *iface, - IUIAutomationFocusChangedEventHandler *handler) - { - struct uia_data *This = impl_from_IUIAutomation(iface); -- FIXME("This %p\n", This); -- return E_NOTIMPL; -+ -+ TRACE("iface %p, handler %p\n", iface, handler); -+ -+ return uia_evh_remove_focus_event_handler(This, handler); - } - - static HRESULT WINAPI uia_RemoveAllEventHandlers(IUIAutomation *iface) -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -new file mode 100644 -index 00000000000..0360b9d6b6d ---- /dev/null -+++ b/dlls/uiautomationcore/uia_event.c -@@ -0,0 +1,77 @@ -+/* -+ * Copyright 2021 Connor Mcadams for CodeWeavers -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#define COBJMACROS -+#include "uia_private.h" -+ -+#include "wine/debug.h" -+#include "wine/heap.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); -+ -+static void uia_evh_add_event_handler(struct uia_data *data, struct uia_evh *evh) -+{ -+ list_add_tail(&data->uia_evh_list, &evh->entry); -+} -+ -+/* -+ * FIXME: Check if ref count is incremented/decremented when added/removed. -+ */ -+HRESULT uia_evh_add_focus_event_handler(struct uia_data *data, -+ IUIAutomationFocusChangedEventHandler *handler) -+{ -+ struct uia_evh *evh = heap_alloc_zero(sizeof(*evh)); -+ -+ TRACE("data %p, handler %p\n", data, handler); -+ if (!evh) -+ return E_OUTOFMEMORY; -+ -+ evh->event_type = FOCUS_EVH; -+ evh->u.IUIAutomationFocusChangedEvh_iface = handler; -+ -+ uia_evh_add_event_handler(data, evh); -+ -+ return S_OK; -+} -+ -+/* -+ * Figure out HRESULT value when removing an event handler that hasn't been -+ * added. -+ */ -+HRESULT uia_evh_remove_focus_event_handler(struct uia_data *data, -+ IUIAutomationFocusChangedEventHandler *handler) -+{ -+ struct list *evh_list = &data->uia_evh_list; -+ struct list *cursor, *cursor2; -+ struct uia_evh *evh; -+ -+ LIST_FOR_EACH_SAFE(cursor, cursor2, evh_list) -+ { -+ evh = LIST_ENTRY(cursor, struct uia_evh, entry); -+ if (evh->event_type == FOCUS_EVH -+ && evh->u.IUIAutomationFocusChangedEvh_iface == handler) -+ { -+ list_remove(cursor); -+ IUIAutomationFocusChangedEventHandler_Release(handler); -+ heap_free(evh); -+ return S_OK; -+ } -+ } -+ -+ return S_OK; -+} -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index 5e60ecc1151..35f86ea8c85 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -19,9 +19,54 @@ - #include "uiautomation.h" - #include "oleacc.h" - -+#include "wine/list.h" -+ -+/* -+ * EVH = Event Handler. -+ */ -+enum { -+ BASIC_EVH, -+ CHANGES_EVH, -+ FOCUS_EVH, -+ PROPERTY_EVH, -+ STRUCTURE_EVH, -+ TEXT_EDIT_EVH, -+}; -+ -+struct uia_evh -+{ -+ struct list entry; -+ -+ UINT event_type; -+ union -+ { -+ IUIAutomationEventHandler *IUIAutomationEvh_iface; -+ IUIAutomationChangesEventHandler *IUIAutomationChangesEvh_iface; -+ IUIAutomationFocusChangedEventHandler *IUIAutomationFocusChangedEvh_iface; -+ IUIAutomationPropertyChangedEventHandler *IUIAutomationPropertyChangedEvh_iface; -+ IUIAutomationStructureChangedEventHandler *IUIAutomationStructureChangedEvh_iface; -+ IUIAutomationTextEditTextChangedEventHandler *IUIAutomationTextEditTextChangedEvh_iface; -+ } u; -+}; -+ -+struct uia_data { -+ IUIAutomation IUIAutomation_iface; -+ LONG ref; -+ -+ struct list uia_evh_list; -+}; -+ - HRESULT create_uia_iface(IUIAutomation **) DECLSPEC_HIDDEN; - - HRESULT create_uia_elem_from_raw_provider(IUIAutomationElement **, - IRawElementProviderSimple *) DECLSPEC_HIDDEN; - HRESULT create_uia_elem_from_msaa_acc(IUIAutomationElement **, - IAccessible *, INT) DECLSPEC_HIDDEN; -+ -+/* -+ * uia_event.c functions. -+ */ -+HRESULT uia_evh_add_focus_event_handler(struct uia_data *data, -+ IUIAutomationFocusChangedEventHandler *handler) DECLSPEC_HIDDEN; -+HRESULT uia_evh_remove_focus_event_handler(struct uia_data *data, -+ IUIAutomationFocusChangedEventHandler *handler) DECLSPEC_HIDDEN; -From 64e2bbe7370bebe3d0bdc43f27f8d258dff87f7c Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Fri, 25 Jun 2021 13:11:57 -0400 -Subject: [PATCH] uiautomationcore: Implement - IUIAutomation::RemoveAllEventHandlers. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_client.c | 6 ++-- - dlls/uiautomationcore/uia_event.c | 46 +++++++++++++++++++++++++++++ - dlls/uiautomationcore/uia_private.h | 1 + - 3 files changed, 51 insertions(+), 2 deletions(-) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index 8c83e837b09..46c72f76ddf 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -467,8 +467,10 @@ static HRESULT WINAPI uia_RemoveFocusChangedEventHandler(IUIAutomation *iface, - static HRESULT WINAPI uia_RemoveAllEventHandlers(IUIAutomation *iface) - { - struct uia_data *This = impl_from_IUIAutomation(iface); -- FIXME("This %p\n", This); -- return E_NOTIMPL; -+ -+ TRACE("iface %p\n", iface); -+ -+ return uia_evh_remove_all_event_handlers(This); - } - - static HRESULT WINAPI uia_IntNativeArrayToSafeArray(IUIAutomation *iface, -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index 0360b9d6b6d..9e22b96ce0d 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -75,3 +75,49 @@ HRESULT uia_evh_remove_focus_event_handler(struct uia_data *data, - - return S_OK; - } -+ -+HRESULT uia_evh_remove_all_event_handlers(struct uia_data *data) -+{ -+ struct list *evh_list = &data->uia_evh_list; -+ struct list *cursor, *cursor2; -+ struct uia_evh *evh; -+ -+ LIST_FOR_EACH_SAFE(cursor, cursor2, evh_list) -+ { -+ evh = LIST_ENTRY(cursor, struct uia_evh, entry); -+ switch (evh->event_type) -+ { -+ case BASIC_EVH: -+ IUIAutomationEventHandler_Release(evh->u.IUIAutomationEvh_iface); -+ break; -+ -+ case CHANGES_EVH: -+ IUIAutomationChangesEventHandler_Release(evh->u.IUIAutomationChangesEvh_iface); -+ break; -+ -+ case FOCUS_EVH: -+ IUIAutomationFocusChangedEventHandler_Release(evh->u.IUIAutomationFocusChangedEvh_iface); -+ break; -+ -+ case PROPERTY_EVH: -+ IUIAutomationPropertyChangedEventHandler_Release(evh->u.IUIAutomationPropertyChangedEvh_iface); -+ break; -+ -+ case STRUCTURE_EVH: -+ IUIAutomationStructureChangedEventHandler_Release(evh->u.IUIAutomationStructureChangedEvh_iface); -+ break; -+ -+ case TEXT_EDIT_EVH: -+ IUIAutomationTextEditTextChangedEventHandler_Release(evh->u.IUIAutomationTextEditTextChangedEvh_iface); -+ break; -+ -+ default: -+ break; -+ } -+ -+ list_remove(cursor); -+ heap_free(evh); -+ } -+ -+ return S_OK; -+} -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index 35f86ea8c85..2e9785f47ef 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -70,3 +70,4 @@ HRESULT uia_evh_add_focus_event_handler(struct uia_data *data, - IUIAutomationFocusChangedEventHandler *handler) DECLSPEC_HIDDEN; - HRESULT uia_evh_remove_focus_event_handler(struct uia_data *data, - IUIAutomationFocusChangedEventHandler *handler) DECLSPEC_HIDDEN; -+HRESULT uia_evh_remove_all_event_handlers(struct uia_data *data) DECLSPEC_HIDDEN; -From 11fe3f6aed90bb4207c33077747bfb8d1d905c18 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Fri, 25 Jun 2021 16:37:30 -0400 -Subject: [PATCH] uiautomationcore: Initial event thread implementation. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_event.c | 153 +++++++++++++++++++++++++++- - dlls/uiautomationcore/uia_private.h | 18 +++- - 2 files changed, 165 insertions(+), 6 deletions(-) - -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index 9e22b96ce0d..a345730cda5 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -24,9 +24,141 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); - --static void uia_evh_add_event_handler(struct uia_data *data, struct uia_evh *evh) -+/* -+ * UI Automation Event Listener functions. -+ * The first time an event handler interface is added on the client side, the -+ * event listener thread is created. It is responsible for listening for -+ * events being raised by UIA providers and MSAA servers, and subsequently -+ * handling all relevant event handler interfaces. -+ */ -+static HRESULT uia_event_listener_thread_initialize(struct uia_evl *evl) - { -- list_add_tail(&data->uia_evh_list, &evh->entry); -+ HRESULT hr; -+ -+ hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); -+ if (FAILED(hr)) -+ return hr; -+ -+ return S_OK; -+} -+ -+static void uia_event_listener_thread_exit(struct uia_evl *evl) -+{ -+ struct uia_data *data = evl->data; -+ -+ heap_free(evl); -+ data->evl = NULL; -+ -+ CoUninitialize(); -+} -+ -+static DWORD WINAPI uia_event_listener_main(LPVOID lpParam) -+{ -+ struct uia_evl *evl = (struct uia_evl*)lpParam; -+ MSG msg = { }; -+ -+ PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); -+ SetEvent(evl->pump_initialized); -+ -+ if (FAILED(uia_event_listener_thread_initialize(evl))) -+ { -+ ERR("UI Automation Event Listener thread failed to start!\n"); -+ return 0; -+ } -+ -+ WaitForSingleObject(evl->first_event, INFINITE); -+ TRACE("UI Automation Event listener thread started!\n"); -+ /* From here, main loop, i.e monitor for messages. */ -+ while (GetMessageW(&msg, NULL, 0, 0)) -+ { -+ BOOL exit = FALSE; -+ -+ if (msg.hwnd) -+ { -+ TranslateMessage(&msg); -+ DispatchMessageW(&msg); -+ continue; -+ } -+ -+ EnterCriticalSection(&evl->ev_handler_cs); -+ -+ if (list_empty(&evl->uia_evh_list)) -+ exit = TRUE; -+ -+ LeaveCriticalSection(&evl->ev_handler_cs); -+ TRACE("Event listener thread ran, exit %d\n", exit); -+ if (exit) -+ break; -+ } -+ -+ uia_event_listener_thread_exit(evl); -+ TRACE("Event listener thread exited.\n"); -+ return 0; -+} -+ -+static HRESULT start_uia_event_listener(struct uia_data *data) -+{ -+ struct uia_evl *evl; -+ -+ evl = heap_alloc_zero(sizeof(*evl)); -+ if (!evl) -+ return E_OUTOFMEMORY; -+ -+ evl->data = data; -+ list_init(&evl->uia_evh_list); -+ -+ /* -+ * Create an event handler to signal when the event listener threads -+ * message pump has been initialized. -+ */ -+ evl->pump_initialized = CreateEventW(NULL, 0, 0, NULL); -+ evl->first_event = CreateEventW(NULL, 0, 0, NULL); -+ InitializeCriticalSection(&evl->ev_handler_cs); -+ -+ evl->h_thread = CreateThread(NULL, 0, uia_event_listener_main, evl, 0, &evl->tid); -+ -+ /* Wait for Window message queue creation. */ -+ WaitForSingleObject(evl->pump_initialized, INFINITE); -+ PostThreadMessageW(evl->tid, WM_NULL, 0, 0); -+ -+ data->evl = evl; -+ -+ return S_OK; -+} -+ -+static HRESULT uia_evh_add_event_handler(struct uia_data *data, struct uia_evh *evh) -+{ -+ BOOL initialized = FALSE; -+ -+ /* -+ * If this is the first event handler added, signified by the event listener -+ * being inactive, start it before adding the event. -+ */ -+ if (!data->evl) -+ { -+ HRESULT hr; -+ -+ hr = start_uia_event_listener(data); -+ if (FAILED(hr)) -+ return hr; -+ -+ initialized = TRUE; -+ } -+ -+ EnterCriticalSection(&data->evl->ev_handler_cs); -+ -+ list_add_tail(&data->evl->uia_evh_list, &evh->entry); -+ -+ LeaveCriticalSection(&data->evl->ev_handler_cs); -+ -+ if (initialized) -+ SetEvent(data->evl->first_event); -+ /* -+ * Awaken the thread by triggering GetMessage. -+ */ -+ PostThreadMessageW(data->evl->tid, WM_NULL, 0, 0); -+ -+ return S_OK; - } - - /* -@@ -56,10 +188,12 @@ HRESULT uia_evh_add_focus_event_handler(struct uia_data *data, - HRESULT uia_evh_remove_focus_event_handler(struct uia_data *data, - IUIAutomationFocusChangedEventHandler *handler) - { -- struct list *evh_list = &data->uia_evh_list; -+ struct list *evh_list = &data->evl->uia_evh_list; - struct list *cursor, *cursor2; - struct uia_evh *evh; - -+ EnterCriticalSection(&data->evl->ev_handler_cs); -+ - LIST_FOR_EACH_SAFE(cursor, cursor2, evh_list) - { - evh = LIST_ENTRY(cursor, struct uia_evh, entry); -@@ -69,19 +203,25 @@ HRESULT uia_evh_remove_focus_event_handler(struct uia_data *data, - list_remove(cursor); - IUIAutomationFocusChangedEventHandler_Release(handler); - heap_free(evh); -- return S_OK; -+ goto exit; - } - } - -+exit: -+ -+ LeaveCriticalSection(&data->evl->ev_handler_cs); -+ PostThreadMessageW(data->evl->tid, WM_NULL, 0, 0); -+ - return S_OK; - } - - HRESULT uia_evh_remove_all_event_handlers(struct uia_data *data) - { -- struct list *evh_list = &data->uia_evh_list; -+ struct list *evh_list = &data->evl->uia_evh_list; - struct list *cursor, *cursor2; - struct uia_evh *evh; - -+ EnterCriticalSection(&data->evl->ev_handler_cs); - LIST_FOR_EACH_SAFE(cursor, cursor2, evh_list) - { - evh = LIST_ENTRY(cursor, struct uia_evh, entry); -@@ -119,5 +259,8 @@ HRESULT uia_evh_remove_all_event_handlers(struct uia_data *data) - heap_free(evh); - } - -+ LeaveCriticalSection(&data->evl->ev_handler_cs); -+ PostThreadMessageW(data->evl->tid, WM_NULL, 0, 0); -+ - return S_OK; - } -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index 2e9785f47ef..d3fd1aeef01 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -49,11 +49,27 @@ struct uia_evh - } u; - }; - -+struct uia_data; -+ -+/* -+ * EVL = Event listener. -+ */ -+struct uia_evl -+{ -+ HANDLE h_thread, pump_initialized, first_event; -+ CRITICAL_SECTION ev_handler_cs; -+ UINT tid; -+ -+ struct uia_data *data; -+ -+ struct list uia_evh_list; -+}; -+ - struct uia_data { - IUIAutomation IUIAutomation_iface; - LONG ref; - -- struct list uia_evh_list; -+ struct uia_evl *evl; - }; - - HRESULT create_uia_iface(IUIAutomation **) DECLSPEC_HIDDEN; -From 7bc5a475386415100c3dadcf97a3cc2333e41185 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 29 Jun 2021 09:54:43 -0400 -Subject: [PATCH] uiautomationcore: Add tls data to event listener. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_event.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index a345730cda5..4cfba8e572c 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -24,6 +24,8 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); - -+DWORD tls_index = TLS_OUT_OF_INDEXES; -+ - /* - * UI Automation Event Listener functions. - * The first time an event handler interface is added on the client side, the -@@ -39,6 +41,9 @@ static HRESULT uia_event_listener_thread_initialize(struct uia_evl *evl) - if (FAILED(hr)) - return hr; - -+ if (!TlsSetValue(tls_index, (LPVOID)evl)) -+ FIXME("Failed to set Tls index value!\n"); -+ - return S_OK; - } - -@@ -48,6 +53,8 @@ static void uia_event_listener_thread_exit(struct uia_evl *evl) - - heap_free(evl); - data->evl = NULL; -+ if (!TlsSetValue(tls_index, NULL)) -+ FIXME("Failed to set Tls index value!\n"); - - CoUninitialize(); - } -@@ -104,6 +111,9 @@ static HRESULT start_uia_event_listener(struct uia_data *data) - if (!evl) - return E_OUTOFMEMORY; - -+ if (tls_index == TLS_OUT_OF_INDEXES) -+ tls_index = TlsAlloc(); -+ - evl->data = data; - list_init(&evl->uia_evh_list); - -From 4041865db37749679c38d8d58d21182d905bfa6b Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 29 Jun 2021 10:55:05 -0400 -Subject: [PATCH] uiautomationcore: Add WinEvent hooks. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_event.c | 28 ++++++++++++++++++++++++++++ - dlls/uiautomationcore/uia_private.h | 3 +++ - 2 files changed, 31 insertions(+) - -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index 4cfba8e572c..03d9e59e1a7 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -26,6 +26,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); - - DWORD tls_index = TLS_OUT_OF_INDEXES; - -+/* -+ * Event hook callback for window creation events. -+ */ -+void CALLBACK uia_evl_window_create_proc(HWINEVENTHOOK hWinEventHook, DWORD event, -+ HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, -+ DWORD dwmsEventTime) -+{ -+ return; -+} -+ -+/* -+ * Event hook callback for MSAA object focus events. -+ */ -+void CALLBACK uia_evl_msaa_obj_focus_proc(HWINEVENTHOOK hWinEventHook, DWORD event, -+ HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, -+ DWORD dwmsEventTime) -+{ -+ return; -+} -+ - /* - * UI Automation Event Listener functions. - * The first time an event handler interface is added on the client side, the -@@ -44,6 +64,11 @@ static HRESULT uia_event_listener_thread_initialize(struct uia_evl *evl) - if (!TlsSetValue(tls_index, (LPVOID)evl)) - FIXME("Failed to set Tls index value!\n"); - -+ evl->object_focus_hook = SetWinEventHook(EVENT_OBJECT_FOCUS, -+ EVENT_OBJECT_FOCUS, 0, uia_evl_msaa_obj_focus_proc, 0, 0, WINEVENT_OUTOFCONTEXT); -+ evl->win_creation_hook = SetWinEventHook(EVENT_OBJECT_CREATE, -+ EVENT_OBJECT_CREATE, 0, uia_evl_window_create_proc, 0, 0, WINEVENT_OUTOFCONTEXT); -+ - return S_OK; - } - -@@ -51,6 +76,9 @@ static void uia_event_listener_thread_exit(struct uia_evl *evl) - { - struct uia_data *data = evl->data; - -+ UnhookWinEvent(evl->object_focus_hook); -+ UnhookWinEvent(evl->win_creation_hook); -+ - heap_free(evl); - data->evl = NULL; - if (!TlsSetValue(tls_index, NULL)) -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index d3fd1aeef01..c832129f64b 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -60,6 +60,9 @@ struct uia_evl - CRITICAL_SECTION ev_handler_cs; - UINT tid; - -+ HWINEVENTHOOK win_creation_hook; -+ HWINEVENTHOOK object_focus_hook; -+ - struct uia_data *data; - - struct list uia_evh_list; -From 5c1113a2e8b6b011fa5ecdeaa26879c60dd0b93a Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 29 Jun 2021 13:00:49 -0400 -Subject: [PATCH] uiautomationcore: Add event message queue. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_event.c | 187 +++++++++++++++++++++++++++- - dlls/uiautomationcore/uia_private.h | 34 +++++ - 2 files changed, 220 insertions(+), 1 deletion(-) - -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index 03d9e59e1a7..f429523867d 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -26,6 +26,59 @@ WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); - - DWORD tls_index = TLS_OUT_OF_INDEXES; - -+static HRESULT uia_evm_add_msaa_event(struct uia_evl *evl, HWND hwnd, -+ LONG obj_id, LONG child_id, LONG event); -+ -+static EVENTID uia_msaa_event_to_uia_event_id(LONG obj_id, LONG event) -+{ -+ switch (event) -+ { -+ case EVENT_OBJECT_ACCELERATORCHANGE: return UIA_AcceleratorKeyPropertyId; -+ case EVENT_OBJECT_CREATE: return UIA_StructureChangedEventId; /* StructureChangeType_ChildAdded */ -+ case EVENT_OBJECT_DESTROY: return UIA_StructureChangedEventId; /* StructureChangeType_ChildRemoved */ -+ case EVENT_OBJECT_FOCUS: return UIA_AutomationFocusChangedEventId; -+ case EVENT_OBJECT_HELPCHANGE: return UIA_AutomationPropertyChangedEventId; /* UIA_HelpTextPropertyId change */ -+ case EVENT_OBJECT_LOCATIONCHANGE: return UIA_AutomationPropertyChangedEventId; /* UIA_BoundingRectanglePropertyId change */ -+ case EVENT_OBJECT_NAMECHANGE: return UIA_AutomationPropertyChangedEventId; /* UIA_NamePropertyId change */ -+ case EVENT_OBJECT_PARENTCHANGE: return UIA_StructureChangedEventId; /* unsure of StructureChangeType, needs tests. */ -+ case EVENT_OBJECT_REORDER: return UIA_StructureChangedEventId; /* StructureChangeType_ChildrenReordered? */ -+ case EVENT_OBJECT_SELECTION: return UIA_SelectionItem_ElementSelectedEventId; -+ case EVENT_OBJECT_SELECTIONADD: return UIA_SelectionItem_ElementAddedToSelectionEventId; -+ case EVENT_OBJECT_SELECTIONREMOVE: return UIA_SelectionItem_ElementRemovedFromSelectionEventId; -+ case EVENT_OBJECT_HIDE: return UIA_StructureChangedEventId; /* StructureChangeType_ChildRemoved */ -+ case EVENT_OBJECT_SHOW: return UIA_StructureChangedEventId; /* StructureChangeType_ChildAdded */ -+ case EVENT_OBJECT_STATECHANGE: return UIA_AutomationPropertyChangedEventId; /* Various property-changed events. */ -+ case EVENT_OBJECT_VALUECHANGE: return UIA_AutomationPropertyChangedEventId; /* UIA_RangeValueValuePropertyId or UIA_ValueValuePropertyId */ -+ case EVENT_SYSTEM_ALERT: return UIA_SystemAlertEventId; -+ case EVENT_SYSTEM_DIALOGEND: return UIA_Window_WindowClosedEventId; -+ case EVENT_SYSTEM_DIALOGSTART: return UIA_Window_WindowOpenedEventId; -+ case EVENT_SYSTEM_FOREGROUND: return UIA_AutomationFocusChangedEventId; -+ case EVENT_SYSTEM_MENUEND: return UIA_MenuModeEndEventId; -+ case EVENT_SYSTEM_MENUPOPUPEND: return UIA_MenuClosedEventId; -+ case EVENT_SYSTEM_MENUPOPUPSTART: return UIA_MenuOpenedEventId; -+ case EVENT_SYSTEM_MENUSTART: return UIA_MenuModeStartEventId; -+ case EVENT_SYSTEM_MINIMIZEEND: return UIA_AutomationPropertyChangedEventId; /* UIA_WindowWindowVisualStatePropertyId change */ -+ case EVENT_SYSTEM_MINIMIZESTART: return UIA_AutomationPropertyChangedEventId; /* UIA_WindowWindowVisualStatePropertyId change */ -+ case EVENT_SYSTEM_MOVESIZEEND: return UIA_AutomationPropertyChangedEventId; /* UIA_BoundingRectanglePropertyId change */ -+ case EVENT_SYSTEM_MOVESIZESTART: return UIA_AutomationPropertyChangedEventId; /* UIA_BoundingRectanglePropertyId change */ -+ case EVENT_SYSTEM_SCROLLINGEND: -+ case EVENT_SYSTEM_SCROLLINGSTART: -+ case 0x8015: /* FIXME: EVENT_OBJECT_CONTENTSCROLLED. Do we not have this defined? */ -+ if (obj_id == OBJID_VSCROLL) -+ return UIA_AutomationPropertyChangedEventId; /* UIA_ScrollVerticalScrollPercentPropertyId change */ -+ else if (obj_id == OBJID_HSCROLL) -+ return UIA_AutomationPropertyChangedEventId; /* UIA_ScrollHorizontalScrollPercentPropertyId change */ -+ FIXME("Scroll events only supported on OBJID_VSCROLL/OBJID_HSCROLL!\n"); -+ break; -+ -+ default: -+ FIXME("Unimplemented mapping for MSAA event %#x to UIA event!\n", event); -+ break; -+ } -+ -+ return 0; -+} -+ - /* - * Event hook callback for window creation events. - */ -@@ -43,7 +96,93 @@ void CALLBACK uia_evl_msaa_obj_focus_proc(HWINEVENTHOOK hWinEventHook, DWORD eve - HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, - DWORD dwmsEventTime) - { -- return; -+ struct uia_evl *evl; -+ HRESULT hr; -+ -+ if (idObject != OBJID_CLIENT && idObject != OBJID_WINDOW) -+ return; -+ -+ evl = (struct uia_evl *)TlsGetValue(tls_index); -+ hr = uia_evm_add_msaa_event(evl, hwnd, idObject, idChild, event); -+ if (FAILED(hr)) -+ FIXME("Failed to add event to event message queue!\n"); -+} -+ -+static void uia_evl_check_evh_evm_match(struct uia_evl *evl, struct uia_evm *evm) -+{ -+ struct list *evh_list = &evl->uia_evh_list; -+ struct list *cursor, *cursor2; -+ struct uia_evh *evh; -+ -+ EnterCriticalSection(&evl->ev_handler_cs); -+ -+ LIST_FOR_EACH_SAFE(cursor, cursor2, evh_list) -+ { -+ evh = LIST_ENTRY(cursor, struct uia_evh, entry); -+ -+ switch (evh->event_type) -+ { -+ case FOCUS_EVH: -+ { -+ IUIAutomationFocusChangedEventHandler *handler = evh->u.IUIAutomationFocusChangedEvh_iface; -+ -+ if (evm->event != UIA_AutomationFocusChangedEventId) -+ break; -+ -+ IUIAutomationFocusChangedEventHandler_HandleFocusChangedEvent(handler, evm->elem); -+ break; -+ } -+ -+ default: -+ break; -+ } -+ } -+ -+ LeaveCriticalSection(&evl->ev_handler_cs); -+} -+ -+static void uia_evl_process_evm_queue(struct uia_evl *evl) -+{ -+ struct list *evm_queue = &evl->uia_evm_queue; -+ struct list *cursor, *cursor2; -+ struct uia_evm *evm; -+ HRESULT hr; -+ -+ if (list_empty(&evl->uia_evm_queue)) -+ return; -+ -+ LIST_FOR_EACH_SAFE(cursor, cursor2, evm_queue) -+ { -+ evm = LIST_ENTRY(cursor, struct uia_evm, entry); -+ -+ if (evm->uia_evo == UIA_EVO_MSAA) -+ { -+ IAccessible *acc; -+ VARIANT child_id; -+ -+ hr = AccessibleObjectFromEvent(evm->u.msaa_ev.hwnd, evm->u.msaa_ev.obj_id, -+ evm->u.msaa_ev.child_id, &acc, &child_id); -+ if (FAILED(hr)) -+ goto message_abort; -+ -+ hr = create_uia_elem_from_msaa_acc(&evm->elem, acc, V_I4(&child_id)); -+ if (FAILED(hr)) -+ goto message_abort; -+ } -+ else -+ { -+ hr = create_uia_elem_from_raw_provider(&evm->elem, evm->u.uia_ev.elem_prov); -+ if (FAILED(hr)) -+ goto message_abort; -+ } -+ -+ uia_evl_check_evh_evm_match(evl, evm); -+ IUIAutomationElement_Release(evm->elem); -+ -+message_abort: -+ list_remove(cursor); -+ heap_free(evm); -+ } - } - - /* -@@ -79,6 +218,9 @@ static void uia_event_listener_thread_exit(struct uia_evl *evl) - UnhookWinEvent(evl->object_focus_hook); - UnhookWinEvent(evl->win_creation_hook); - -+ DeleteCriticalSection(&evl->ev_handler_cs); -+ DeleteCriticalSection(&evl->evm_queue_cs); -+ - heap_free(evl); - data->evl = NULL; - if (!TlsSetValue(tls_index, NULL)) -@@ -115,6 +257,8 @@ static DWORD WINAPI uia_event_listener_main(LPVOID lpParam) - continue; - } - -+ uia_evl_process_evm_queue(evl); -+ - EnterCriticalSection(&evl->ev_handler_cs); - - if (list_empty(&evl->uia_evh_list)) -@@ -144,6 +288,7 @@ static HRESULT start_uia_event_listener(struct uia_data *data) - - evl->data = data; - list_init(&evl->uia_evh_list); -+ list_init(&evl->uia_evm_queue); - - /* - * Create an event handler to signal when the event listener threads -@@ -152,6 +297,7 @@ static HRESULT start_uia_event_listener(struct uia_data *data) - evl->pump_initialized = CreateEventW(NULL, 0, 0, NULL); - evl->first_event = CreateEventW(NULL, 0, 0, NULL); - InitializeCriticalSection(&evl->ev_handler_cs); -+ InitializeCriticalSection(&evl->evm_queue_cs); - - evl->h_thread = CreateThread(NULL, 0, uia_event_listener_main, evl, 0, &evl->tid); - -@@ -302,3 +448,42 @@ HRESULT uia_evh_remove_all_event_handlers(struct uia_data *data) - - return S_OK; - } -+ -+/* -+ * uia_evm (Event Message) functions. -+ */ -+ -+/* -+ * Add an event message to the message queue. -+ */ -+static HRESULT uia_evm_add_message_to_queue(struct uia_evl *evl, struct uia_evm *evm) -+{ -+ EnterCriticalSection(&evl->evm_queue_cs); -+ -+ list_add_tail(&evl->uia_evm_queue, &evm->entry); -+ -+ LeaveCriticalSection(&evl->evm_queue_cs); -+ PostThreadMessageW(evl->tid, WM_NULL, 0, 0); -+ -+ return S_OK; -+} -+ -+static HRESULT uia_evm_add_msaa_event(struct uia_evl *evl, HWND hwnd, -+ LONG obj_id, LONG child_id, LONG event) -+{ -+ struct uia_evm *evm = heap_alloc_zero(sizeof(*evm)); -+ -+ TRACE("evl %p, hwnd %p, obj_id %d, child_id %d, event_id %d\n", evl, hwnd, obj_id, child_id, event); -+ if (!evm) -+ return E_OUTOFMEMORY; -+ -+ evm->uia_evo = UIA_EVO_MSAA; -+ evm->u.msaa_ev.hwnd = hwnd; -+ evm->u.msaa_ev.obj_id = obj_id; -+ evm->u.msaa_ev.child_id = child_id; -+ evm->event = uia_msaa_event_to_uia_event_id(obj_id, event); -+ -+ uia_evm_add_message_to_queue(evl, evm); -+ -+ return S_OK; -+} -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index c832129f64b..e254ee38112 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -49,6 +49,38 @@ struct uia_evh - } u; - }; - -+/* -+ * EVM = Event message. Result of an event being raised, either with -+ * UiaRaiseAutomationEvent or an MSAA event with NotifyWinEvent. -+ */ -+struct uia_evm -+{ -+ struct list entry; -+ -+ UINT event; -+ IUIAutomationElement *elem; -+ -+ enum uia_event_origin -+ { -+ UIA_EVO_MSAA, -+ UIA_EVO_UIA, -+ } uia_evo; -+ -+ union -+ { -+ struct -+ { -+ HWND hwnd; -+ -+ LONG obj_id, child_id; -+ } msaa_ev; -+ struct -+ { -+ IRawElementProviderSimple *elem_prov; -+ } uia_ev; -+ } u; -+}; -+ - struct uia_data; - - /* -@@ -58,6 +90,7 @@ struct uia_evl - { - HANDLE h_thread, pump_initialized, first_event; - CRITICAL_SECTION ev_handler_cs; -+ CRITICAL_SECTION evm_queue_cs; - UINT tid; - - HWINEVENTHOOK win_creation_hook; -@@ -66,6 +99,7 @@ struct uia_evl - struct uia_data *data; - - struct list uia_evh_list; -+ struct list uia_evm_queue; - }; - - struct uia_data { -From 266b96c0381cef3551f37981e57726b9d6c64c83 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 26 Jul 2021 14:53:44 -0400 -Subject: [PATCH] uiautomationcore: Add custom IUIAEvlConnection interface. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_event.c | 128 ++++++++++++++++++++++++++++ - dlls/uiautomationcore/uia_private.h | 12 +++ - include/uiautomationcore.idl | 17 ++++ - 3 files changed, 157 insertions(+) - -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index f429523867d..be637edeb2d 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -28,6 +28,107 @@ DWORD tls_index = TLS_OUT_OF_INDEXES; - - static HRESULT uia_evm_add_msaa_event(struct uia_evl *evl, HWND hwnd, - LONG obj_id, LONG child_id, LONG event); -+static HRESULT uia_evm_add_uia_event(struct uia_evl *evl, -+ IRawElementProviderSimple *elem_prov, UINT event); -+ -+/* -+ * Custom COM interface that is passed to UIA providers. Allows them to raise -+ * events to be sent to any clients with active event listener threads. -+ */ -+static inline struct uia_evlc *impl_from_IUIAEvlConnection(IUIAEvlConnection *iface) -+{ -+ return CONTAINING_RECORD(iface, struct uia_evlc, IUIAEvlConnection_iface); -+} -+ -+static HRESULT WINAPI evlc_QueryInterface(IUIAEvlConnection *iface, REFIID riid, -+ void **ppvObject) -+{ -+ struct uia_evlc *This = impl_from_IUIAEvlConnection(iface); -+ -+ TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject); -+ -+ if (IsEqualIID(riid, &IID_IUIAEvlConnection) || -+ IsEqualIID(riid, &IID_IUnknown)) -+ *ppvObject = iface; -+ else -+ { -+ WARN("no interface: %s\n", debugstr_guid(riid)); -+ *ppvObject = NULL; -+ return E_NOINTERFACE; -+ } -+ -+ IUIAEvlConnection_AddRef(iface); -+ -+ return S_OK; -+} -+ -+static ULONG WINAPI evlc_AddRef(IUIAEvlConnection *iface) -+{ -+ struct uia_evlc *This = impl_from_IUIAEvlConnection(iface); -+ ULONG ref = InterlockedIncrement(&This->ref); -+ -+ TRACE("(%p) ref = %u\n", This, ref); -+ return ref; -+} -+ -+static FORCEINLINE ULONG WINAPI evlc_Release(IUIAEvlConnection *iface) -+{ -+ struct uia_evlc *This = impl_from_IUIAEvlConnection(iface); -+ ULONG ref = InterlockedDecrement(&This->ref); -+ -+ TRACE("(%p) ref = %u\n", This, ref); -+ -+ if(!ref) -+ heap_free(This); -+ -+ return ref; -+} -+ -+static HRESULT WINAPI evlc_ProviderRaiseEvent(IUIAEvlConnection *iface, -+ LONG event_type, IRawElementProviderSimple *pRetVal) -+{ -+ struct uia_evlc *This = impl_from_IUIAEvlConnection(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ /* Do stuff here. */ -+ IRawElementProviderSimple_AddRef(pRetVal); -+ uia_evm_add_uia_event(This->evl, pRetVal, event_type); -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI evlc_CheckListenerStatus(IUIAEvlConnection *iface, -+ VARIANT *val) -+{ -+ V_VT(val) = VT_BOOL; -+ V_BOOL(val) = VARIANT_TRUE; -+ -+ return S_OK; -+} -+ -+static const IUIAEvlConnectionVtbl uia_evlc_vtbl = { -+ evlc_QueryInterface, -+ evlc_AddRef, -+ evlc_Release, -+ evlc_ProviderRaiseEvent, -+ evlc_CheckListenerStatus, -+}; -+ -+static HRESULT create_uia_evlc_iface(IUIAEvlConnection **iface) -+{ -+ struct uia_evlc *uia; -+ -+ uia = heap_alloc_zero(sizeof(*uia)); -+ if (!uia) -+ return E_OUTOFMEMORY; -+ -+ uia->IUIAEvlConnection_iface.lpVtbl = &uia_evlc_vtbl; -+ uia->ref = 1; -+ *iface = &uia->IUIAEvlConnection_iface; -+ -+ return S_OK; -+} - - static EVENTID uia_msaa_event_to_uia_event_id(LONG obj_id, LONG event) - { -@@ -208,6 +309,12 @@ static HRESULT uia_event_listener_thread_initialize(struct uia_evl *evl) - evl->win_creation_hook = SetWinEventHook(EVENT_OBJECT_CREATE, - EVENT_OBJECT_CREATE, 0, uia_evl_window_create_proc, 0, 0, WINEVENT_OUTOFCONTEXT); - -+ /* -+ * Create interface to be passed to providers so that they can signal -+ * events to active listeners. -+ */ -+ create_uia_evlc_iface(&evl->evlc_iface); -+ - return S_OK; - } - -@@ -218,6 +325,9 @@ static void uia_event_listener_thread_exit(struct uia_evl *evl) - UnhookWinEvent(evl->object_focus_hook); - UnhookWinEvent(evl->win_creation_hook); - -+ CoDisconnectObject((IUnknown *)evl->evlc_iface, 0); -+ IUIAEvlConnection_Release(evl->evlc_iface); -+ - DeleteCriticalSection(&evl->ev_handler_cs); - DeleteCriticalSection(&evl->evm_queue_cs); - -@@ -487,3 +597,21 @@ static HRESULT uia_evm_add_msaa_event(struct uia_evl *evl, HWND hwnd, - - return S_OK; - } -+ -+static HRESULT uia_evm_add_uia_event(struct uia_evl *evl, -+ IRawElementProviderSimple *elem_prov, UINT event) -+{ -+ struct uia_evm *evm = heap_alloc_zero(sizeof(*evm)); -+ -+ TRACE("evl %p, elem_prov %p, event %#x\n", evl, elem_prov, event); -+ if (!evm) -+ return E_OUTOFMEMORY; -+ -+ evm->uia_evo = UIA_EVO_UIA; -+ evm->u.uia_ev.elem_prov = elem_prov; -+ evm->event = event; -+ -+ uia_evm_add_message_to_queue(evl, evm); -+ -+ return S_OK; -+} -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index e254ee38112..2f329206251 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -95,6 +95,7 @@ struct uia_evl - - HWINEVENTHOOK win_creation_hook; - HWINEVENTHOOK object_focus_hook; -+ IUIAEvlConnection *evlc_iface; - - struct uia_data *data; - -@@ -102,6 +103,17 @@ struct uia_evl - struct list uia_evm_queue; - }; - -+/* -+ * EVLC = Event listener connection. -+ */ -+struct uia_evlc -+{ -+ IUIAEvlConnection IUIAEvlConnection_iface; -+ LONG ref; -+ -+ struct uia_evl *evl; -+}; -+ - struct uia_data { - IUIAutomation IUIAutomation_iface; - LONG ref; -diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl -index e10c2316ceb..7d33bde45a4 100644 ---- a/include/uiautomationcore.idl -+++ b/include/uiautomationcore.idl -@@ -291,4 +291,21 @@ library UIA - - HRESULT GetFocus([out, retval] IRawElementProviderFragment **pRetVal); - } -+ -+#ifdef __WIDL__ -+ [ -+ object, -+ uuid(5d419260-d515-11eb-b8bc-0242ac130003), -+ oleautomation, -+ pointer_default(unique) -+ ] -+ interface IUIAEvlConnection : IUnknown -+ { -+ HRESULT ProviderRaiseEvent( -+ [in] long event, -+ [in] IRawElementProviderSimple *pRetVal); -+ HRESULT CheckListenerStatus( -+ [out, retval] VARIANT *val); -+ } -+#endif - } -From bc57cedd3c832269380c75ea9fa2b15c644b9565 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 26 Jul 2021 15:04:37 -0400 -Subject: [PATCH] uiautomationcore: Send UI Automation Providers an event - listener interface. - -Send UI Automation providers an IUIAEvlConnection interface so that they -can send raised events to active event listeners. Pass this interface by -modifying UiaReturnRawElementProvider's wParam value. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_event.c | 115 +++++++++++++++++++++++++++++- - dlls/uiautomationcore/uia_main.c | 71 +++++++++++++++++- - 2 files changed, 183 insertions(+), 3 deletions(-) - -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index be637edeb2d..fcb0907101c 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -31,6 +31,102 @@ static HRESULT uia_evm_add_msaa_event(struct uia_evl *evl, HWND hwnd, - static HRESULT uia_evm_add_uia_event(struct uia_evl *evl, - IRawElementProviderSimple *elem_prov, UINT event); - -+/* -+ * FIXME: Need to keep track of each UIA provider window, and be able to -+ * dynamically use the IRawElementProviderAdviseEvents interface to add/remove -+ * events as they are added/removed. For now, we're just adding the -+ * UIA_AutomationFocusChangedEventId event if the fragment root exposes -+ * an IRawElementProviderAdviseEvents interface. -+ */ -+static void uia_get_advise_events_iface(IRawElementProviderSimple *elprov) -+{ -+ IRawElementProviderAdviseEvents *elem_events = NULL; -+ IRawElementProviderFragmentRoot *frag_root = NULL; -+ IRawElementProviderFragment *elem_frag = NULL; -+ HRESULT hr; -+ -+ hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragment, (void **)&elem_frag); -+ if (FAILED(hr) || !elem_frag) -+ return; -+ -+ hr = IRawElementProviderFragment_get_FragmentRoot(elem_frag, &frag_root); -+ if (FAILED(hr) || !frag_root) -+ goto exit; -+ -+ hr = IRawElementProviderFragmentRoot_QueryInterface(frag_root, &IID_IRawElementProviderAdviseEvents, (void **)&elem_events); -+ if (FAILED(hr) || !elem_events) -+ goto exit; -+ -+ IRawElementProviderAdviseEvents_AdviseEventAdded(elem_events, UIA_AutomationFocusChangedEventId, NULL); -+ -+exit: -+ if (elem_frag) -+ IRawElementProviderFragment_Release(elem_frag); -+ if (frag_root) -+ IRawElementProviderFragmentRoot_Release(frag_root); -+ if (elem_events) -+ IRawElementProviderAdviseEvents_Release(elem_events); -+} -+ -+/* -+ * Check if a window responds to a request for a UI Automation object, and if -+ * it does, send it an event listener connection interface. -+ */ -+static BOOL uia_evl_attempt_evlc_connect(HWND hwnd, IUIAEvlConnection *iface) -+{ -+ IRawElementProviderSimple *elem_prov; -+ LRESULT lres; -+ HRESULT hr; -+ -+ lres = SendMessageW(hwnd, WM_GETOBJECT, 0, UiaRootObjectId); -+ if (!lres || FAILED(lres)) -+ return FALSE; -+ -+ /* -+ * This confirms we have an actual UI Automation provider, release the -+ * returned raw element provider interface and send an evlc interface. -+ */ -+ hr = ObjectFromLresult(lres, &IID_IRawElementProviderSimple, 0, -+ (void **)&elem_prov); -+ if (FAILED(hr)) -+ return FALSE; -+ -+ uia_get_advise_events_iface(elem_prov); -+ IRawElementProviderSimple_Release(elem_prov); -+ -+ /* FIXME: Probably a less hacky way to do this. Revisit later. */ -+ lres = LresultFromObject(&IID_IUIAEvlConnection, 0, (IUnknown *)iface); -+ PostMessageW(hwnd, WM_GETOBJECT, (WPARAM)lres, UiaRootObjectId); -+ -+ return TRUE; -+} -+ -+/* -+ * Attempt to send an evlc interface to a window if it's a UIA Provider. -+ * If it isn't, try to get an IAccessible from it so that if it has -+ * accessibility functionality, it gets activated. -+ */ -+static void uia_evl_query_hwnd(HWND hwnd, struct uia_evl *evl) -+{ -+ IAccessible *acc; -+ WCHAR buf[256]; -+ -+ /* -+ * FIXME: Ignore windows that are obviously created by Wine. Before I did -+ * this, there'd be random hangs. Might be a better solution. -+ */ -+ if (GetClassNameW(hwnd, buf, ARRAY_SIZE(buf)) && (!lstrcmpW(buf, L"OleMainThreadWndClass") || -+ !lstrcmpW(buf, L"IME"))) -+ return; -+ -+ if (uia_evl_attempt_evlc_connect(hwnd, evl->evlc_iface)) -+ return; -+ -+ AccessibleObjectFromWindow(hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc); -+ if (acc) -+ IAccessible_Release(acc); -+} -+ - /* - * Custom COM interface that is passed to UIA providers. Allows them to raise - * events to be sent to any clients with active event listener threads. -@@ -187,7 +283,11 @@ void CALLBACK uia_evl_window_create_proc(HWINEVENTHOOK hWinEventHook, DWORD even - HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, - DWORD dwmsEventTime) - { -- return; -+ if (event == EVENT_OBJECT_CREATE && idObject == OBJID_WINDOW) -+ { -+ struct uia_evl *evl = (struct uia_evl *)TlsGetValue(tls_index); -+ uia_evl_query_hwnd(hwnd, evl); -+ } - } - - /* -@@ -286,6 +386,17 @@ static void uia_evl_process_evm_queue(struct uia_evl *evl) - } - } - -+/* -+ * Upon event listener creation, query each window on the desktop for -+ * accessibility data. Once started, new windows will be queried upon -+ * creation. -+ */ -+static BOOL CALLBACK uia_evl_enumerate_windows(HWND hwnd, LPARAM lparam) -+{ -+ uia_evl_query_hwnd(hwnd, (struct uia_evl *)lparam); -+ return TRUE; -+} -+ - /* - * UI Automation Event Listener functions. - * The first time an event handler interface is added on the client side, the -@@ -314,6 +425,8 @@ static HRESULT uia_event_listener_thread_initialize(struct uia_evl *evl) - * events to active listeners. - */ - create_uia_evlc_iface(&evl->evlc_iface); -+ impl_from_IUIAEvlConnection(evl->evlc_iface)->evl = evl; -+ EnumWindows(uia_evl_enumerate_windows, (LPARAM)evl); - - return S_OK; - } -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index c8a3795ed1b..46ba4cbeacc 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -259,13 +259,51 @@ IRawElementProviderSimpleVtbl hwnd_host_provider_vtbl = { - hwnd_host_provider_get_HostRawElementProvider, - }; - -+struct uia_provider_evlc -+{ -+ struct list entry; -+ -+ IUIAEvlConnection *evlc_iface; -+}; -+ -+static struct list global_provider_evlc_list = LIST_INIT( global_provider_evlc_list ); -+ -+/* -+ * Check the current list of evlc's on the provider side to see if they are -+ * still active. If not, remove them from the list. -+ */ -+static void prune_listener_list(void) -+{ -+ struct uia_provider_evlc *evlc; -+ struct list *cursor, *cursor2; -+ VARIANT var; -+ HRESULT hr; -+ -+ LIST_FOR_EACH_SAFE(cursor, cursor2, &global_provider_evlc_list) -+ { -+ evlc = LIST_ENTRY(cursor, struct uia_provider_evlc, entry); -+ hr = IUIAEvlConnection_CheckListenerStatus(evlc->evlc_iface, &var); -+ if (hr == CO_E_OBJNOTCONNECTED) -+ { -+ list_remove(cursor); -+ IUIAEvlConnection_Release(evlc->evlc_iface); -+ heap_free(evlc); -+ } -+ } -+} -+ - /*********************************************************************** - * UiaClientsAreListening (uiautomationcore.@) - */ - BOOL WINAPI UiaClientsAreListening(void) - { -- FIXME("()\n"); -- return FALSE; -+ TRACE("()\n"); -+ -+ prune_listener_list(); -+ if (list_empty(&global_provider_evlc_list)) -+ return FALSE; -+ -+ return TRUE; - } - - /*********************************************************************** -@@ -321,6 +359,35 @@ LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, - return 0; - } - -+ /* -+ * If a client send a WM_GETOBJECT message with a wParam value that isn't -+ * 0, it's attempting to send an IUIAEvlConnection interface so that the -+ * provider can signal events to the event listener. -+ */ -+ if (wParam) -+ { -+ IUIAEvlConnection *evlc_iface; -+ VARIANT var; -+ HRESULT hr; -+ -+ TRACE("Client sent IUIAEvlConnection interface!\n"); -+ hr = ObjectFromLresult((LRESULT)wParam, &IID_IUIAEvlConnection, 0, -+ (void **)&evlc_iface); -+ hr = IUIAEvlConnection_CheckListenerStatus(evlc_iface, &var); -+ if (SUCCEEDED(hr)) -+ { -+ struct uia_provider_evlc *uia = heap_alloc_zero(sizeof(*uia)); -+ if (!uia) -+ return 0; -+ -+ /* If success, add this to the providers listening clients list. */ -+ uia->evlc_iface = evlc_iface; -+ list_add_tail(&global_provider_evlc_list, &uia->entry); -+ } -+ -+ return 0; -+ } -+ - return LresultFromObject(&IID_IRawElementProviderSimple, wParam, (IUnknown *)elprov); - } - -From 4d476fc39a73a3c279976d52edb4e73f5cd676ad Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Wed, 30 Jun 2021 09:35:50 -0400 -Subject: [PATCH] uiautomationcore: Implement UiaRaiseAutomationEvent. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_main.c | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index 46ba4cbeacc..952a9d47a0d 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -396,7 +396,26 @@ LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, - */ - HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVENTID id) - { -- FIXME("(%p, %d): stub\n", provider, id); -+ struct uia_provider_evlc *evlc; -+ struct list *cursor, *cursor2; -+ HRESULT hr; -+ -+ TRACE("(%p, %d)\n", provider, id); -+ -+ LIST_FOR_EACH_SAFE(cursor, cursor2, &global_provider_evlc_list) -+ { -+ evlc = LIST_ENTRY(cursor, struct uia_provider_evlc, entry); -+ hr = IUIAEvlConnection_ProviderRaiseEvent(evlc->evlc_iface, id, provider); -+ TRACE("Event raised!\n"); -+ if (hr == CO_E_OBJNOTCONNECTED) -+ { -+ TRACE("Evlc no longer active, removing.\n"); -+ list_remove(cursor); -+ IUIAEvlConnection_Release(evlc->evlc_iface); -+ heap_free(evlc); -+ } -+ } -+ - return S_OK; - } - -From 0790c4220b451ab36c3412b2bf14cd9bb86979ad Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 1 Jun 2021 09:18:41 -0400 -Subject: [PATCH] tabtip: Create tabtip.exe. - -TabTIP: Tablet text input panel. This program watches for editable text -input fields gaining focus and runs an event handler when this occurs. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - configure | 2 + - configure.ac | 1 + - programs/tabtip/Makefile.in | 6 + - programs/tabtip/tabtip.c | 365 ++++++++++++++++++++++++++++++++++++ - 4 files changed, 374 insertions(+) - create mode 100644 programs/tabtip/Makefile.in - create mode 100644 programs/tabtip/tabtip.c - -diff --git a/configure b/configure -index e4cb2ec69e2..2c7c59e8996 100755 ---- a/configure -+++ b/configure -@@ -1905,6 +1905,7 @@ enable_start - enable_subst - enable_svchost - enable_systeminfo -+enable_tabtip - enable_taskkill - enable_tasklist - enable_taskmgr -@@ -22688,6 +22689,7 @@ wine_fn_config_makefile programs/start enable_start - wine_fn_config_makefile programs/subst enable_subst - wine_fn_config_makefile programs/svchost enable_svchost - wine_fn_config_makefile programs/systeminfo enable_systeminfo -+wine_fn_config_makefile programs/tabtip enable_tabtip - wine_fn_config_makefile programs/taskkill enable_taskkill - wine_fn_config_makefile programs/tasklist enable_tasklist - wine_fn_config_makefile programs/taskmgr enable_taskmgr -diff --git a/configure.ac b/configure.ac -index b1044c175b0..b6d0e64c2b8 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3651,6 +3651,7 @@ WINE_CONFIG_MAKEFILE(programs/start) - WINE_CONFIG_MAKEFILE(programs/subst) - WINE_CONFIG_MAKEFILE(programs/svchost) - WINE_CONFIG_MAKEFILE(programs/systeminfo) -+WINE_CONFIG_MAKEFILE(programs/tabtip) - WINE_CONFIG_MAKEFILE(programs/taskkill) - WINE_CONFIG_MAKEFILE(programs/tasklist) - WINE_CONFIG_MAKEFILE(programs/taskmgr) -diff --git a/programs/tabtip/Makefile.in b/programs/tabtip/Makefile.in -new file mode 100644 -index 00000000000..846b813be69 ---- /dev/null -+++ b/programs/tabtip/Makefile.in -@@ -0,0 +1,6 @@ -+MODULE = tabtip.exe -+IMPORTS = uuid ole32 user32 oleacc uiautomationcore rpcrt4 shell32 -+ -+EXTRADLLFLAGS = -mconsole -municode -mno-cygwin -+ -+C_SRCS = tabtip.c -diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c -new file mode 100644 -index 00000000000..18b8ae32ef8 ---- /dev/null -+++ b/programs/tabtip/tabtip.c -@@ -0,0 +1,365 @@ -+/* -+ * Copyright 2021 Connor McAdams -+ * -+ * 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 "windows.h" -+#define COBJMACROS -+#include -+#include "uiautomation.h" -+#include "ole2.h" -+#include "strsafe.h" -+#include "oleacc.h" -+#include "shellapi.h" -+#include -+#include -+ -+#include "wine/debug.h" -+#ifndef UNICODE -+#define UNICODE -+#endif -+ -+WINE_DEFAULT_DEBUG_CHANNEL(tabtip); -+ -+extern HANDLE CDECL __wine_make_process_system(void); -+LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -+ -+enum { -+ EVENT_PGM_EXIT, -+ EVENT_WINE_EXIT, -+ THREAD_EVENT_COUNT, -+}; -+ -+struct thread_data { -+ HANDLE events[THREAD_EVENT_COUNT]; -+ HWND main_hwnd; -+}; -+ -+typedef struct { -+ IUIAutomationFocusChangedEventHandler IUIAutomationFocusChangedEventHandler_iface; -+ LONG ref; -+} event_data; -+ -+DWORD last_keyup_event; -+BOOL keyboard_up; -+ -+static const char *ct_id_str[] = { -+ "UIA_ButtonControlTypeId (50000)", -+ "UIA_CalendarControlTypeId (50001)", -+ "UIA_CheckBoxControlTypeId (50002)", -+ "UIA_ComboBoxControlTypeId (50003)", -+ "UIA_EditControlTypeId (50004)", -+ "UIA_HyperlinkControlTypeId (50005)", -+ "UIA_ImageControlTypeId (50006)", -+ "UIA_ListItemControlTypeId (50007)", -+ "UIA_ListControlTypeId (50008)", -+ "UIA_MenuControlTypeId (50009)", -+ "UIA_MenuBarControlTypeId (50010)", -+ "UIA_MenuItemControlTypeId (50011)", -+ "UIA_ProgressBarControlTypeId (50012)", -+ "UIA_RadioButtonControlTypeId (50013)", -+ "UIA_ScrollBarControlTypeId (50014)", -+ "UIA_SliderControlTypeId (50015)", -+ "UIA_SpinnerControlTypeId (50016)", -+ "UIA_StatusBarControlTypeId (50017)", -+ "UIA_TabControlTypeId (50018)", -+ "UIA_TabItemControlTypeId (50019)", -+ "UIA_TextControlTypeId (50020)", -+ "UIA_ToolBarControlTypeId (50021)", -+ "UIA_ToolTipControlTypeId (50022)", -+ "UIA_TreeControlTypeId (50023)", -+ "UIA_TreeItemControlTypeId (50024)", -+ "UIA_CustomControlTypeId (50025)", -+ "UIA_GroupControlTypeId (50026)", -+ "UIA_ThumbControlTypeId (50027)", -+ "UIA_DataGridControlTypeId (50028)", -+ "UIA_DataItemControlTypeId (50029)", -+ "UIA_DocumentControlTypeId (50030)", -+ "UIA_SplitButtonControlTypeId (50031)", -+ "UIA_WindowControlTypeId (50032)", -+ "UIA_PaneControlTypeId (50033)", -+ "UIA_HeaderControlTypeId (50034)", -+ "UIA_HeaderItemControlTypeId (50035)", -+ "UIA_TableControlTypeId (50036)", -+ "UIA_TitleBarControlTypeId (50037)", -+ "UIA_SeparatorControlTypeId (50038)", -+ "UIA_SemanticZoomControlTypeId (50039)", -+ "UIA_AppBarControlTypeId (50040)", -+}; -+ -+/* -+ * IUIAutomationFocusChangedEventHandler vtbl. -+ */ -+static inline event_data *impl_from_uia_focus_event(IUIAutomationFocusChangedEventHandler *iface) -+{ -+ return CONTAINING_RECORD(iface, event_data, IUIAutomationFocusChangedEventHandler_iface); -+} -+ -+HRESULT WINAPI uia_focus_event_QueryInterface(IUIAutomationFocusChangedEventHandler *iface, -+ REFIID riid, void **ppv) -+{ -+ event_data *This = impl_from_uia_focus_event(iface); -+ -+ WINE_TRACE("This %p, %s\n", This, debugstr_guid( riid )); -+ if (IsEqualIID(riid, &IID_IUIAutomationFocusChangedEventHandler) || -+ IsEqualIID(riid, &IID_IUnknown)) { -+ *ppv = iface; -+ } else { -+ *ppv = NULL; -+ return E_NOINTERFACE; -+ } -+ -+ IUIAutomationFocusChangedEventHandler_AddRef(iface); -+ return S_OK; -+} -+ -+ULONG WINAPI uia_focus_event_AddRef(IUIAutomationFocusChangedEventHandler* iface) -+{ -+ event_data *This = impl_from_uia_focus_event(iface); -+ ULONG ref = InterlockedIncrement(&This->ref); -+ -+ WINE_TRACE("This %p, ref %d\n", This, ref); -+ -+ return ref; -+} -+ -+ULONG WINAPI uia_focus_event_Release(IUIAutomationFocusChangedEventHandler* iface) -+{ -+ event_data *This = impl_from_uia_focus_event(iface); -+ ULONG ref = InterlockedDecrement(&This->ref); -+ -+ WINE_TRACE("This %p, ref %d\n", This, ref); -+ -+ return ref; -+} -+ -+/*** IUIAutomationFocusChangedEventHandler methods ***/ -+HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChangedEventHandler *iface, -+ IUIAutomationElement *sender) -+{ -+ event_data *This = impl_from_uia_focus_event(iface); -+ -+ WINE_TRACE("This %p, sender %p\n", This, sender); -+ if (sender) -+ { -+ VARIANT var; -+ INT ct_id; -+ BSTR name; -+ -+ IUIAutomationElement_get_CurrentControlType(sender, &ct_id); -+ IUIAutomationElement_get_CurrentName(sender, &name); -+ IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); -+ -+ if ((last_keyup_event < (GetTickCount() - 5000)) && -+ ct_id == UIA_EditControlTypeId && (V_VT(&var) == VT_BOOL && V_BOOL(&var))) -+ { -+ if (!keyboard_up) -+ { -+ WINE_TRACE("Keyboard up!\n"); -+ keyboard_up = TRUE; -+ ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); -+ -+ last_keyup_event = GetTickCount(); -+ } -+ } -+ else -+ { -+ if (keyboard_up) -+ { -+ WINE_TRACE("Keyboard down!\n"); -+ keyboard_up = FALSE; -+ } -+ } -+ -+ if (ct_id >= 50000) -+ ct_id -= 50000; -+ else -+ ct_id = 0; -+ -+ WINE_TRACE("element name: %s, ct_id %s\n", wine_dbgstr_w(name), ct_id_str[ct_id]); -+ } -+ -+ return S_OK; -+} -+ -+IUIAutomationFocusChangedEventHandlerVtbl uia_focus_event_vtbl = { -+ uia_focus_event_QueryInterface, -+ uia_focus_event_AddRef, -+ uia_focus_event_Release, -+ uia_focus_event_HandleFocusChangedEvent, -+}; -+ -+static HRESULT create_uia_event_handler(IUIAutomation **uia_iface, event_data *data) -+{ -+ HRESULT hr; -+ -+ hr = CoCreateInstance(&CLSID_CUIAutomation, NULL, CLSCTX_INPROC_SERVER, -+ &IID_IUIAutomation, (void **)uia_iface); -+ if (FAILED(hr)) -+ { -+ ERR("Failed to create IUIAutomation interface, hr %#x\n", hr); -+ return hr; -+ } -+ -+ data->IUIAutomationFocusChangedEventHandler_iface.lpVtbl = &uia_focus_event_vtbl; -+ data->ref = 1; -+ -+ hr = IUIAutomation_AddFocusChangedEventHandler(*uia_iface, NULL, -+ &data->IUIAutomationFocusChangedEventHandler_iface); -+ if (FAILED(hr)) -+ ERR("Failed to add focus changed event handler, hr %#x\n", hr); -+ -+ return hr; -+} -+ -+static DWORD WINAPI tabtip_exit_watcher(LPVOID lpParam) -+{ -+ struct thread_data *data = (struct thread_data *)lpParam; -+ DWORD event; -+ -+ event = WaitForMultipleObjects(THREAD_EVENT_COUNT, data->events, FALSE, INFINITE); -+ switch (event) -+ { -+ case EVENT_PGM_EXIT: -+ break; -+ -+ case EVENT_WINE_EXIT: -+ PostMessageW(data->main_hwnd, WM_DESTROY, 0, 0); -+ break; -+ -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) -+{ -+ HANDLE wine_exit_event, pgm_exit_event, started_event; -+ // Register the window class. -+ const wchar_t CLASS_NAME[] = L"IPTip_Main_Window"; -+ struct thread_data t_data = { }; -+ IUIAutomation *uia_iface; -+ WNDCLASSW wc = { }; -+ event_data data = { }; -+ MSG msg = { }; -+ int ret = 0; -+ HWND hwnd; -+ -+ wine_exit_event = pgm_exit_event = started_event = NULL; -+ last_keyup_event = 0; -+ keyboard_up = FALSE; -+ -+ NtSetInformationProcess( GetCurrentProcess(), ProcessWineMakeProcessSystem, -+ &wine_exit_event, sizeof(HANDLE *) ); -+ pgm_exit_event = CreateEventW(NULL, 0, 0, NULL); -+ started_event = CreateEventW(NULL, TRUE, FALSE, L"TABTIP_STARTED_EVENT"); -+ -+ if (!pgm_exit_event || !wine_exit_event || !started_event) -+ { -+ ERR("Failed to create event handles!\n"); -+ ret = -1; -+ goto exit; -+ } -+ -+ wc.lpfnWndProc = WindowProc; -+ wc.hInstance = hInstance; -+ wc.lpszClassName = CLASS_NAME; -+ -+ RegisterClassW(&wc); -+ -+ hwnd = CreateWindowExW(0, CLASS_NAME, -+ L"Input", WS_OVERLAPPEDWINDOW, 4, 4, 0, 0, NULL, -+ NULL, hInstance, NULL); -+ -+ if (!hwnd) -+ { -+ ERR("Failed to create hwnd!\n"); -+ ret = -1; -+ goto exit; -+ } -+ -+ if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) -+ { -+ ERR("CoInitialize failed!\n"); -+ ret = -1; -+ goto exit; -+ } -+ -+ if (FAILED(create_uia_event_handler(&uia_iface, &data))) -+ { -+ ret = -1; -+ goto exit; -+ } -+ -+ t_data.events[EVENT_WINE_EXIT] = wine_exit_event; -+ t_data.events[EVENT_PGM_EXIT] = pgm_exit_event; -+ t_data.main_hwnd = hwnd; -+ -+ SetEvent(started_event); -+ CreateThread(NULL, 0, tabtip_exit_watcher, &t_data, 0, NULL); -+ -+ while (GetMessageW(&msg, NULL, 0, 0)) -+ { -+ TranslateMessage(&msg); -+ DispatchMessageW(&msg); -+ } -+ -+ SetEvent(pgm_exit_event); -+ IUIAutomation_RemoveAllEventHandlers(uia_iface); -+ IUIAutomation_Release(uia_iface); -+ -+ CoUninitialize(); -+ -+exit: -+ -+ if (wine_exit_event) -+ CloseHandle(wine_exit_event); -+ -+ if (pgm_exit_event) -+ CloseHandle(pgm_exit_event); -+ -+ if (started_event) -+ CloseHandle(started_event); -+ -+ return ret; -+} -+ -+LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -+{ -+ switch (uMsg) -+ { -+ case WM_DESTROY: -+ PostQuitMessage(0); -+ return 0; -+ -+ case WM_PAINT: -+ { -+ PAINTSTRUCT ps; -+ HDC hdc = BeginPaint(hwnd, &ps); -+ -+ FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1)); -+ -+ EndPaint(hwnd, &ps); -+ } -+ return 0; -+ default: -+ break; -+ } -+ -+ return DefWindowProcW(hwnd, uMsg, wParam, lParam); -+} -From 79b36647ecc3984775491eb7ddf4d7975d9ebc51 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 27 Jul 2021 15:54:01 -0400 -Subject: [PATCH] ia2comproxy: Add proxy/stub dll for IAccessible2 interfaces. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - configure | 2 + - configure.ac | 1 + - dlls/ia2comproxy/Makefile.in | 10 + - dlls/ia2comproxy/ia2_classes.idl | 31 + - dlls/ia2comproxy/ia2comproxy.spec | 4 + - dlls/ia2comproxy/oleacc_classes.idl | 21 + - include/Makefile.in | 1 + - include/ia2api.idl | 5538 +++++++++++++++++++++++++++ - 8 files changed, 5608 insertions(+) - create mode 100644 dlls/ia2comproxy/Makefile.in - create mode 100644 dlls/ia2comproxy/ia2_classes.idl - create mode 100644 dlls/ia2comproxy/ia2comproxy.spec - create mode 100644 dlls/ia2comproxy/oleacc_classes.idl - create mode 100644 include/ia2api.idl - -diff --git a/configure b/configure -index 2c7c59e8996..bbfdd5cc762 100755 ---- a/configure -+++ b/configure -@@ -1414,6 +1414,7 @@ enable_hlink - enable_hnetcfg - enable_http_sys - enable_httpapi -+enable_ia2comproxy - enable_iccvid - enable_icmp - enable_ieframe -@@ -21977,6 +21978,7 @@ wine_fn_config_makefile dlls/hnetcfg/tests enable_tests - wine_fn_config_makefile dlls/http.sys enable_http_sys - wine_fn_config_makefile dlls/httpapi enable_httpapi - wine_fn_config_makefile dlls/httpapi/tests enable_tests -+wine_fn_config_makefile dlls/ia2comproxy enable_ia2comproxy - wine_fn_config_makefile dlls/iccvid enable_iccvid - wine_fn_config_makefile dlls/icmp enable_icmp - wine_fn_config_makefile dlls/ieframe enable_ieframe -diff --git a/configure.ac b/configure.ac -index b6d0e64c2b8..f37f4e02324 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -2937,6 +2937,7 @@ WINE_CONFIG_MAKEFILE(dlls/hnetcfg/tests) - WINE_CONFIG_MAKEFILE(dlls/http.sys) - WINE_CONFIG_MAKEFILE(dlls/httpapi) - WINE_CONFIG_MAKEFILE(dlls/httpapi/tests) -+WINE_CONFIG_MAKEFILE(dlls/ia2comproxy) - WINE_CONFIG_MAKEFILE(dlls/iccvid) - WINE_CONFIG_MAKEFILE(dlls/icmp) - WINE_CONFIG_MAKEFILE(dlls/ieframe) -diff --git a/dlls/ia2comproxy/Makefile.in b/dlls/ia2comproxy/Makefile.in -new file mode 100644 -index 00000000000..4b824b09590 ---- /dev/null -+++ b/dlls/ia2comproxy/Makefile.in -@@ -0,0 +1,10 @@ -+MODULE = ia2comproxy.dll -+IMPORTLIB = ia2comproxy -+IMPORTS = uuid rpcrt4 oleacc ole32 oleaut32 -+ -+EXTRADLLFLAGS = -mno-cygwin -+ -+IDL_SRCS = ia2_classes.idl \ -+ oleacc_classes.idl -+ -+dlldata_EXTRADEFS = -DWINE_REGISTER_DLL -DPROXY_DELEGATION -diff --git a/dlls/ia2comproxy/ia2_classes.idl b/dlls/ia2comproxy/ia2_classes.idl -new file mode 100644 -index 00000000000..d608a194e30 ---- /dev/null -+++ b/dlls/ia2comproxy/ia2_classes.idl -@@ -0,0 +1,31 @@ -+/* -+ * Copyright 2021 Connor McAdams 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 ident -+#pragma makedep regtypelib -+#pragma makedep proxy -+#pragma makedep register -+ -+cpp_quote("#include \"oleacc.h\"") -+#include "ia2api.idl" -+ -+[ -+ threading(both), -+ uuid(01c20f2b-3dd2-400f-949f-ad00bdab1d41) /* IAccessibleHyperLink */ -+] -+coclass PSFactoryBuffer { interface IFactoryBuffer; } -diff --git a/dlls/ia2comproxy/ia2comproxy.spec b/dlls/ia2comproxy/ia2comproxy.spec -new file mode 100644 -index 00000000000..b16365d0c9f ---- /dev/null -+++ b/dlls/ia2comproxy/ia2comproxy.spec -@@ -0,0 +1,4 @@ -+@ stdcall -private DllCanUnloadNow() -+@ stdcall -private DllGetClassObject(ptr ptr ptr) -+@ stdcall -private DllRegisterServer() -+@ stdcall -private DllUnregisterServer() -diff --git a/dlls/ia2comproxy/oleacc_classes.idl b/dlls/ia2comproxy/oleacc_classes.idl -new file mode 100644 -index 00000000000..62674f0e6ec ---- /dev/null -+++ b/dlls/ia2comproxy/oleacc_classes.idl -@@ -0,0 +1,21 @@ -+/* -+ * Copyright 2021 Connor McAdams 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 ident -+ -+#include "oleacc.idl" -diff --git a/include/Makefile.in b/include/Makefile.in -index a3841c8870b..95d5a896830 100644 ---- a/include/Makefile.in -+++ b/include/Makefile.in -@@ -338,6 +338,7 @@ SOURCES = \ - httprequest.idl \ - httprequestid.h \ - i_cryptasn1tls.h \ -+ ia2api.idl \ - iads.idl \ - icftypes.idl \ - icm.h \ -diff --git a/include/ia2api.idl b/include/ia2api.idl -new file mode 100644 -index 00000000000..f34f6cf2fae ---- /dev/null -+++ b/include/ia2api.idl -@@ -0,0 +1,5538 @@ -+/************************************************************************* -+ * -+ * File Name (api_all_headers.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2013 Linux Foundation -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+import "objidl.idl"; -+import "oaidl.idl"; -+import "oleacc.idl"; -+ -+/************************************************************************* -+ * -+ * File Name (IA2CommonTypes.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+ /** These constants control the scrolling of an object or substring into a window. -+ -+ This enum is used in IAccessible2::scrollTo and IAccessibleText::scrollSubstringTo. -+*/ -+enum IA2ScrollType { -+ -+ /** Scroll the top left corner of the object or substring such that the top left -+ corner (and as much as possible of the rest of the object or substring) is within -+ the top level window. In cases where the entire object or substring fits within -+ the top level window, the placement of the object or substring is dependent on -+ the application. For example, the object or substring may be scrolled to the -+ closest edge, the furthest edge, or midway between those two edges. In cases -+ where there is a hierarchy of nested scrollable controls, more than one control -+ may have to be scrolled. -+ */ -+ IA2_SCROLL_TYPE_TOP_LEFT, -+ -+ /** Scroll the bottom right corner of the object or substring such that the bottom right -+ corner (and as much as possible of the rest of the object or substring) is within -+ the top level window. In cases where the entire object or substring fits within -+ the top level window, the placement of the object or substring is dependent on -+ the application. For example, the object or substring may be scrolled to the -+ closest edge, the furthest edge, or midway between those two edges. In cases -+ where there is a hierarchy of nested scrollable controls, more than one control -+ may have to be scrolled. -+ */ -+ IA2_SCROLL_TYPE_BOTTOM_RIGHT, -+ -+ /** Scroll the top edge of the object or substring such that the top edge -+ (and as much as possible of the rest of the object or substring) is within the -+ top level window. In cases where the entire object or substring fits within -+ the top level window, the placement of the object or substring is dependent on -+ the application. For example, the object or substring may be scrolled to the -+ closest edge, the furthest edge, or midway between those two edges. In cases -+ where there is a hierarchy of nested scrollable controls, more than one control -+ may have to be scrolled. -+ */ -+ IA2_SCROLL_TYPE_TOP_EDGE, -+ -+ /** Scroll the bottom edge of the object or substring such that the bottom edge -+ (and as much as possible of the rest of the object or substring) is within the -+ top level window. In cases where the entire object or substring fits within -+ the top level window, the placement of the object or substring is dependent on -+ the application. For example, the object or substring may be scrolled to the -+ closest edge, the furthest edge, or midway between those two edges. In cases -+ where there is a hierarchy of nested scrollable controls, more than one control -+ may have to be scrolled. -+ */ -+ IA2_SCROLL_TYPE_BOTTOM_EDGE, -+ -+ /** Scroll the left edge of the object or substring such that the left edge -+ (and as much as possible of the rest of the object or substring) is within the -+ top level window. In cases where the entire object or substring fits within -+ the top level window, the placement of the object or substring is dependent on -+ the application. For example, the object or substring may be scrolled to the -+ closest edge, the furthest edge, or midway between those two edges. In cases -+ where there is a hierarchy of nested scrollable controls, more than one control -+ may have to be scrolled. -+ */ -+ IA2_SCROLL_TYPE_LEFT_EDGE, -+ -+ /** Scroll the right edge of the object or substring such that the right edge -+ (and as much as possible of the rest of the object or substring) is within the -+ top level window. In cases where the entire object or substring fits within -+ the top level window, the placement of the object or substring is dependent on -+ the application. For example, the object or substring may be scrolled to the -+ closest edge, the furthest edge, or midway between those two edges. In cases -+ where there is a hierarchy of nested scrollable controls, more than one control -+ may have to be scrolled. -+ */ -+ IA2_SCROLL_TYPE_RIGHT_EDGE, -+ -+ /** Scroll the object or substring such that as much as possible of the -+ object or substring is within the top level window. The placement of -+ the object is dependent on the application. For example, the object or -+ substring may be scrolled to to closest edge, the furthest edge, or midway -+ between those two edges. -+ */ -+ IA2_SCROLL_TYPE_ANYWHERE -+}; -+ -+/** These constants define which coordinate system a point is located in. -+ -+ This enum is used in IAccessible2::scrollToPoint, IAccessibleImage::imagePosition, -+ IAccessibleText::characterExtents, and IAccessibleText::offsetAtPoint, and -+ IAccessibleText::scrollSubstringToPoint. -+*/ -+enum IA2CoordinateType { -+ -+ /// The coordinates are relative to the screen. -+ IA2_COORDTYPE_SCREEN_RELATIVE, -+ -+ /** The coordinates are relative to the upper left corner of the bounding box -+ of the immediate parent. -+ */ -+ IA2_COORDTYPE_PARENT_RELATIVE -+ -+}; -+ -+/** Special offsets for use in IAccessibleText and IAccessibleEditableText methods -+ -+ Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for more information. -+*/ -+enum IA2TextSpecialOffsets { -+ IA2_TEXT_OFFSET_LENGTH = -1, /**< This offset is equivalent to the length of the string. It eliminates -+ the need to call IAccessibleText::nCharacters. */ -+ IA2_TEXT_OFFSET_CARET = -2 /**< This offset signifies that the text related to the physical location -+ of the caret should be used. */ -+}; -+ -+/** These constants specify the kind of change made to a table. -+ -+ This enum is used in the IA2TableModelChange struct which in turn is used by -+ IAccessibleTable::modelChange and IAccessibleTable2::modelChange. -+*/ -+enum IA2TableModelChangeType { -+ IA2_TABLE_MODEL_CHANGE_INSERT, // = 0; -+ IA2_TABLE_MODEL_CHANGE_DELETE, -+ IA2_TABLE_MODEL_CHANGE_UPDATE -+}; -+ -+/** A structure defining the type of and extents of changes made to a table -+ -+ IAccessibleTable::modelChange and IAccessibleTable2::modelChange return this struct. -+ In the case of an insertion or change the row and column offsets define the boundaries -+ of the inserted or changed subtable after the operation. In the case of a deletion -+ the row and column offsets define the boundaries of the subtable being removed before -+ the removal. -+*/ -+typedef struct IA2TableModelChange { -+ enum IA2TableModelChangeType type; // insert, delete, update -+ long firstRow; ///< 0 based, inclusive -+ long lastRow; ///< 0 based, inclusive -+ long firstColumn; ///< 0 based, inclusive -+ long lastColumn; ///< 0 based, inclusive -+} IA2TableModelChange; -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleRelation.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @defgroup grpRelations Relations -+ Use the following constants to compare against the BSTRs returned by -+ IAccessibleRelation::relationType. -+*/ -+///@{ -+ -+/** The target object is the containing application object. */ -+const WCHAR *const IA2_RELATION_CONTAINING_APPLICATION = L"containingApplication"; -+ -+/** The target object is the containing document object. The target object implements -+ the IAccessibleDocument interface. -+*/ -+const WCHAR *const IA2_RELATION_CONTAINING_DOCUMENT = L"containingDocument"; -+ -+/** The target object is the containing tab pane object. */ -+const WCHAR *const IA2_RELATION_CONTAINING_TAB_PANE = L"containingTabPane"; -+ -+/** The target object is the containing window object. */ -+const WCHAR *const IA2_RELATION_CONTAINING_WINDOW = L"containingWindow"; -+ -+/** Some attribute of this object is affected by a target object. */ -+const WCHAR *const IA2_RELATION_CONTROLLED_BY = L"controlledBy"; -+ -+/** This object is interactive and controls some attribute of a target object. */ -+const WCHAR *const IA2_RELATION_CONTROLLER_FOR = L"controllerFor"; -+ -+/** This object is described by the target object. */ -+const WCHAR *const IA2_RELATION_DESCRIBED_BY = L"describedBy"; -+ -+/** This object is describes the target object. */ -+const WCHAR *const IA2_RELATION_DESCRIPTION_FOR = L"descriptionFor"; -+ -+/** This object is embedded by a target object. */ -+const WCHAR *const IA2_RELATION_EMBEDDED_BY = L"embeddedBy"; -+ -+/** This object embeds a target object. This relation can be used on the -+ OBJID_CLIENT accessible for a top level window to show where the content -+ areas are. -+*/ -+const WCHAR *const IA2_RELATION_EMBEDS = L"embeds"; -+ -+/** Content flows to this object from a target object. -+ This relation and IA2_RELATION_FLOWS_TO are useful to tie text and non-text -+ objects together in order to allow assistive technology to follow the -+ intended reading order. -+*/ -+const WCHAR *const IA2_RELATION_FLOWS_FROM = L"flowsFrom"; -+ -+/** Content flows from this object to a target object. */ -+const WCHAR *const IA2_RELATION_FLOWS_TO = L"flowsTo"; -+ -+/** This object is label for a target object. */ -+const WCHAR *const IA2_RELATION_LABEL_FOR = L"labelFor"; -+ -+/** This object is labelled by a target object. Note that the double L spelling -+ which follows is preferred. Please use it instead. This single L version may -+ be removed in a later version. -+*/ -+const WCHAR *const IA2_RELATION_LABELED_BY = L"labelledBy"; -+ -+/** This object is labelled by a target object. */ -+const WCHAR *const IA2_RELATION_LABELLED_BY = L"labelledBy"; -+ -+/** This object is a member of a group of one or more objects. When -+ there is more than one object in the group each member may have one and the -+ same target, e.g. a grouping object. It is also possible that each member has -+ multiple additional targets, e.g. one for every other member in the group. -+*/ -+const WCHAR *const IA2_RELATION_MEMBER_OF = L"memberOf"; -+ -+/** The target object is the next object in the tab order. */ -+const WCHAR *const IA2_RELATION_NEXT_TABBABLE = L"nextTabbable"; -+ -+/** This object is a logical child of a target object. This relation is the reciprocal -+ of the IA2_RELATION_NODE_PARENT_OF relation. In some cases an application's accessible -+ tree is such that objects can be in a logical parent-child relationship which is -+ different from the hierarchy of the accessible tree. */ -+const WCHAR *const IA2_RELATION_NODE_CHILD_OF = L"nodeChildOf"; -+ -+/** This object is a logical parent of a target object. This relation is the reciprocal -+ of the IA2_RELATION_NODE_CHILD_OF relation. In some cases an application's accessible -+ tree is such that objects can be in a logical parent-child relationship which is -+ different from the hierarchy of the accessible tree. */ -+const WCHAR *const IA2_RELATION_NODE_PARENT_OF = L"nodeParentOf"; -+ -+/** This object is a parent window of the target object. */ -+const WCHAR *const IA2_RELATION_PARENT_WINDOW_OF = L"parentWindowOf"; -+ -+/** This object is a transient component related to the target object. -+ When this object is activated the target object doesn't lose focus. -+*/ -+const WCHAR *const IA2_RELATION_POPUP_FOR = L"popupFor"; -+ -+/** The target object is the previous object in the tab order. */ -+const WCHAR *const IA2_RELATION_PREVIOUS_TABBABLE = L"previousTabbable"; -+ -+/** This object is a sub window of a target object. */ -+const WCHAR *const IA2_RELATION_SUBWINDOW_OF = L"subwindowOf"; -+ -+/** The target object provides the detailed, extended description for this -+ object. It provides more detailed information than would normally be provided -+ using the IA2_RELATION_DESCRIBED_BY relation. A common use for this relation is -+ in digital publishing where an extended description needs to be conveyed in -+ a book that requires structural markup or the embedding of other technology to -+ provide illustrative content. */ -+const WCHAR *const IA2_RELATION_DETAILS = L"details"; -+ -+/** This object provides the detailed, extended description for the target -+ object. See IA2_RELATION_DETAILS. */ -+const WCHAR *const IA2_RELATION_DETAILS_FOR = L"detailsFor"; -+ -+/** The target object is the error message for this object. */ -+const WCHAR *const IA2_RELATION_ERROR = L"error"; -+ -+/** This object is the error message for the target object. */ -+const WCHAR *const IA2_RELATION_ERROR_FOR = L"errorFor"; -+ -+///@} -+ -+/** This interface gives access to an object's set of relations. -+*/ -+[object, uuid(7CDF86EE-C3DA-496a-BDA4-281B336E1FDC)] -+interface IAccessibleRelation : IUnknown -+{ -+ /** @brief Returns the type of the relation. -+ @param [out] relationType -+ The strings returned are defined @ref grpRelations "in this section of the documentation". -+ @retval S_OK -+ */ -+ [propget] HRESULT relationType -+ ( -+ [out, retval] BSTR *relationType -+ ); -+ -+ /** @brief Returns a localized version of the relation type. -+ @param [out] localizedRelationType -+ @retval S_OK -+ */ -+ [propget] HRESULT localizedRelationType -+ ( -+ [out, retval] BSTR *localizedRelationType -+ ); -+ -+ /** @brief Returns the number of targets for this relation. -+ @param [out] nTargets -+ @retval S_OK -+ */ -+ [propget] HRESULT nTargets -+ ( -+ [out, retval] long *nTargets -+ ); -+ -+ /** @brief Returns one accessible relation target. -+ @param [in] targetIndex -+ 0 based index -+ @param [out] target -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Use QueryInterface to get IAccessible2. -+ */ -+ [propget] HRESULT target -+ ( -+ [in] long targetIndex, -+ [out, retval] IUnknown **target -+ ); -+ -+ /** @brief Returns multiple accessible relation targets -+ @param [in] maxTargets -+ maximum size of the array allocated by the client -+ @param [out] targets -+ The array of target objects. Note that this array is to be allocated by the -+ client and freed when no longer needed. Refer to @ref _arrayConsideration -+ "Special Consideration when using Arrays" for more details. You will need to use -+ QueryInterface on the IUnknown to get the IAccessible2. -+ @param [out] nTargets -+ actual number of targets in the returned array (not more than maxTargets) -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, e.g. a negative value -+ */ -+ [propget] HRESULT targets -+ ( -+ [in] long maxTargets, -+ [out, size_is(maxTargets), length_is(*nTargets)] -+ IUnknown **targets, -+ [out, retval] long *nTargets -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleAction.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** This enum defines values which are predefined actions for use when implementing -+ support for media. -+ -+ This enum is used when specifying an action for IAccessibleAction::doAction. -+*/ -+ -+enum IA2Actions { -+ IA2_ACTION_OPEN = -1, /**< Used to inform the server that the client will -+ signal via IA2_ACTION_COMPLETE when it has consumed -+ the content provided by the object. This action -+ allows the object's server to wait for all clients -+ to signal their readiness for additional content. -+ Any form of content generation that requires -+ synchronization with an AT would require use of this -+ action. One example is the generation of text describing -+ visual content not obvious from a video's sound track. -+ In this scenario the Text to Speech or Braille output -+ may take more time than the related length of silence -+ in the video's sound track. */ -+ IA2_ACTION_COMPLETE = -2, /**< Used by the client to inform the server that it has -+ consumed the most recent content provided by this object. */ -+ IA2_ACTION_CLOSE = -3 /**< Used to inform the server that the client no longer -+ requires synchronization. */ -+}; -+ -+/** @brief This interface gives access to actions that can be executed -+ for accessible objects. -+ -+ Every accessible object that can be manipulated via the native GUI beyond the -+ methods available either in the MSAA IAccessible interface or in the set of -+ IAccessible2 interfaces (other than this IAccessibleAction interface) should -+ support the IAccessibleAction interface in order to provide Assistive Technology -+ access to all the actions that can be performed by the object. Each action can -+ be performed or queried for a name, description or associated key bindings. -+ Actions are needed more for ATs that assist the mobility impaired, such as -+ on-screen keyboards and voice command software. By providing actions directly, -+ the AT can present them to the user without the user having to perform the extra -+ steps to navigate a context menu. -+ -+ The first action should be equivalent to the MSAA default action. If there is -+ only one action, %IAccessibleAction should also be implemented. -+*/ -+[object, uuid(B70D9F59-3B5A-4dba-AB9E-22012F607DF5)] -+interface IAccessibleAction : IUnknown -+{ -+ -+ /** @brief Returns the number of accessible actions available in this object. -+ -+ If there are more than one, the first one is considered the -+ "default" action of the object. -+ @param [out] nActions -+ The returned value of the number of actions is zero if there are -+ no actions. -+ @retval S_OK -+ @note This method is missing a [propget] prefix in the IDL. The result is the -+ method is named nActions in generated C++ code instead of get_nActions. -+ */ -+ HRESULT nActions -+ ( -+ [out,retval] long* nActions -+ ); -+ -+ /** @brief Performs the specified Action on the object. -+ @param [in] actionIndex -+ 0 based index specifying the action to perform. If it lies outside -+ the valid range no action is performed. -+ @retval S_OK -+ @retval S_FALSE if action could not be performed -+ @retval E_INVALIDARG if bad [in] passed -+ @note If implementing support for media, refer to the predefined constants in the ::IA2Actions enum. -+ */ -+ HRESULT doAction -+ ( -+ [in] long actionIndex -+ ); -+ -+ /** @brief Returns a description of the specified action of the object. -+ @param [in] actionIndex -+ 0 based index specifying which action's description to return. -+ If it lies outside the valid range an empty string is returned. -+ @param [out] description -+ The returned value is a localized string of the specified action. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT description -+ ( -+ [in] long actionIndex, -+ [out, retval] BSTR *description -+ ); -+ -+ /** @brief Returns an array of BSTRs describing one or more key bindings, if -+ there are any, associated with the specified action. -+ -+ The returned strings are the localized human readable key sequences to be -+ used to activate each action, e.g. "Ctrl+Shift+D". Since these key -+ sequences are to be used when the object has focus, they are like -+ mnemonics (access keys), and not like shortcut (accelerator) keys. -+ -+ There is no need to implement this method for single action controls since -+ that would be redundant with the standard MSAA programming practice of -+ getting the mnemonic from get_accKeyboardShortcut. -+ -+ An AT such as an On Screen Keyboard might not expose these bindings but -+ provide alternative means of activation. -+ -+ Note: the client allocates and passes in an array of pointers. The server -+ allocates the BSTRs and passes back one or more pointers to these BSTRs into -+ the array of pointers allocated by the client. The client is responsible -+ for deallocating the BSTRs. -+ -+ @param [in] actionIndex -+ 0 based index specifying which action's key bindings should be returned. -+ @param [in] nMaxBindings -+ This parameter is ignored. Refer to @ref _arrayConsideration -+ "Special Consideration when using Arrays" for more details. -+ @param [out] keyBindings -+ An array of BSTRs, allocated by the server, one for each key binding. -+ The client must free it with CoTaskMemFree. -+ @param [out] nBindings -+ The number of key bindings returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are no key bindings, [out] values are NULL and 0 respectively -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT keyBinding -+ ( -+ [in] long actionIndex, -+ [in] long nMaxBindings, -+ [out, size_is(,nMaxBindings), length_is(,*nBindings)] BSTR **keyBindings, -+ [out, retval] long *nBindings -+ ); -+ -+ /** @brief Returns the non-localized name of specified action. -+ @param [in] actionIndex -+ 0 based index specifying which action's non-localized name should be returned. -+ @param [out] name -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT name -+ ( -+ [in] long actionIndex, -+ [out, retval] BSTR *name -+ ); -+ -+ /** @brief Returns the localized name of specified action. -+ @param [in] actionIndex -+ 0 based index specifying which action's localized name should be returned. -+ @param [out] localizedName -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT localizedName -+ ( -+ [in] long actionIndex, -+ [out, retval] BSTR *localizedName -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleRole.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007-2018 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** Collection of roles -+ -+ This enumerator defines an extended set of accessible roles of objects implementing -+ the %IAccessible2 interface. These roles are in addition to the MSAA roles obtained -+ through the MSAA get_accRole method. Examples are 'footnote', 'heading', and -+ 'label'. You obtain an object's %IAccessible2 roles by calling IAccessible2::role. -+*/ -+enum IA2Role { -+ -+ /** Unknown role. The object contains some Accessible information, but its -+ role is not known. -+ */ -+ IA2_ROLE_UNKNOWN = 0, -+ -+ /** An object that can be drawn into and to manage events from the objects -+ drawn into it. Also refer to ::IA2_ROLE_FRAME, -+ ::IA2_ROLE_GLASS_PANE, and ::IA2_ROLE_LAYERED_PANE. -+ */ -+ IA2_ROLE_CANVAS = 0x401, -+ -+ /// A caption describing another object. -+ IA2_ROLE_CAPTION, -+ -+ /// Used for check buttons that are menu items. -+ IA2_ROLE_CHECK_MENU_ITEM, -+ -+ /// A specialized dialog that lets the user choose a color. -+ IA2_ROLE_COLOR_CHOOSER, -+ -+ /// A date editor. -+ IA2_ROLE_DATE_EDITOR, -+ -+ /** An iconified internal frame in an ::IA2_ROLE_DESKTOP_PANE. -+ Also refer to ::IA2_ROLE_INTERNAL_FRAME. -+ */ -+ IA2_ROLE_DESKTOP_ICON, -+ -+ /** A desktop pane. A pane that supports internal frames and iconified -+ versions of those internal frames. Also refer to ::IA2_ROLE_INTERNAL_FRAME. -+ */ -+ IA2_ROLE_DESKTOP_PANE, -+ -+ /** A directory pane. A pane that allows the user to navigate through -+ and select the contents of a directory. May be used by a file chooser. -+ Also refer to ::IA2_ROLE_FILE_CHOOSER. -+ */ -+ IA2_ROLE_DIRECTORY_PANE, -+ -+ /** An editable text object in a toolbar. Deprecated. -+ The edit bar role was meant for a text area in a tool bar. However, to detect -+ a text area in a tool bar the AT can query the parent. -+ */ -+ IA2_ROLE_EDITBAR, -+ -+ /// Embedded (OLE) object. -+ IA2_ROLE_EMBEDDED_OBJECT, -+ -+ /// Text that is used as an endnote (footnote at the end of a chapter or section). -+ IA2_ROLE_ENDNOTE, -+ -+ /** A file chooser. A specialized dialog that displays the files in the -+ directory and lets the user select a file, browse a different directory, -+ or specify a filename. May use the directory pane to show the contents of -+ a directory. -+ Also refer to ::IA2_ROLE_DIRECTORY_PANE. -+ */ -+ IA2_ROLE_FILE_CHOOSER, -+ -+ /** A font chooser. A font chooser is a component that lets the user pick -+ various attributes for fonts. -+ */ -+ IA2_ROLE_FONT_CHOOSER, -+ -+ /** Footer of a document page. -+ Also refer to ::IA2_ROLE_HEADER. -+ */ -+ IA2_ROLE_FOOTER, -+ -+ /// Text that is used as a footnote. Also refer to ::IA2_ROLE_ENDNOTE. -+ IA2_ROLE_FOOTNOTE, -+ -+ /** A container of form controls. An example of the use of this role is to -+ represent an HTML FORM tag. -+ */ -+ IA2_ROLE_FORM, -+ -+ /** Frame role. A top level window with a title bar, border, menu bar, etc. -+ It is often used as the primary window for an application. Also refer to -+ ::IA2_ROLE_CANVAS and the MSAA roles of dialog and window. -+ */ -+ IA2_ROLE_FRAME, -+ -+ /** A glass pane. A pane that is guaranteed to be painted on top of all panes -+ beneath it. Also refer to ::IA2_ROLE_CANVAS, ::IA2_ROLE_INTERNAL_FRAME, and -+ ::IA2_ROLE_ROOT_PANE. -+ */ -+ IA2_ROLE_GLASS_PANE, -+ -+ /** Header of a document page. -+ Also refer to ::IA2_ROLE_FOOTER. -+ */ -+ IA2_ROLE_HEADER, -+ -+ /// Heading. Use the IAccessible2::attributes level attribute to determine the heading level. -+ IA2_ROLE_HEADING, -+ -+ /// A small fixed size picture, typically used to decorate components. -+ IA2_ROLE_ICON, -+ -+ /** An image map object. Usually a graphic with multiple hotspots, where -+ each hotspot can be activated resulting in the loading of another document -+ or section of a document. -+ */ -+ IA2_ROLE_IMAGE_MAP, -+ -+ /** An object which is used to allow input of characters not found on a keyboard, -+ such as the input of Chinese characters on a Western keyboard. -+ */ -+ IA2_ROLE_INPUT_METHOD_WINDOW, -+ -+ /** An internal frame. A frame-like object that is clipped by a desktop pane. -+ The desktop pane, internal frame, and desktop icon objects are often used to -+ create multiple document interfaces within an application. -+ Also refer to ::IA2_ROLE_DESKTOP_ICON, ::IA2_ROLE_DESKTOP_PANE, and ::IA2_ROLE_FRAME. -+ */ -+ IA2_ROLE_INTERNAL_FRAME, -+ -+ /// An object used to present an icon or short string in an interface. -+ IA2_ROLE_LABEL, -+ -+ /** A layered pane. A specialized pane that allows its children to be drawn -+ in layers, providing a form of stacking order. This is usually the pane that -+ holds the menu bar as well as the pane that contains most of the visual -+ components in a window. -+ Also refer to ::IA2_ROLE_CANVAS, ::IA2_ROLE_GLASS_PANE, and ::IA2_ROLE_ROOT_PANE. -+ */ -+ IA2_ROLE_LAYERED_PANE, -+ -+ /** A section whose content is parenthetic or ancillary to the main content -+ of the resource. -+ */ -+ IA2_ROLE_NOTE, -+ -+ /** A specialized pane whose primary use is inside a dialog. -+ Also refer to MSAA's dialog role. -+ */ -+ IA2_ROLE_OPTION_PANE, -+ -+ /** An object representing a page of document content. It is used in documents -+ which are accessed by the user on a page by page basis. -+ */ -+ IA2_ROLE_PAGE, -+ -+ /// A paragraph of text. -+ IA2_ROLE_PARAGRAPH, -+ -+ /** A radio button that is a menu item. -+ Also refer to MSAA's button and menu item roles. -+ */ -+ IA2_ROLE_RADIO_MENU_ITEM, -+ -+ /** An object which is redundant with another object in the accessible hierarchy. -+ ATs typically ignore objects with this role. -+ */ -+ IA2_ROLE_REDUNDANT_OBJECT, -+ -+ /** A root pane. A specialized pane that has a glass pane and a layered pane -+ as its children. -+ Also refer to ::IA2_ROLE_GLASS_PANE and ::IA2_ROLE_LAYERED_PANE -+ */ -+ IA2_ROLE_ROOT_PANE, -+ -+ /** A ruler such as those used in word processors. -+ */ -+ IA2_ROLE_RULER, -+ -+ /** A scroll pane. An object that allows a user to incrementally view a large -+ amount of information. Its children can include scroll bars and a viewport. -+ Also refer to ::IA2_ROLE_VIEW_PORT and MSAA's scroll bar role. -+ */ -+ IA2_ROLE_SCROLL_PANE, -+ -+ /** A container of document content. An example of the use of this role is to -+ represent an HTML DIV tag. A section may be used as a region. A region is a -+ group of elements that together form a perceivable unit. A region does not -+ necessarily follow the logical structure of the content, but follows the -+ perceivable structure of the page. A region may have an attribute in the set -+ of IAccessible2::attributes which indicates that it is "live". A live region -+ is content that is likely to change in response to a timed change, a user -+ event, or some other programmed logic or event. -+ */ -+ IA2_ROLE_SECTION, -+ -+ /// Object with graphical representation used to represent content on draw pages. -+ IA2_ROLE_SHAPE, -+ -+ /** A split pane. A specialized panel that presents two other panels at the -+ same time. Between the two panels is a divider the user can manipulate to make -+ one panel larger and the other panel smaller. -+ */ -+ IA2_ROLE_SPLIT_PANE, -+ -+ /** An object that forms part of a menu system but which can be "undocked" -+ from or "torn off" the menu system to exist as a separate window. -+ */ -+ IA2_ROLE_TEAR_OFF_MENU, -+ -+ /// An object used as a terminal emulator. -+ IA2_ROLE_TERMINAL, -+ -+ /// Collection of objects that constitute a logical text entity. -+ IA2_ROLE_TEXT_FRAME, -+ -+ /** A toggle button. A specialized push button that can be checked or unchecked, -+ but does not provide a separate indicator for the current state. -+ Also refer to MSAA's roles of push button, check box, and radio button. -+
Note: IA2_ROLE_TOGGLE_BUTTON should not be used. Instead, use MSAA's -+ ROLE_SYSTEM_PUSHBUTTON and STATE_SYSTEM_PRESSED. -+ */ -+ IA2_ROLE_TOGGLE_BUTTON, -+ -+ /** A viewport. An object usually used in a scroll pane. It represents the -+ portion of the entire data that the user can see. As the user manipulates -+ the scroll bars, the contents of the viewport can change. -+ Also refer to ::IA2_ROLE_SCROLL_PANE. -+ */ -+ IA2_ROLE_VIEW_PORT, -+ -+ /** An object containing content which is complementary to the main content of -+ a document, but remains meaningful when separated from the main content. There -+ are various types of content that would appropriately have this role. For example, -+ in the case where content is delivered via a web portal to a web browser, this may -+ include but not be limited to show times, current weather, related articles, or -+ stocks to watch. The complementary role indicates that contained content is relevant -+ to the main content. If the complementary content is completely separable main -+ content, it may be appropriate to use a more general role. -+ */ -+ IA2_ROLE_COMPLEMENTARY_CONTENT, -+ -+ /** An object representing a navigational landmark, a region on a page to -+ which the user may want quick access, such as a navigation area, a search -+ facility or the main content of a page. -+ */ -+ IA2_ROLE_LANDMARK, -+ -+ /** -+ * A bar that serves as a level indicator to, for instance, show -+ * the strength of a password or the charge of a battery. -+ */ -+ IA2_ROLE_LEVEL_BAR, -+ -+ /** Content previously deleted or proposed for deletion, e.g. in revision -+ history or a content view providing suggestions from reviewers. -+ */ -+ IA2_ROLE_CONTENT_DELETION, -+ -+ /** Content previously inserted or proposed for insertion, e.g. in revision -+ history or a content view providing suggestions from reviewers. -+ */ -+ IA2_ROLE_CONTENT_INSERTION, -+ -+ /// A section of content that is quoted from another source. -+ IA2_ROLE_BLOCK_QUOTE, -+ -+ /** A run of content that is marked or highlighted, such as for reference -+ purposes, or to call it out as having a special purpose that is clear from -+ context. If the mark is used in conjuction with a related content section -+ in the document, then IA2_RELATION_DETAILS should be used to link the -+ related content (and the reverse relation IA2_RELATION_DETAILS_FOR should -+ link back to the IA2_ROLE_MARK object). If the mark has related information -+ in a tooltip, or as hidden text, then accDescription should be used to -+ provide this information. -+ */ -+ IA2_ROLE_MARK, -+ -+ /** A grouping for content that is called out as a proposed change from the -+ current version of the document, such as by a reviewer of the content. -+ Should include as children one or both of: -+ IA2_ROLE_CONTENT_DELETION and IA2_ROLE_CONTENT_INSERTION, in any order, -+ to indicate what the actual change is. -+ If the suggestion is accepted, the implementation should change the role to -+ a generic one such as IA2_ROLE_SECTION or IA2_ROLE_TEXT_FRAME. -+ */ -+ IA2_ROLE_SUGGESTION, -+ -+ /** A single comment, typically user-generated content. Supports reply -+ hierarchies via descendant structure, e.g. a child comment is a reply -+ to the parent comment. Supports groupPosition() method to determine -+ reply level (top comment is 1), as well as set size and position in set -+ within that level. -+ */ -+ IA2_ROLE_COMMENT -+}; -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleStates.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+typedef long AccessibleStates; -+ -+/** %IAccessible2 specific state bit constants -+ -+ This enum defines the state bits returned by IAccessible2::states. The -+ %IAccessible2 state bits are in addition to those returned by MSAA. -+*/ -+enum IA2States { -+ -+/** Indicates a window is currently the active window, or is an active subelement -+ within a container or table. -+ -+ This state can be used to indicate the current active item in a container, even -+ if the container itself is not currently active. In other words this would indicate -+ the item that will get focus if you tab to the container. -+ -+ This information is important for knowing what to report for trees and potentially -+ other containers in a virtual buffer. -+ -+ Also, see ::IA2_STATE_MANAGES_DESCENDANTS for more information. -+*/ -+IA2_STATE_ACTIVE = 0x1, -+ -+/** Indicates that the object is armed. -+ -+ Used to indicate that the control is "pressed" and will be invoked when the -+ actuator, e.g. a mouse button, is "released". An AT which either monitors the -+ mouse or synthesizes mouse events might need to know that, and possibly a talking -+ interface would even let the user know about it. It could also potentially be -+ useful to on screen keyboards or test tools since the information does indicate -+ something about the state of the interface, for example, code operating asynchronously -+ might need to wait for the armed state to change before doing something else. -+ -+*/ -+IA2_STATE_ARMED = 0x2, -+ -+/** Indicates the user interface object corresponding to this object no longer exists. */ -+IA2_STATE_DEFUNCT = 0x4, -+ -+/** An object with this state has a caret and implements the IAccessibleText interface. -+ -+ Such fields may be read-only, so STATE_SYSTEM_READONLY is valid in combination -+ with IA2_STATE_EDITABLE. -+ -+*/ -+IA2_STATE_EDITABLE = 0x8, -+ -+/** Indicates the orientation of this object is horizontal. */ -+IA2_STATE_HORIZONTAL = 0x10, -+ -+/** Indicates this object is minimized and is represented only by an icon. */ -+IA2_STATE_ICONIFIED = 0x20, -+ -+/** Indicates an input validation failure. */ -+IA2_STATE_INVALID_ENTRY = 0x40, -+ -+/** Indicates that this object manages its children. -+ -+ Note: Due to the fact that MSAA's WinEvents don't allow the active child index -+ to be passed on the IA2_EVENT_ACTIVE_DESCENDANT_CHANGED event, the manages -+ descendants scheme can't be used. Instead the active child object has to fire -+ MSAA's EVENT_OBJECT_FOCUS. In a future release a new event mechanism may be -+ added to provide for event specific data to be passed with the event. At that -+ time the IA2_EVENT_ACTIVE_DECENDENT_CHANGED event and -+ IA2_STATE_MANAGES_DESCENDANTS state would be useful. -+*/ -+IA2_STATE_MANAGES_DESCENDANTS = 0x80, -+ -+/** Indicates that an object is modal. -+ -+ Modal objects have the behavior that something must be done with the object -+ before the user can interact with an object in a different window. -+*/ -+IA2_STATE_MODAL = 0x100, -+ -+/** Indicates this text object can contain multiple lines of text. */ -+IA2_STATE_MULTI_LINE = 0x200, -+ -+/** Indicates this object paints every pixel within its rectangular region. */ -+IA2_STATE_OPAQUE = 0x400, -+ -+/** Indicates that user interaction is required. -+ -+ An example of when this state is used is when a field in a form must be filled -+ before a form can be processed. -+*/ -+IA2_STATE_REQUIRED = 0x800, -+ -+/** Indicates an object which supports text selection. -+ -+ Note: This is different than MSAA STATE_SYSTEM_SELECTABLE. -+*/ -+IA2_STATE_SELECTABLE_TEXT = 0x1000, -+ -+/** Indicates that this text object can contain only a single line of text. */ -+IA2_STATE_SINGLE_LINE = 0x2000, -+ -+/** Indicates that the accessible object is stale. -+ -+ This state is used when the accessible object no longer accurately -+ represents the state of the object which it is representing such as when an -+ object is transient or when an object has been or is in the process of being -+ destroyed or when the object's index in its parent has changed. -+*/ -+IA2_STATE_STALE = 0x4000, -+ -+/** Indicates that the object implements autocompletion. -+ -+ This state indicates that a text control will respond to the input of -+ one ore more characters and cause a sub-item to become selected. The -+ selection may also result in events fired on the parent object. -+*/ -+IA2_STATE_SUPPORTS_AUTOCOMPLETION = 0x8000, -+ -+/** Indicates this object is transient. -+ -+ An object has this state when its parent object has the state ::IA2_STATE_MANAGES_DESCENDANTS. -+ For example, a list item object may be managed by its parent list object and may only -+ exist as long as the object is actually rendered. Similarly a table cell's accessible -+ object may exist only while the cell has focus. However, from the perspective of an -+ assistive technology a transient object behaves like a non-transient object. As a -+ result it is likely that this state is not of use to an assistive technology, but it -+ is provided in case an assistive technology determines that knowledge of the transient -+ nature of the object is useful and also for harmony with the Linux accessibility API. -+ -+ Also, see ::IA2_STATE_MANAGES_DESCENDANTS for more information. -+ */ -+IA2_STATE_TRANSIENT = 0x10000, -+ -+/** Indicates the orientation of this object is vertical. */ -+IA2_STATE_VERTICAL = 0x20000, -+ -+/** Indicates this object is checkable. -+ -+ The standard checkable objects are check boxes, radio buttons, check box menu -+ items, radio menu items, and toggle buttons. Since assistive technology will -+ determine that these objects are checkable via the object's role the checkable -+ state is not required. However, this state is necessary in those cases where -+ an object has a role which is not one of the previously mentioned roles. An -+ example is a table cell which indicates whether or not an email has an attachment, -+ whether or not an mail is considered spam, and whether or not an email has been read. -+ */ -+IA2_STATE_CHECKABLE = 0x40000, -+ -+/** Indicates this object is pinned. -+ -+ This state indicates that an object is fixed at a certain location. One example -+ is a browser tab that when pinned cannot be moved until unpinned. Another example -+ is a movable or floating object that when pinned remains in its pinned location -+ until being unpinned. -+ */ -+IA2_STATE_PINNED = 0x80000 -+ -+}; -+ -+/************************************************************************* -+ * -+ * File Name (Accessible2.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @mainpage -+ -+ @section _interfaces Interfaces -+ IAccessible2\n -+ IAccessible2_2\n -+ IAccessible2_3\n -+ IAccessibleAction\n -+ IAccessibleApplication\n -+ IAccessibleComponent\n -+ IAccessibleDocument\n -+ IAccessibleEditableText\n -+ IAccessibleHypertext\n -+ IAccessibleHypertext2\n -+ IAccessibleHyperlink\n -+ IAccessibleImage\n -+ IAccessibleRelation\n -+ IAccessibleTable [Deprecated]\n -+ IAccessibleTable2\n -+ IAccessibleTableCell\n -+ IAccessibleText\n -+ IAccessibleText2\n -+ IAccessibleValue -+ -+ @section _structs Structs -+ IA2Locale\n -+ IA2Range\n -+ IA2TableModelChange\n -+ IA2TextSegment -+ -+ @section _enums Enums -+ ::IA2Actions values are predefined actions for use when implementing support for HTML5 media.\n -+ ::IA2CoordinateType values define the requested coordinate type (screen or parent window).\n -+ ::IA2EventID values identify events.\n -+ ::IA2Role values defines roles which are in addition to the existing MSAA roles.\n -+ ::IA2ScrollType values define where to place an object or substring on the screen.\n -+ ::IA2States values define states which are in addition to the existing MSAA states.\n -+ ::IA2TableModelChangeType values describe the kinds of changes made to a table (insert, delete, update).\n -+ ::IA2TextBoundaryType values define the requested text unit (character, word, sentence, line, paragraph).\n -+ ::IA2TextSpecialOffsets values define special offsets for use in the text interfaces. -+ -+ @section _constants Constants -+ @ref grpRelations -+ -+ @section _misc Miscellaneous -+ @ref _licensePage "BSD License"\n -+ @ref _generalInfo "General Information"\n -+ -+ @page _licensePage BSD License -+ %IAccessible2 IDL Specification -+ -+ Copyright (c) 2007, 2013 Linux Foundation\n -+ Copyright (c) 2006 IBM Corporation\n -+ Copyright (c) 2000, 2006 Sun Microsystems, Inc.\n -+ All rights reserved. -+ -+ Redistribution and use in source and binary forms, with or without -+ modification, are permitted provided that the following conditions -+ are met: -+ -+ 1. Redistributions of source code must retain the above copyright -+ notice, this list of conditions and the following disclaimer. -+ -+ 2. Redistributions in binary form must reproduce the above -+ copyright notice, this list of conditions and the following -+ disclaimer in the documentation and/or other materials -+ provided with the distribution. -+ -+ 3. Neither the name of the Linux Foundation nor the names of its -+ contributors may be used to endorse or promote products -+ derived from this software without specific prior written -+ permission. -+ -+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ -+ This BSD License conforms to the Open Source Initiative "Simplified -+ BSD License" as published at: -+ http://www.opensource.org/licenses/bsd-license.php -+ -+ %IAccessible2 is a trademark of the Linux Foundation. The %IAccessible2 -+ mark may be used in accordance with the -+ -+ Linux Foundation Trademark Policy to indicate compliance with the %IAccessible2 specification. -+ -+ @page _generalInfo General Information -+ The following information is applicable to two or more interfaces. -+ -+ @ref _errors\n -+ @ref _memory\n -+   @ref _arrayConsideration\n -+ @ref _indexes\n -+ @ref _enums\n -+ @ref _specialOffsets\n -+ @ref _dicoveringInterfaces\n -+ @ref _changingInterfaces\n -+ @ref _applicationInfo\n -+ @ref _childIDs\n -+ @ref _variants\n -+ @ref _iaaction-iahyperlink\n -+ @ref _trademark -+ -+ @section _errors Error Handling -+ HRESULT values are defined by the Microsoft® Win32® API. For more information, refer to -+ -+ Interpreting HRESULT Values in MSDN®. -+ -+ Note that the S_FALSE return value is considered a non-error value and the -+ SUCCEEDED macro will return TRUE. S_FALSE is used when there is no failure -+ but there was nothing valid to return, e.g. in IAccessible2::attributes when -+ there are no attributes. When S_FALSE is returned [out] pointer types should -+ be NULL and [out] longs should generally be 0, but sometimes -1 is used such -+ as IAccessible2::indexInParent, IAccessibleText::caretOffset, and -+ IAccessibleHypertext::hyperlinkIndex. -+ -+ Note that for BSTR [out] variables common COM practice is that the server does -+ the SysAllocString and the client does the SysFreeString. Also note that when -+ NULL is returned there is no need for the client to call SysFreeString. Please -+ refer to the documentation for each method for more details regarding error handling. -+ -+ @section _memory Memory Management -+ The following memory management issues should be considered: -+ @li Although [out] BSTR variables are declared by the client, their space is -+ allocated by the server. They need to be freed with SysFreeString by the -+ client at end of life; the same is true when BSTRs are used in structs or -+ arrays which are passed to the server. -+ @li If there is no valid [out] BSTR to return, the server should return S_FALSE and -+ assign NULL to the output, e.g. *theOutBSTR = NULL;. -+ @li COM interfaces need to be referenced with AddRef when used and dereferenced -+ with Release at end of life. -+ @li Single [out] longs, HWNDs, booleans, and structs are declared by the caller -+ and passed by reference. The marshaller does all the memory management. -+ -+ The following articles may be helpful for understanding memory management issues: -+ @li An article by Don Box in a -+ Q & A section -+ of the November 1996 edition of the Microsoft Systems Journal. -+ @li A posting to a CodeGuru forum, -+ Windows SDK -+ String: What are the rules for BSTR allocation and deallocation? -+ -+ @subsection _arrayConsideration Special Consideration when using Arrays -+ There are several methods which return arrays. In the case of IAccessible2::relations -+ and IAccessibleRelation::targets the client must allocate and free the arrays. -+ -+ For the remaining methods which return arrays, the server must allocate the array -+ and the client must free the array when no longer needed. These methods are -+ IAccessible2::extendedStates, IAccessible2::localizedExtendedStates, -+ IAccessible2_2::relationTargetsOfType, IAccessibleAction::keyBinding, -+ IAccessibleHypertext2::hyperlinks, IAccessibleTable::selectedChildren, -+ IAccessibleTable::selectedColumns, IAccessibleTable::selectedRows, -+ IAccessibleTable2::selectedCells, IAccessibleTable2::selectedColumns, -+ IAccessibleTable2::selectedRows, IAccessibleTableCell::columnHeaderCells, -+ and IAccessibleTableCell::rowHeaderCells. -+ For those methods, the server must allocate both the top level array and any storage -+ associated with it, e.g. for BSTRs. The server must allocate the arrays with -+ CoTaskMemAlloc and any BSTRs with SysAllocString. The client must use CoTaskMemFree -+ to free the array and any BSTRs must be freed with SysFreeString. -+ -+ Also, the IDL for IAccessible2::extendedStates, IAccessible2::localizedExtendedStates, -+ IAccessibleAction::keyBinding, IAccessibleTable::selectedChildren, -+ IAccessibleTable::selectedColumns, and IAccessibleTable::selectedRows includes an -+ extraneous [in] parameter for the caller to specify the max size of the array. -+ This parameter will be ignored by the COM server. -+ -+ @section _indexes Zero and One Based Indexes -+ Unless otherwise specified all offsets and indexes are 0 based. -+ -+ @section _enums Enums -+ Note that enums start at 0. -+ -+ @section _specialOffsets Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods -+ IAccessibleText and IAccessibleEditableText can use one or more of the following -+ special offset values. They are defined in the ::IA2TextSpecialOffsets enum. -+ @li Using ::IA2_TEXT_OFFSET_LENGTH (-1) as an offset in any of the IAccessibleText or -+ IAccessibleEditableText methods is the same as specifying the length of the string. -+ @li Using ::IA2_TEXT_OFFSET_CARET (-2) as an offset for IAccessibleText::textBeforeOffset, -+ IAccessibleText::textAtOffset, and IAccessibleText::textAfterOffset indicates that the -+ text related to the physical location of the caret should be used. This is needed for -+ applications that consider the character offset of the end of one line (as reached by -+ pressing the End key) the same as the offset of the first character on the next line. -+ Since the same offset is associated with two different lines a special means is needed -+ to fetch text from the line where the caret is physically located. -+ -+ @section _dicoveringInterfaces Discovery of Interfaces -+ In general AT (Assistive Technology) should try IAccessible2 interfaces, followed by using -+ the MSAA (Microsoft® Active Accessibility®) interfaces. (In cases where the an application -+ is known to have custom interfaces which provide information not supplied by IAccessible2 -+ or MSAA, then those custom interfaces can be used.) The AT can then, by default, support -+ unknown IAccessible2/MSAA applications, without the application developers having to request -+ AT vendors for support on an individual application by application basis. -+ -+ When you have a reference to an IAccessible and require a reference to an IAccessible2 use -+ QueryService as follows: -+ @code -+ // pAcc is a reference to the accessible object's IAccessible interface. -+ IServiceProvider *pService = NULL; -+ hr = pAcc->QueryInterface(IID_IServiceProvider, (void **)&pService); -+ if(SUCCEEDED(hr)) { -+ IAccessible2 *pIA2 = NULL; -+ hr = pService->QueryService(IID_IAccessible, IID_IAccessible2, (void**)&pIA2); -+ if (SUCCEEDED(hr) && pIA2) { -+ // The control supports IAccessible2. -+ // pIA2 is the reference to the accessible object's IAccessible2 interface. -+ } -+ } -+ @endcode -+ -+ @section _changingInterfaces Changing between Accessible Interfaces -+ Note that developers must always implement MSAA's IAccessible and, if needed, some -+ of the interfaces in the set of IAccessible2 interfaces. Although the IAccessible2 -+ IDL is coded such that IAccessible2 is a subclass of MSAA's IAccessible, none of -+ MSAA's IAccessible methods are redefined by IAccessible2. -+ -+ QueryService must be used to switch from a reference to an MSAA IAccessible interface -+ to another interface. This has been -+ -+ documented and the pertinent facts have been extracted below: -+ -+ @par -+ Why use QueryService instead of just using QueryInterface to get IAccessibleEx -+ directly? The reason is that since MSAA 2.0, clients don't talk to a server's -+ IAccessible interface directly; instead they talk to an intermediate MSAA-provided -+ wrapper that calls through to the original IAccessible. This wrapper provides services -+ such as implementing IDispatch, supplying information from MSAA 2.0's Dynamic Annotation -+ service, and scaling locations when running on Windows Vista with DPI scaling enabled. -+ QueryService is the supported way to expose additional interfaces from an existing -+ IAccessible and was originally used by MSHTML to expose IHTMLElement objects corresponding -+ to IAccessibles. QueryService is often more convenient for servers to implement than -+ QueryInterface because it does not have the same requirements for preserving object -+ identity or symmetry/transitivity as QueryInterface, so QueryService allows servers to -+ easily implement the interface on the same object or a separate object. The latter is -+ often hard to do with QueryInterface unless the original object supports aggregation. -+ -+ Two related references in MSDN® are: -+ @li -+ "Using QueryService to expose a native object model interface for an IAccessible object" -+ @li -+ "Accessing the Internet Explorer Object Associated with an Accessible Object" -+ -+ Based on this information from Microsoft, QueryService must be used to switch back and forth -+ between a reference to an MSAA IAccessible interface and any of the IAccessible2 interfaces. -+ -+ Regarding switching between any of the IAccessible2 interfaces, applications implementing -+ IAccessible2 should implement the IAccessible2 interfaces on a single object since ATs -+ will be using QueryInterface to switch between the IAccessilbe2 interfaces. Implementing -+ the IAccessible2 interfaces on separate objects would require the use of QueryService. -+ There is one exception, IAccessibleApplication can be implemented on a separate object so -+ its common code doesn't have to be included in each accessible object. ATs should use -+ QueryService to access IAccessibleApplication. -+ -+ @section _applicationInfo Access to Information about the Application -+ Servers implementing IAccessible2 should provide access to the IAccessibleApplication -+ interface via QueryService from any object so that ATs can easily determine specific -+ information about the application such as its name or version. -+ -+ @section _childIDs Child IDs -+ The IAccessible2 interfaces do not support child IDs, i.e. simple child elements. -+ Full accessible objects must be created for each object that supports IAccessible2. -+ Therefore MSAA's get_accChild should never return a child ID (other than CHILDID_SELF) -+ for an object that implements any of the IAccessible2 interfaces. -+ -+ Microsoft's UI Automation specification has the same limitation and this was resolved -+ in the UI Automation Express specification by adding IAccessibleEx::GetObjectForChild -+ and IAccessibleEx::GetIAccessiblePair. These methods allow mapping back and forth -+ between an IAccessibleEx and an {IAccessible, Child ID} pair. A future version of -+ IAccessible2 may include similar methods to map back and forth between an IAccessible2 -+ and an {IAccessible, Child ID} pair. -+ -+ @section _variants VARIANTs -+ Some methods return a VARIANT. Implementers need to make sure that the return type is -+ specified, i.e. VT_I4, VT_IDISPATCH, etc. The methods that return VARIANTs are -+ IAccessibleHyperlink::anchor, IAccessibleHyperlink::anchorTarget, IAccessibleValue::currentValue, -+ IAccessibleValue::maximumValue, IAccessibleValue::minimumValue. -+ -+ @section _iaaction-iahyperlink IAccessibleHyperlink as subclass of IAccessibleAction -+ In this version of the IDL, IAccessibleHyperlink is a subclass of IAccessibleAction. -+ However, there is no practical need for that inheritance and in some cases, such as -+ an image map of smart tags, it doesn't make sense because such an image map doesn't -+ have actionable objects; it's the secondary smart tags that are actionable. As a -+ result, implementations should not rely on the inheritance as it may be removed in -+ a later version of the IDL. -+ -+ @section _trademark Trademark Attribution -+ The names of actual companies and products mentioned herein may be the trademarks of -+ their respective owners. In particular, Active Accessibility, Microsoft, MSDN, and Win32 -+ are trademarks of the Microsoft group of companies in the U.S.A. and/or other countries. -+ -+**/ -+ -+/** A structure defining the locale of an accessible object. -+ -+IAccessible2::locale returns this struct. -+*/ -+typedef struct IA2Locale { -+ BSTR language; ///< ISO 639-1 Alpha-2 two character language code -+ BSTR country; ///< ISO 3166-1 Alpha-2 two character country code -+ BSTR variant; ///< Application specific variant of the locale -+} IA2Locale; -+ -+/** @brief This interface exposes the primary set of information about an -+ IAccessible2 enabled accessible object. -+ -+ This interface must always be provided for objects that support some -+ portion of the collection of the %IAccessible2 interfaces. -+ -+ Please refer to @ref _changingInterfaces "Changing between Accessible Interfaces" -+ for special considerations related to use of the MSAA IAccessible interface and -+ the set of %IAccessible2 interfaces. -+ */ -+[object, oleautomation, uuid(E89F726E-C4F4-4c19-BB19-B647D7FA8478)] -+interface IAccessible2 : IAccessible -+{ -+ -+ /** @brief Returns the number of accessible relations for this object. -+ @param [out] nRelations -+ @retval S_OK -+ */ -+ [propget] HRESULT nRelations -+ ( -+ [out, retval] long *nRelations -+ ); -+ -+ /** @brief Returns one accessible relation for this object. -+ @param [in] relationIndex -+ 0 based -+ @param [out] relation -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT relation -+ ( -+ [in] long relationIndex, -+ [out, retval] IAccessibleRelation **relation -+ ); -+ -+ /** @brief Returns multiple accessible relations for this object. -+ @param [in] maxRelations -+ maximum size of the array allocated by the client -+ @param [out] relations -+ The array of accessible relation objects. Note that this array is to be -+ allocated by the client and freed when no longer needed. Refer to @ref -+ _arrayConsideration "Special Consideration when using Arrays" for more details. -+ @param [out] nRelations -+ actual number of relations in the returned array (not more than maxRelations) -+ @retval S_OK -+ @retval S_FALSE if there are no relations, nRelations is set to 0 -+ @note As a performant alternative, client code should consider using IAccessible2_2::relationTargetsOfType. -+ */ -+ [propget] HRESULT relations -+ ( -+ [in] long maxRelations, -+ [out, size_is(maxRelations), length_is(*nRelations)] -+ IAccessibleRelation **relations, -+ [out, retval] long *nRelations -+ ); -+ -+ /** @brief Returns the role of an %IAccessible2 object. -+ @param [out] role -+ The role of an %IAccessible2 object. -+ @retval S_OK -+ @note -+ @li For convenience MSAA roles are also passed through this method so the -+ AT doesn't have to also fetch roles through MSAA's get_accRole. -+ @li %IAccessible2 roles should not be passed through MSAA's get_accRole. -+ @li For compatibility with non IAccessible2 enabled ATs, IAccessible2 -+ applications should also add support to get_accRole to return the closest -+ MSAA role or ROLE_SYSTEM_CLIENT (the MSAA defined default role) if there -+ is not a good match. -+ @li This method is missing a [propget] prefix in the IDL. The result is the -+ method is named role in generated C++ code instead of get_role. -+ */ -+ HRESULT role -+ ( -+ [out, retval] long *role -+ ); -+ -+ /** @brief Makes an object visible on the screen. -+ @param [in] scrollType -+ Defines where the object should be placed on the screen. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT scrollTo -+ ( -+ [in] enum IA2ScrollType scrollType -+ ); -+ -+ /** @brief Moves the top left of an object to a specified location. -+ -+ @param [in] coordinateType -+ Specifies whether the coordinates are relative to the screen or the parent object. -+ @param [in] x -+ Defines the x coordinate. -+ @param [in] y -+ Defines the y coordinate. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT scrollToPoint -+ ( -+ [in] enum IA2CoordinateType coordinateType, -+ [in] long x, -+ [in] long y -+ ); -+ -+ /** @brief Returns grouping information. -+ -+ Used for tree items, list items, tab panel labels, radio buttons, etc. -+ Also used for collections of non-text objects. -+ -+ @param [out] groupLevel -+ 1 based, 0 indicates that this value is not applicable -+ @param [out] similarItemsInGroup -+ 1 based, 0 indicates that this value is not applicable -+ @param [out] positionInGroup -+ 1 based, 0 indicates that this value is not applicable. This is an index -+ into the objects in the current group, not an index into all the objects -+ at the same group level. -+ @retval S_OK if at least one value is valid -+ @retval S_FALSE if no values are valid, [out] values are 0s -+ @note This method is meant to describe the nature of an object's containment -+ structure. It's exposed by trees, tree grids, nested lists, nested menus, -+ but not headings, which uses the level object attribute. It is also exposed -+ by radio buttons (with groupLevel == 0). -+ @note This is normally not implemented on a combo box to describe the nature -+ of its contents. Normally an AT will get that information from its child list -+ object. However, in some cases when non-edit combo boxes are not able to be structured -+ such that the list is a child of the combo box, this method is implemented on -+ the combo box itself. ATs can use this interface if a child list is not found. -+ */ -+ [propget] HRESULT groupPosition -+ ( -+ [out] long *groupLevel, -+ [out] long *similarItemsInGroup, -+ [out, retval] long *positionInGroup -+ ); -+ -+ /** @brief Returns the bit strip containing any IAccessible2 states. -+ -+ The IAccessible2 states are in addition to the MSAA states and are defined in -+ the IA2States enum. -+ -+ @param [out] states -+ @retval S_OK -+ */ -+ [propget] HRESULT states -+ ( -+ [out, retval] AccessibleStates *states -+ ); -+ -+ /** @brief Returns the extended role. -+ -+ An extended role is a role which is dynamically generated by the application. -+ It is not predefined by the %IAccessible2 specification. -+ -+ @param [out] extendedRole -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT extendedRole -+ ( -+ [out, retval] BSTR *extendedRole -+ ); -+ -+ /** @brief Returns the localized extended role. -+ @param [out] localizedExtendedRole -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT localizedExtendedRole -+ ( -+ [out, retval] BSTR *localizedExtendedRole -+ ); -+ -+ /** @brief Returns the number of extended states. -+ @param [out] nExtendedStates -+ @retval S_OK -+ */ -+ [propget] HRESULT nExtendedStates -+ ( -+ [out, retval] long *nExtendedStates -+ ); -+ -+ /** @brief Returns the extended states (array of strings). -+ -+ An extended state is a state which is dynamically generated by the application. -+ It is not predefined by the %IAccessible2 specification. -+ -+ @param [in] maxExtendedStates -+ This parameter is ignored. Refer to @ref _arrayConsideration -+ "Special Consideration when using Arrays" for more details. -+ @param [out] extendedStates -+ This array is allocated by the server. The client must free it with CoTaskMemFree. -+ @param [out] nExtendedStates -+ The number of extended states returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are no states, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT extendedStates -+ ( -+ [in] long maxExtendedStates, -+ [out, size_is(,maxExtendedStates), length_is(,*nExtendedStates)] BSTR **extendedStates, -+ [out, retval] long *nExtendedStates -+ ); -+ -+ /** @brief Returns the localized extended states (array of strings). -+ -+ @param [in] maxLocalizedExtendedStates -+ This parameter is ignored. Refer to @ref _arrayConsideration -+ "Special Consideration when using Arrays" for more details. -+ @param [out] localizedExtendedStates -+ This array is allocated by the server. The client must free it with CoTaskMemFree. -+ @param [out] nLocalizedExtendedStates -+ The number of localized extended states returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are no states, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT localizedExtendedStates -+ ( -+ [in] long maxLocalizedExtendedStates, -+ [out, size_is(,maxLocalizedExtendedStates), length_is(,*nLocalizedExtendedStates)] BSTR **localizedExtendedStates, -+ [out, retval] long *nLocalizedExtendedStates -+ ); -+ -+ /** @brief Returns the unique ID. -+ -+ The uniqueID is an identifier for this object, is unique within the -+ current window, and remains the same for the lifetime of the accessible -+ object. -+ -+ The uniqueID is not related to: -+ - the MSAA objectID which is used by the server to disambiguate between -+ IAccessibles per HWND or -+ - the MSAA childID which is used to disambiguate between children being -+ managed by an IAccessible. -+ -+ This value is provided so the AT can have access to a unique runtime persistent -+ identifier even when not handling an event for the object. -+ -+ An example of when this value is useful is if the AT wants to build a cache. -+ The AT could cache the uniqueIDs in addition to other data being cached. -+ When an event is fired the AT could map the uniqueID to its internal model. -+ Thus, if there's a REORDER/SHOW/HIDE event the AT knows which part of the -+ internal structure has been invalidated and can refetch just that part. -+ -+ This value can also be used by an AT to determine when the current control -+ has changed. If the role is the same for two controls that are adjacent in -+ the tab order, this can be used to detect the new control. -+ -+ Another use of this value by an AT is to identify when a grouping object has -+ changed, e.g. when moving from a radio button in one group to a radio button in a -+ different group. -+ -+ One means of implementing this would be to create a factory with a 32 bit number -+ generator and a reuse pool. The number generator would emit numbers starting -+ at 1. Each time an object's life cycle ended, its number would be saved into a -+ reuse pool. The number generator would be used whenever the reuse pool was empty. -+ -+ Another way to create a unique ID is to generate it from a pointer value, e.g. an -+ object's address. That would be unique because no two active objects can use the -+ same allocated memory space. -+ -+ @param [out] uniqueID -+ @retval S_OK -+ */ -+ [propget] HRESULT uniqueID -+ ( -+ [out, retval] long *uniqueID -+ ); -+ -+ /** @brief Returns the window handle for the parent window which contains this object. -+ -+ This is the same window handle which will be passed for any events that occur on the -+ object, but is cached in the accessible object for use when it would be helpful to -+ access the window handle in cases where an event isn't fired on this object. -+ -+ A use case is when a screen reader is grabbing an entire web page on a page load. -+ Without the availability of windowHandle, the AT would have to get the window handle -+ by using WindowFromAccessibleObject on each IAccessible, which is slow because it's -+ implemented by oleacc.dll as a loop which crawls up the ancestor chain and looks for -+ a ROLE_WINDOW object, mapping that back to a window handle. -+ -+ @param [out] windowHandle -+ @retval S_OK -+ */ -+ [propget] HRESULT windowHandle -+ ( -+ [out, retval] HWND *windowHandle -+ ); -+ -+ /** @brief Returns the index of this object in its parent object. -+ @param [out] indexInParent -+ 0 based; -1 indicates there is no parent; the upper bound is the value -+ returned by the parent's IAccessible::get_accChildCount. -+ @retval S_OK -+ @retval S_FALSE if no parent, [out] value is -1 -+ */ -+ [propget] HRESULT indexInParent -+ ( -+ [out, retval] long *indexInParent -+ ); -+ -+ /** @brief Returns the IA2Locale of the accessible object. -+ @param [out] locale -+ @retval S_OK -+ */ -+ [propget] HRESULT locale -+ ( -+ [out, retval] IA2Locale *locale -+ ); -+ -+ /** @brief Returns the attributes specific to this object, such as a cell's formula. -+ @param [out] attributes -+ @retval S_OK -+ @retval S_FALSE returned if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT attributes -+ ( -+ [out, retval] BSTR *attributes -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (Accessible2_2.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface exposes the primary set of information about an -+ IAccessible2 enabled accessible object. -+ -+ This interface must always be provided for objects that support some -+ portion of the collection of the %IAccessible2 interfaces. -+ -+ Please refer to @ref _changingInterfaces "Changing between Accessible Interfaces" -+ for special considerations related to use of the MSAA IAccessible interface and -+ the set of %IAccessible2 interfaces. -+ */ -+[object, uuid(6C9430E9-299D-4E6F-BD01-A82A1E88D3FF)] -+interface IAccessible2_2 : IAccessible2 -+{ -+ /** @brief Returns the attribute value of a specified attribute specific to this object. -+ @param [in] name -+ @param [out] attribute -+ @retval S_OK -+ @retval S_FALSE returned if there is nothing to return, [out] value is NULL. -+ @retval E_INVALIDARG if bad [in] passed. -+ @note The output value is a VARIANT. Typically it will be a VT_BSTR, but there -+ are some cases where it will be a VT_I4 or VT_BOOL. Refer to the -+ Object Attributes specification for more information. -+ */ -+ [propget] HRESULT attribute -+ ( -+ [in] BSTR name, -+ [out, retval] VARIANT *attribute -+ ); -+ -+ /** @brief Returns the deepest hypertext accessible in the subtree of this object, and the caret offset within it. -+ @param [out] accessible -+ @param [out] caretOffset -+ @retval S_OK -+ @retval S_FALSE returned if there is no caret in any of the objects in the subtree, [out] accessible is NULL and [out] caretOffset is -1. -+ */ -+ [propget] HRESULT accessibleWithCaret -+ ( -+ [out] IUnknown **accessible, -+ [out, retval] long *caretOffset -+ ); -+ -+ /** @brief Returns relation targets for a specified target type. -+ @param [in] type -+ The requested @ref grpRelations "relation type". -+ @param [in] maxTargets -+ The number of targets requested. 0 indicates that all targets should be returned. -+ @param [out] targets -+ This array is allocated by the server. The client must free it with CoTaskMemFree. -+ @param [out] nTargets -+ The number of targets returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are no targets, [out] values are NULL and 0 respectively. -+ @retval E_INVALIDARG if bad [in] passed. -+ */ -+ [propget] HRESULT relationTargetsOfType -+ ( -+ [in] BSTR type, -+ [in] long maxTargets, -+ [out, size_is(,*nTargets)] IUnknown ***targets, -+ [out, retval] long *nTargets -+ ); -+ -+} -+ -+/** -+ * This structure represents a directional range of the content. It is defined -+ * by two points in the content, where each one is defined by an accessible -+ * object and an offset relative to it. A typical case of a range point is -+ * a text accessible and text offset within it. -+ * -+ * The "anchor" is one point of the range and typically remains constant. -+ * The other point is the "active" point, which typically corresponds to -+ * the user's focus or point of interest. The user moves the active point to -+ * expand or collapse the range. In most cases, anchor is the start of the range -+ * and active is the end. However, in case of selection, when selecting -+ * backwards (e.g. pressing shift+left arrow in a text field), the start of -+ * the range is the active point, as the user moves this to manipulate -+ * the selection. -+ */ -+typedef struct IA2Range { -+ IUnknown* anchor; -+ long anchorOffset; -+ IUnknown* active; -+ long activeOffset; -+} IA2Range; -+ -+/** -+ * @brief This interface is an extension of IAccessible2_2 and IAccessible2 -+ * interfaces. -+ */ -+[object, uuid(5BE18059-762E-4E73-9476-ABA294FED411)] -+interface IAccessible2_3 : IAccessible2_2 -+{ -+ /** -+ * @brief Returns an array of ranges for selections within the accessible. -+ * @param [out] ranges -+ The array of selection ranges, allocated by the server. The client must -+ free it with CoTaskMemFree. -+ * @param [out] nRanges -+ the array length -+ * @retval S_OK -+ * @retval S_FALSE returned if there is no selection within the accessible -+ */ -+ [propget] HRESULT selectionRanges -+ ( -+ [out, size_is(,*nRanges)] IA2Range **ranges, -+ [out, retval] long *nRanges -+ ); -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleComponent.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** A value specifying a color in ARGB format, where each 8 bit color component -+specifies alpha, red, green, and blue respectively. The alpha value is optional. -+*/ -+typedef long IA2Color; -+ -+/** @brief This interface is implemented by any object that can be rendered -+ on the screen. -+ -+ This interface provides the standard mechanism for an assistive technology -+ to retrieve information concerning the graphical representation of an object. -+ Coordinates used by the functions of this interface are specified in -+ different coordinate systems. Their scale is the same and is equal to -+ that of the screen coordinate system. In other words all coordinates -+ are measured in pixels. They differ in their respective origin: -+
    -+
  • The screen coordinate system has its origin in the upper left -+ corner of the current screen.
  • -+
  • The origin of the parent coordinate system is the upper left corner -+ of the parent's bounding box. With no parent the screen coordinate -+ system is used instead.
  • -+
-+*/ -+[object, uuid(1546D4B0-4C98-4bda-89AE-9A64748BDDE4)] -+interface IAccessibleComponent : IUnknown -+{ -+ -+ /** @brief Returns the location of the upper left corner of the object's -+ bounding box relative to the immediate parent object. -+ -+ The coordinates of the bounding box are given relative to the parent's -+ coordinate system. The coordinates of the returned position are relative -+ to this object's parent or relative to the screen on which this object -+ is rendered if it has no parent. If the object is not on any screen -+ the returned position is (0,0). -+ -+ @param [out] x -+ @param [out] y -+ @retval S_OK -+ */ -+ [propget] HRESULT locationInParent -+ ( -+ [out] long *x, -+ [out, retval] long *y -+ ); -+ -+ /** @brief Returns the foreground color of this object. -+ @param [out] foreground -+ The returned color is the foreground color of this object or, if -+ that is not supported, the default foreground color. -+ @retval S_OK -+ */ -+ [propget] HRESULT foreground -+ ( -+ [out, retval] IA2Color *foreground -+ ); -+ -+ /** @brief Returns the background color of this object. -+ @param [out] background -+ The returned color is the background color of this object or, if -+ that is not supported, the default background color. -+ @retval S_OK -+ */ -+ [propget] HRESULT background -+ ( -+ [out, retval] IA2Color *background -+ ); -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleValue.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface gives access to a single numerical value. -+ -+ The %IAccessibleValue interface represents a single numerical value and should -+ be implemented by any class that supports numerical value like progress bars -+ and spin boxes. This interface lets you access the value and its upper and -+ lower bounds. -+*/ -+[object, uuid(35855B5B-C566-4fd0-A7B1-E65465600394)] -+interface IAccessibleValue : IUnknown -+{ -+ -+ /** @brief Returns the value of this object as a number. -+ -+ The exact return type is implementation dependent. Typical types are long and -+ double. -+ @param [out] currentValue -+ Returns the current value represented by this object. See the section about -+ @ref _variants "VARIANTs" for additional information. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is a VARIANT with vt = VT_EMPTY -+ */ -+ [propget] HRESULT currentValue -+ ( -+ [out, retval] VARIANT *currentValue -+ ); -+ -+ /** @brief Sets the value of this object to the given number. -+ -+ The argument is clipped to the valid interval whose upper and lower -+ bounds are returned by the methods IAccessibleValue::maximumValue and -+ IAccessibleValue::minimumValue, i.e. if it is lower than the minimum -+ value the new value will be the minimum and if it is greater than the -+ maximum then the new value will be the maximum. -+ -+ @param [in] value -+ The new value represented by this object. The set of admissible types for -+ this argument is implementation dependent. -+ @retval S_OK -+ */ -+ HRESULT setCurrentValue -+ ( -+ [in] VARIANT value -+ ); -+ -+ /** @brief Returns the maximal value that can be represented by this object. -+ -+ The type of the returned value is implementation dependent. It does not have -+ to be the same type as that returned by method IAccessibleValue::currentValue. -+ -+ @param [out] maximumValue -+ Returns the maximal value in an implementation dependent type. If this object -+ has no upper bound then an empty object is returned. See the section about -+ @ref _variants "VARIANTs" for additional information. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is a VARIANT with vt = VT_EMPTY -+ */ -+ [propget] HRESULT maximumValue -+ ( -+ [out, retval] VARIANT *maximumValue -+ ); -+ -+ /** @brief Returns the minimal value that can be represented by this object. -+ -+ The type of the returned value is implementation dependent. It does not have -+ to be the same type as that returned by method IAccessibleValue::currentValue. -+ -+ @param [out] minimumValue -+ Returns the minimal value in an implementation dependent type. If this object -+ has no lower bound then an empty object is returned. See the section about -+ @ref _variants "VARIANTs" for additional information. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is a VARIANT with vt = VT_EMPTY -+ */ -+ [propget] HRESULT minimumValue -+ ( -+ [out, retval] VARIANT *minimumValue -+ ); -+ -+}; -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleText.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** A structure containing a substring and the start and end offsets in the enclosing string. -+ -+ IAccessibleText::newText and IAccessibleText::oldText return this struct. -+*/ -+typedef struct IA2TextSegment { -+ BSTR text; ///< A copy of a segment of text taken from an enclosing paragraph. -+ long start; ///< Index of the first character of the segment in the enclosing text. -+ long end; ///< Index of the character following the last character of the segment in the enclosing text. -+} IA2TextSegment; -+ -+/** This enum defines values which specify a text boundary type. -+ -+ IA2_TEXT_BOUNDARY_SENTENCE is optional. When a method doesn't implement this -+ method it must return S_FALSE. Typically this feature would not be implemented -+ by an application. However, if the application developer was not satisfied with -+ how screen readers have handled the reading of sentences this boundary type -+ could be implemented and screen readers could use the application's version of a -+ sentence rather than the screen reader's. -+ -+ The rest of the boundary types must be supported. -+ -+ This enum is used in IAccessibleText::textBeforeOffset, IAccessibleText::textAtOffset, -+ and IAccessibleText::textAfterOffset. -+*/ -+ -+enum IA2TextBoundaryType { -+ /** Typically, a single character is returned. In some cases more than one -+ character is returned, for example, when a document contains field data such -+ as a field containing a date, time, or footnote reference. In this case -+ the caret can move over several characters in one movement of the caret. -+ Note, that after the caret moves, the caret offset changes by the number of -+ characters in the field, e.g. by 8 characters in the following date: 03/26/07. -+ */ -+ IA2_TEXT_BOUNDARY_CHAR, -+ -+ /** The range provided matches the range observed when the application -+ processes the Ctrl + left arrow and Ctrl + right arrow key sequences. -+ Typically this is from the start of one word to the start of the next, but -+ various applications are inconsistent in the handling of the end of a line. -+ */ -+ IA2_TEXT_BOUNDARY_WORD, -+ -+ /** Range is from start of one sentence to the start of another sentence. -+ */ -+ IA2_TEXT_BOUNDARY_SENTENCE, -+ -+ /** Range is from start of one paragraph to the start of another paragraph. -+ */ -+ IA2_TEXT_BOUNDARY_PARAGRAPH, -+ -+ /** Range is from start of one line to the start of another line. This often -+ means that an end-of-line character will appear at the end of the range. -+ However in the case of some applications an end-of-line character indicates -+ the end of a paragraph and the lines composing the paragraph, other than -+ the last line, do not contain an end of line character. -+ */ -+ IA2_TEXT_BOUNDARY_LINE, -+ -+ /** Deprecated. Using this value will cause all text to be returned. -+ Note: IAccessibleText::text should be used instead. -+ */ -+ IA2_TEXT_BOUNDARY_ALL -+}; -+ -+/** @brief This interface gives read-only access to text. -+ -+ The %IAccessibleText interface should be implemented by all components -+ that present textual information on the display like buttons, -+ text entry fields, or text portions of the document window. The interface -+ provides access to the text's content, attributes, and spatial location. -+ However, text can not be modified with this interface. That is the task -+ of the IAccessibleEditableText interface. -+ -+ The text length, i.e. the number of characters in the text, is -+ returned by IAccessibleText::nCharacters. All methods that operate -+ on particular characters (e.g. IAccessibleText::textAtOffset) use character -+ indices from 0 to length-1. All methods that operate on character positions -+ (e.g. IAccessibleText::text) use indices from 0 to length. -+ -+ Please note that accessible text does not necessarily support selection. -+ In this case it should behave as if there where no selection. An empty -+ selection is used for example to express the current cursor position. -+ -+ Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ -+ E_FAIL is returned in the following cases -+ @li endOffset < startOffset -+ @li endoffset > length -+*/ -+[object, uuid(24FD2FFB-3AAD-4a08-8335-A3AD89C0FB4B)] -+interface IAccessibleText : IUnknown -+{ -+ -+ /** @brief Adds a text selection -+ @param [in] startOffset -+ Starting offset ( 0 based). -+ @param [in] endOffset -+ Offset of first character after new selection (0 based). -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ */ -+ HRESULT addSelection -+ ( -+ [in] long startOffset, -+ [in] long endOffset -+ ); -+ -+ /** @brief Returns text attributes. -+ @param [in] offset -+ Text offset (0 based). Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ @param [out] startOffset -+ The starting offset of the character range over which all text attributes match -+ those of offset. (0 based) -+ @param [out] endOffset -+ The offset of the first character past the character range over which all text -+ attributes match those of offset. (0 based) -+ @param [out] textAttributes -+ A string of attributes describing the text. The attributes are described in the -+ -+ text attributes specification on the %IAccessible2 web site. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] values are 0s and NULL respectively -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT attributes -+ ( -+ [in] long offset, -+ [out] long *startOffset, -+ [out] long *endOffset, -+ [out, retval] BSTR *textAttributes -+ ); -+ -+ /** @brief Returns the position of the caret. -+ -+ Returns the 0-based offset of the caret within the text. If the text is -+ implemented as a tree of text objects with embed characters in higher levels -+ representing substrings of child text objects and the caret is in one of the -+ child text objects, then the offset in the higher level text object would be -+ at the embed character representing child text object that contains the caret. -+ -+ For example, if the string "one two three" is implemented as a two text objects, -+ with a top level text object containing an embed character "one ? three" and a -+ child text object containing "two" and if the caret is in the descendant object -+ just before the 'o' in "two", then: -+
    -+
  • the caretOffset for the "one ? three" object would be 4, matching the embed character
  • -+
  • the caretOffset for "two" would be 2, matching the "o"
  • -+
-+ The caret position/offset is that of the character logically following it, e.g. -+ to the right of it in a left to right language, or to the left of it in a right -+ to left language. -+ @param [out] offset -+ The returned offset is relative to the text represented by this object. -+ @retval S_OK -+ @retval S_FALSE if the caret is not currently active on this object, i.e. the -+ caret is located on some other object. The returned offset value will be -1. -+ @note S_FALSE (and an offset of -1) will not be returned if the caret is somewhere -+ in the text object or one of its descendants. -+ */ -+ [propget] HRESULT caretOffset -+ ( -+ [out, retval] long *offset -+ ); -+ -+ -+ /** @brief Returns the bounding box of the specified position. -+ -+ The virtual character after the last character of the represented -+ text, i.e. the one at position length is a special case. It represents the -+ current input position and will therefore typically be queried by AT more -+ often than other positions. Because it does not represent an existing character -+ its bounding box is defined in relation to preceding characters. It should be -+ roughly equivalent to the bounding box of some character when inserted at the -+ end of the text. Its height typically being the maximal height of all the -+ characters in the text or the height of the preceding character, its width being -+ at least one pixel so that the bounding box is not degenerate. -+ -+ Note that the index 'length' is not always valid. Whether it is or not is -+ implementation dependent. It typically is when text is editable or otherwise -+ when on the screen the caret can be placed behind the text. You can be sure -+ that the index is valid after you have received a ::IA2_EVENT_TEXT_CARET_MOVED -+ event for this index. -+ @param [in] offset -+ Index of the character for which to return its bounding box. The valid range -+ is 0..length. Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ @param [in] coordType -+ Specifies if the coordinates are relative to the screen or to the parent window. -+ @param [out] x -+ X coordinate of the top left corner of the bounding box of the referenced character. -+ @param [out] y -+ Y coordinate of the top left corner of the bounding box of the referenced character. -+ @param [out] width -+ Width of the bounding box of the referenced character. -+ @param [out] height -+ Height of the bounding box of the referenced character. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT characterExtents -+ ( -+ [in] long offset, -+ [in] enum IA2CoordinateType coordType, -+ [out] long *x, -+ [out] long *y, -+ [out] long *width, -+ [out, retval] long *height -+ ); -+ -+ -+ /** @brief Returns the number of active non-contiguous selections -+ @param [out] nSelections -+ @retval S_OK -+ */ -+ [propget] HRESULT nSelections -+ ( -+ [out, retval] long *nSelections -+ ); -+ -+ /** @brief Returns the text position for the specified screen position. -+ -+ Given a point return the zero-based index of the character under that -+ point. The same functionality could be achieved by using the bounding -+ boxes for each character as returned by IAccessibleText::characterExtents. -+ The method IAccessibleText::offsetAtPoint, however, can be implemented -+ more efficiently. -+ -+ @param [in] x -+ The position's x value for which to look up the index of the character that -+ is rendered on to the display at that point. -+ @param [in] y -+ The position's y value for which to look up the index of the character that -+ is rendered on to the display at that point. -+ @param [in] coordType -+ Screen coordinates or window coordinates. -+ @param [out] offset -+ Index of the character under the given point or -1 if the point -+ is invalid or there is no character under the point. -+ @retval S_OK -+ @retval S_FALSE if nothing to return, [out] value is -1 -+ -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT offsetAtPoint -+ ( -+ [in] long x, -+ [in] long y, -+ [in] enum IA2CoordinateType coordType, -+ [out, retval] long *offset -+ ); -+ -+ /** @brief Returns the character offsets of Nth active text selection -+ -+ Returns the 0-based starting and ending offsets of the Nth selection. If the -+ text is implemented as a tree of text objects with embed characters in higher -+ levels representing substrings of child text objects, consider the following. -+ If the starting selection offset is in one of the child text objects, then the -+ starting offset in the higher level text object would be at the embed character -+ representing the child text object that contains the starting selection offset. -+ If the ending selection offset is in one of the child text objects, then the -+ ending offset in the higher level text object would be just after the embed -+ character representing the child text object that contains the ending selection -+ offset. -+ -+ For example, if the string "one two three" is implemented as a two text objects, -+ with a top level text object containing an embed character "one ? three" and a -+ child text object containing "two" and if the selection is the string "two" then: -+
    -+
  • the startOffset for the "one ? three" object would be 4, matching the embed character and the endOffset would be 5.
  • -+
  • the startOffset for the "two" object would be 0, and the endOffset would be 3
  • -+
-+ Selection offsets are that of the character logically following it, e.g. -+ to the right of it in a left to right language or to the left of it in a right to left language. -+ @param [in] selectionIndex -+ Index of selection (0 based). -+ @param [out] startOffset -+ 0 based offset of first selected character -+ @param [out] endOffset -+ 0 based offset of one past the last selected character. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT selection -+ ( -+ [in] long selectionIndex, -+ [out] long *startOffset, -+ [out, retval] long *endOffset -+ ); -+ -+ /** @brief Returns the substring between the two given indices. -+ -+ The substring starts with the character at startOffset (inclusive) and up to -+ the character at endOffset (exclusive), if startOffset is less or equal -+ endOffset. If endOffset is lower than startOffset, the result is the same -+ as a call with the two arguments being exchanged. -+ -+ The whole text can be requested by passing the indices zero and -+ IAccessibleText::nCharacters. If both indices have the same value, an empty -+ string is returned. -+ @param [in] startOffset -+ Index of the first character to include in the returned string. The valid range -+ is 0..length. -+ @param [in] endOffset -+ Index of the last character to exclude in the returned string. The valid range -+ is 0..length. -+ @param [out] text -+ Returns the substring starting with the character at startOffset (inclusive) -+ and up to the character at endOffset (exclusive), if startOffset is less than -+ or equal to endOffset. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note -+ @li The returned string may be longer than endOffset-startOffset bytes if text -+ contains multi-byte characters. -+ @li Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ */ -+ [propget] HRESULT text -+ ( -+ [in] long startOffset, -+ [in] long endOffset, -+ [out, retval] BSTR *text -+ ); -+ -+ /** @brief Returns a text portion before the given position. -+ -+ Returns the substring of the specified text type that is located before the -+ given character and does not include it. The result of this method should be -+ same as a result for IAccessibleText::textAtOffset with a suitably decreased -+ index value. -+ -+ For example, if text type is ::IA2_TEXT_BOUNDARY_WORD, then the complete -+ word that is closest to and located before offset is returned. -+ -+ If the index is valid, but no text is found, S_FALSE is returned along with out -+ values of 0, 0, and a NULL pointer. This would happen for boundary types other -+ than character when the text consists entirely of whitespace. -+ -+ @param [in] offset -+ Index of the character for which to return the text part before it. The index -+ character will not be part of the returned string. The valid range is 0..length. -+ Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ @param [in] boundaryType -+ The type of the text portion to return. See ::IA2TextBoundaryType for the -+ complete list. -+ @param [out] startOffset -+ 0 based offset of first character. -+ @param [out] endOffset -+ 0 based offset of one past the last character. -+ @param [out] text -+ Returns the requested text portion. This portion may be empty or invalid when -+ no appropriate text portion is found or text type is invalid. -+ @retval S_OK -+ @retval S_FALSE if the requested boundary type is not implemented, such as -+ ::IA2_TEXT_BOUNDARY_SENTENCE, or if there is nothing to return; -+ [out] values are 0s and NULL respectively -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT textBeforeOffset -+ ( -+ [in] long offset, -+ [in] enum IA2TextBoundaryType boundaryType, -+ [out] long *startOffset, -+ [out] long *endOffset, -+ [out, retval] BSTR *text -+ ); -+ -+ /** @brief Returns a text portion after the given position. -+ -+ Returns the substring of the specified text type that is located after the -+ given character and does not include it. The result of this method should be -+ same as a result for IAccessibleText::textAtOffset with a suitably increased -+ index value. -+ -+ For example, if text type is ::IA2_TEXT_BOUNDARY_WORD, then the complete -+ word that is closest to and located after offset is returned. -+ -+ If the index is valid, but no text is found, S_FALSE is returned along with out -+ values of 0, 0, and a NULL pointer. This would happen for boundary types other -+ than character when the text consists entirely of whitespace. -+ -+ @param [in] offset -+ Index of the character for which to return the text part after it. The index -+ character will not be part of the returned string. The valid range is 0..length. -+ Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ @param [in] boundaryType -+ The type of the text portion to return. See ::IA2TextBoundaryType for the complete -+ list. -+ @param [out] startOffset -+ 0 based offset of first character. -+ @param [out] endOffset -+ 0 based offset of one past the last character. -+ @param [out] text -+ Returns the requested text portion. This portion may be empty or invalid when -+ no appropriate text portion is found or text type is invalid. -+ @retval S_OK -+ @retval S_FALSE if the requested boundary type is not implemented, such as -+ ::IA2_TEXT_BOUNDARY_SENTENCE, or if there is nothing to return; -+ [out] values are 0s and NULL respectively -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT textAfterOffset -+ ( -+ [in] long offset, -+ [in] enum IA2TextBoundaryType boundaryType, -+ [out] long *startOffset, -+ [out] long *endOffset, -+ [out, retval] BSTR *text -+ ); -+ -+ /** @brief Returns a text portion that spans the given position. -+ -+ Returns the substring defined by the specified boundary type at the specified -+ offset. Refer to IA2TextBoundaryType for more details. -+ -+ For the word boundary type the returned string will contain the word at the -+ offset if the offset is inside a word and will contain the word before the -+ offset if the offset is not inside a word. All offsets from the first to the -+ last characters of a word are considered inside the word. Boundary types of -+ sentence and paragraph should exhibit similar behavior. -+ -+ If the index is valid, but no text is found, S_FALSE is returned along with out -+ values of 0, 0, and a NULL pointer. This would happen for boundary types other -+ than character when the text consists entirely of whitespace. -+ -+ @param [in] offset -+ Index of the character for which to return the text part it belongs to. The valid -+ range is 0..length. -+ Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ @param [in] boundaryType -+ The type of the text portion to return. See ::IA2TextBoundaryType for the complete -+ list. -+ @param [out] startOffset -+ 0 based offset of first character. -+ @param [out] endOffset -+ 0 based offset of one past the last character. -+ @param [out] text -+ Returns the requested text portion. This portion may be empty or invalid when -+ no appropriate text portion is found or text type is invalid. -+ @retval S_OK -+ @retval S_FALSE if the requested boundary type is not implemented, such as -+ ::IA2_TEXT_BOUNDARY_SENTENCE, or if there is nothing to return; -+ [out] values are 0s and NULL respectively -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT textAtOffset -+ ( -+ [in] long offset, -+ [in] enum IA2TextBoundaryType boundaryType, -+ [out] long *startOffset, -+ [out] long *endOffset, -+ [out, retval] BSTR *text -+ ); -+ -+ /** @brief Unselects a range of text. -+ @param [in] selectionIndex -+ Index of selection to remove (0 based). -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT removeSelection -+ ( -+ [in] long selectionIndex -+ ); -+ -+ /** @brief Sets the position of the caret. -+ -+ The caret position/offset is that of the character logically following it, -+ e.g. to the right of it in a left to right language. -+ -+ Setting the caret position may or may not alter the current selection. A -+ change of the selection is notified to the accessibility event listeners with -+ an ::IA2_EVENT_TEXT_SELECTION_CHANGED event. -+ -+ When the new caret position differs from the old one (which, of course, is the -+ standard case) this is notified to the accessibility event listeners with an -+ ::IA2_EVENT_TEXT_CARET_MOVED event. -+ @param [in] offset -+ The new index of the caret. This caret is actually placed to the left side of -+ the character with that index. An index of 0 places the caret so that the next -+ insertion goes before the first character. An index of IAccessibleText::nCharacters -+ leads to insertion after the last character. Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ @retval S_OK -+ @retval E_FAIL if the caret cannot be set -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT setCaretOffset -+ ( -+ [in] long offset -+ ); -+ -+ /** @brief Changes the bounds of an existing selection. -+ @param [in] selectionIndex -+ Index of selection to change (0 based) -+ @param [in] startOffset -+ New starting offset (0 based) -+ @param [in] endOffset -+ New ending offset (0 based) - the offset of the character just past the last character of the selection. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ */ -+ HRESULT setSelection -+ ( -+ [in] long selectionIndex, -+ [in] long startOffset, -+ [in] long endOffset -+ ); -+ -+ /** @brief Returns total number of characters. -+ -+ Note that this may be different than the total number of bytes required to store the -+ text, if the text contains multi-byte characters. -+ @param [out] nCharacters -+ @retval S_OK -+ */ -+ [propget] HRESULT nCharacters -+ ( -+ [out, retval] long *nCharacters -+ ); -+ -+ /** @brief Makes a specific part of string visible on screen. -+ @param [in] startIndex -+ 0 based character offset. -+ @param [in] endIndex -+ 0 based character offset - the offset of the character just past the last character of the string. -+ @param [in] scrollType -+ Defines where the object should be placed on the screen. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ */ -+ HRESULT scrollSubstringTo -+ ( -+ [in] long startIndex, -+ [in] long endIndex, -+ [in] enum IA2ScrollType scrollType -+ ); -+ -+ /** @brief Moves the top left of a substring to a specified location. -+ -+ @param [in] startIndex -+ 0 based character offset. -+ @param [in] endIndex -+ 0 based character offset - the offset of the character just past the last character of the string. -+ @param [in] coordinateType -+ Specifies whether the coordinates are relative to the screen or the parent object. -+ @param [in] x -+ Defines the x coordinate. -+ @param [in] y -+ Defines the y coordinate. -+ @retval S_OK -+ @retval S_FALSE if the object is already at the specified location. -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleText methods. -+ */ -+ HRESULT scrollSubstringToPoint -+ ( -+ [in] long startIndex, -+ [in] long endIndex, -+ [in] enum IA2CoordinateType coordinateType, -+ [in] long x, -+ [in] long y -+ ); -+ -+ /** @brief Returns any inserted text. -+ -+ Provided for use by the ::IA2_EVENT_TEXT_INSERTED and ::IA2_EVENT_TEXT_UPDATED -+ event handlers. -+ -+ This data is only guaranteed to be valid while the thread notifying the event -+ continues. Once the handler has returned, the validity of the data depends on -+ how the server manages the life cycle of its objects. Also, note that the server -+ may have different life cycle management strategies for controls depending on -+ whether or not a control manages its children. Lists, trees, and tables can have -+ a large number of children and thus it's possible that the child objects for those -+ controls would only be created as needed. Servers should document their life cycle -+ strategy as this will be of interest to assistive technology or script engines -+ accessing data out of process or from other threads. Servers only need to save the -+ last inserted block of text and a scope of the entire application is adequate. -+ -+ @param [out] newText -+ The text that was just inserted. -+ @retval S_OK -+ @retval S_FALSE If there is nothing to return, the values of IA2TextSegment -+ struct are set as follows: text = NULL, start = 0, end = 0. -+ -+ */ -+ [propget] HRESULT newText -+ ( -+ [out, retval] IA2TextSegment *newText -+ ); -+ -+ /** @brief Returns any removed text. -+ -+ Provided for use by the IA2_EVENT_TEXT_REMOVED/UPDATED event handlers. -+ -+ This data is only guaranteed to be valid while the thread notifying the event -+ continues. Once the handler has returned, the validity of the data depends on -+ how the server manages the life cycle of its objects. Also, note that the server -+ may have different life cycle management strategies for controls depending on -+ whether or not a control manages its children. Lists, trees, and tables can have -+ a large number of children and thus it's possible that the child objects for those -+ controls would only be created as needed. Servers should document their life cycle -+ strategy as this will be of interest to assistive technology or script engines -+ accessing data out of process or from other threads. Servers only need to save the -+ last removed block of text and a scope of the entire application is adequate. -+ -+ @param [out] oldText -+ The text that was just removed. -+ @retval S_OK -+ @retval S_FALSE If there is nothing to return, the values of IA2TextSegment -+ struct are set as follows: text = NULL, start = 0, end = 0. -+ */ -+ [propget] HRESULT oldText -+ ( -+ [out, retval] IA2TextSegment *oldText -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleText2.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface gives read-only access to text. -+ -+ The %IAccessibleText2 interface extends the functionality of the -+ %IAccessibleText interface. -+*/ -+/* -+[object, uuid(9690A9CC-5C80-4DF5-852E-2D5AE4189A54)] -+interface IAccessibleText2 : IAccessibleText -+{ -+*/ -+ /** @brief Returns the range and of the specified set of attributes. -+ -+ Return the range (start and end offsets) and text attributes that correspond -+ to the given attributes filter at the given offset. -+ -+ @param [in] offset -+ The offset at which to search for the attributes specified in the filter. -+ @param [in] filter -+ The requested attribute names. The filter format is "attribute1, attribute2". -+ @param [out] startOffset -+ The starting (0-based) offset of the text containing the specified attributes. -+ @param [out] endOffset -+ The (0-based) offset one past the last character of the text containing the -+ specified attributes. -+ @param [out] attributeValues -+ The values of the requested attributes. -+ @retval S_OK -+ @retval S_FALSE if nothing to return, [out] values are -1, -1, NULL respectively. -+ @retval E_INVALIDARG if bad [in] passed. -+ */ -+/* -+ [propget] HRESULT attributeRange -+ ( -+ [in] long offset, -+ [in] BSTR filter, -+ [out] long *startOffset, -+ [out] long *endOffset, -+ [out, retval] BSTR *attributeValues -+ ); -+ -+} -+*/ -+/************************************************************************* -+ * -+ * File Name (AccessibleEditableText.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2012 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface provides clipboard capability to text objects. -+ -+ This interface is typically used in conjunction with the IAccessibleText -+ interface and complements that interface with the additional capability of -+ clipboard operations. Note that even a read only text object can support -+ the copy capability so this interface is not limited to editable objects. -+ -+ The substrings used with this interface are specified as follows: -+ If startOffset is less than endOffset, the substring starts with the -+ character at startOffset and ends with the character just before endOffset. -+ If endOffset is lower than startOffset, the result is the same as a call -+ with the two arguments exchanged. The whole text can be defined by passing -+ the indices zero and IAccessibleText::nCharacters. If both indices have the -+ same value, an empty string is defined. -+ -+ Refer to the @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about a special offset constant that can be used in %IAccessibleEditableText methods. -+*/ -+[object, uuid(A59AA09A-7011-4b65-939D-32B1FB5547E3)] -+interface IAccessibleEditableText : IUnknown -+{ -+ -+ /** @brief Copies the text range into the clipboard. -+ -+ The selection is set to the specified offsets and then selection is copied into -+ the system clipboard. -+ -+ @param [in] startOffset -+ Start index of the text to moved into the clipboard. -+ The valid range is 0..length. -+ @param [in] endOffset -+ End index of the text to moved into the clipboard. -+ The valid range is 0..length. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleEditableText -+ methods. -+ @deprecated This function is available via the application's GUI. -+ */ -+ HRESULT copyText -+ ( -+ [in] long startOffset, -+ [in] long endOffset -+ ); -+ -+ /** @brief Deletes a range of text. -+ -+ The text between and including the two given indices is deleted -+ from the text represented by this object. -+ -+ @param [in] startOffset -+ Start index of the text to be deleted. -+ The valid range is 0..length. -+ @param [in] endOffset -+ End index of the text to be deleted. -+ The valid range is 0..length. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleEditableText -+ methods. -+ */ -+ HRESULT deleteText -+ ( -+ [in] long startOffset, -+ [in] long endOffset -+ ); -+ -+ /** @brief Inserts text at the specified position. -+ -+ The specified string is inserted at the given index into the text -+ represented by this object. -+ -+ @param [in] offset -+ Index at which to insert the text. -+ The valid range is 0..length. -+ Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleEditableText -+ methods. -+ @param [in] text -+ Text that is inserted. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT insertText -+ ( -+ [in] long offset, -+ [in] BSTR *text -+ ); -+ -+ /** @brief Deletes a range of text and copies it to the clipboard. -+ -+ The selection is set to the specified offsets, the selection is then copied into -+ the system clipboard, and then the selection is deleted. -+ -+ @param [in] startOffset -+ Start index of the text to be deleted. -+ The valid range is 0..length. -+ @param [in] endOffset -+ End index of the text to be deleted. -+ The valid range is 0..length. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleEditableText -+ methods. -+ @deprecated This function is available via the application's GUI. -+ */ -+ HRESULT cutText -+ ( -+ [in] long startOffset, -+ [in] long endOffset -+ ); -+ -+ /** @brief Pastes content from the clipboard. -+ -+ Any existing selection is removed, the clipboard content is then pasted into -+ this object's text at the given offset. This method is similar to the insertText -+ method. If the index is not valid the system clipboard content is not inserted. The -+ behavior is the same as when Ctrl+V is used, i.e. the pasted contents are not -+ necessarily plain text. -+ -+ @param [in] offset -+ Index at which to insert the content from the system clipboard into -+ the text represented by this object. -+ The valid range is 0..length. -+ Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleEditableText -+ methods. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @deprecated This function is available via the application's GUI. -+ */ -+ HRESULT pasteText -+ ( -+ [in] long offset -+ ); -+ -+ /** @brief Replaces text. -+ -+ The text between the two given indices is replaced by the specified -+ replacement string. This method is equivalent to calling first -+ IAccessibleEditableText::deleteText with the two indices and then -+ calling IAccessibleEditableText::insertText with the replacement text -+ at the start index. -+ -+ @param [in] startOffset -+ Start index of the text to be replaced. -+ The valid range is 0..length. -+ @param [in] endOffset -+ End index of the text to be replaced. -+ The valid range is 0..length. -+ @param [in] text -+ The Text that replaces the text between the given indices. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleEditableText -+ methods. -+ */ -+ HRESULT replaceText -+ ( -+ [in] long startOffset, -+ [in] long endOffset, -+ [in] BSTR *text -+ ); -+ -+ /** @brief Replaces the attributes of a text range by the given set of attributes. -+ -+ Sets the attributes for the text between the two given indices. The old -+ attributes are replaced by the new list of attributes. -+ -+ @param [in] startOffset -+ Start index of the text whose attributes are modified. -+ The valid range is 0..length. -+ @param [in] endOffset -+ End index of the text whose attributes are modified. -+ The valid range is 0..length. -+ @param [in] attributes -+ Set of attributes that replaces the old list of attributes of -+ the specified text portion. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ @note Refer to @ref _specialOffsets -+ "Special Offsets for use in the IAccessibleText and IAccessibleEditableText Methods" -+ for information about special offsets that can be used in %IAccessibleEditableText -+ methods. -+ */ -+ HRESULT setAttributes -+ ( -+ [in] long startOffset, -+ [in] long endOffset, -+ [in] BSTR *attributes -+ ); -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleHyperlink.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface represents hyperlinks. -+ -+ This interface represents a hyperlink associated with a single substring -+ of text or single non-text object. Non-text objects can have either a -+ single link or a collection of links such as when the non-text object is -+ an image map. -+ -+ Linked objects and anchors are implementation dependent. This interface is derived -+ from IAccessibleAction. IAccessibleAction::nActions is one greater than the -+ maximum value for the indices used with the methods of this interface. -+ -+ Furthermore, the object that implements this interface has to be connected -+ implicitly or explicitly with an object that implements IAccessibleText. -+ IAccessibleHyperlink::startIndex and IAccessibleHyperlink::endIndex are -+ indices with respect to the text exposed by IAccessibleText. -+ -+ This interface provides access to a single object which can have multiple actions. -+ An example is an image map which is an image with multiple links each of which is -+ associated with a separate non-overlapping area of the image. This interface could -+ also be applied to other kinds of objects with multiple actions such as "smart tags" -+ which are objects, typically strings, which have multiple actions such as -+ "Activate URI", "Bookmark URI", etc. -+ -+ An interesting use case is an image map where each area is associated with multiple -+ actions, e.g. an image map of smart tags. In this case you would have to implement -+ two levels of accessible hyperlinks. The first level hyperlinks would only implement -+ anchor and anchorTarget. The anchors would all reference the image object. The -+ anchorTargets would reference the second level accessible hyperlink objects. None -+ of the IAccessibleAction methods would be implemented on the first level hyperlink -+ objects. The second level hyperlink objects would implement the IAccessibleAction -+ methods. Their anchors would also reference the image object and their anchorTargets -+ would reference URLs or the objects that would be activated. -+ -+ This use case demonstrates that in some cases there is no need for IAccessibleHyperlink -+ to derive from IAccessibleAction. As a result it may be removed in a later version of -+ the IDL and it is suggested that implementations should not rely on the inheritance. -+ -+*/ -+[object, uuid(01C20F2B-3DD2-400f-949F-AD00BDAB1D41)] -+interface IAccessibleHyperlink : IAccessibleAction -+{ -+ -+ /** @brief Returns an object that represents the link anchor, as appropriate -+ for the link at the specified index. -+ @param [in] index -+ A 0 based index identifies the anchor when, as in the case of an image map, -+ there is more than one link represented by this object. The valid maximal -+ index is indicated by IAccessibleAction::nActions. -+ @param [out] anchor -+ This is an implementation dependent value. For example, for a text link this -+ method could return the substring of the containing string where the substring -+ is overridden with link behavior, and for an image link this method could return -+ an IUnknown VARIANT for IAccessibleImage. See the section about -+ @ref _variants "VARIANTs" for additional information. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT anchor -+ ( -+ [in] long index, -+ [out, retval] VARIANT *anchor -+ ); -+ -+ /** @brief Returns an object representing the target of the link, as appropriate -+ for the link at the specified index. -+ @param [in] index -+ A 0 based index identifies the anchor when, as in the case of an image map, -+ there is more than one link represented by this object. The valid maximal -+ index is indicated by IAccessibleAction::nActions. -+ @param [out] anchorTarget -+ This is an implementation dependent value. For example this method could -+ return a BSTR VARIANT of the URI. Alternatively this method could return an -+ IUnknown VARIANT of a COM interface representing a target object to be -+ activated when the link is activated. See the section about -+ @ref _variants "VARIANTs" for additional information. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT anchorTarget -+ ( -+ [in] long index, -+ [out, retval] VARIANT *anchorTarget -+ ); -+ -+ /** @brief Returns the 0 based character offset at which the textual representation of the hyperlink starts. -+ -+ The returned value is related to the IAccessibleText interface of the object that -+ owns this hyperlink. -+ @param [out] index -+ @retval S_OK -+ */ -+ [propget] HRESULT startIndex -+ ( -+ [out, retval] long *index -+ ); -+ -+ /** @brief Returns the 0 based character offset at which the textual representation of the hyperlink ends. -+ -+ The returned value is related to the IAccessibleText interface of the object that -+ owns this hyperlink. The character at the index is not part of the hypertext. -+ @param [out] index -+ @retval S_OK -+ */ -+ [propget] HRESULT endIndex -+ ( -+ [out, retval] long *index -+ ); -+ -+ /** @brief Returns whether the target object referenced by this link is still valid. -+ -+ This is a volatile state that may change without sending an appropriate event. -+ Returns TRUE if the referenced target is still valid and FALSE otherwise. -+ -+ This has also been used to indicate whether or not the URI of the anchorTarget -+ is malformed. -+ -+ @param [out] valid -+ If false, one or more of the object's links are invalid. -+ If true, all of the object's links are valid. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is FALSE -+ @note This method is not being used, is deprecated, and should not be implemented or -+ used. It is likely that this method will be removed in a later version of the IDL. -+ */ -+ [propget] HRESULT valid -+ ( -+ [out, retval] boolean *valid -+ ); -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleHypertext.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface exposes information about hypertext in a document. -+ -+ The %IAccessibleHypertext interface is the main interface to expose -+ hyperlinks in a document, typically a text document, that are used -+ to reference other documents. A typical implementation is to implement -+ this interface on the smallest text object such as a paragraph of text. -+*/ -+[object, uuid(6B4F8BBF-F1F2-418a-B35E-A195BC4103B9)] -+interface IAccessibleHypertext : IAccessibleText -+{ -+ -+ /** @brief Returns the number of links and link groups contained within this hypertext -+ paragraph. -+ @param [out] hyperlinkCount -+ The number of links and link groups within this hypertext paragraph. -+ Returns 0 if there is no link. -+ @retval S_OK -+ */ -+ [propget] HRESULT nHyperlinks -+ ( -+ [out, retval] long *hyperlinkCount -+ ); -+ -+ /** @brief Returns the specified link. -+ -+ The returned IAccessibleHyperlink object encapsulates the hyperlink and -+ provides several kinds of information describing it. -+ @param [in] index -+ This 0 based index specifies the hyperlink to return. -+ @param [out] hyperlink -+ If the given index is valid, i.e. lies in the interval from 0 to the number -+ of links minus one, a reference to the specified hyperlink object is returned. -+ If the index is invalid then a NULL pointer is returned. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT hyperlink -+ ( -+ [in] long index, -+ [out, retval] IAccessibleHyperlink **hyperlink -+ ); -+ -+ /** @brief Returns the index of the hyperlink that is associated with this character index. -+ -+ This is the case when a link spans the given character index. -+ @param [in] charIndex -+ A 0 based index of the character for which to return the link index. If -+ IAccessibleText is used to represent the text containing the link, then the -+ character index is only valid if it is greater than or equal to zero and -+ lower than the number of characters in the text. -+ @param [out] hyperlinkIndex -+ Returns the 0 based index of the hyperlink that is associated with this -+ character index, or -1 if charIndex is not on a link. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is -1 -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT hyperlinkIndex -+ ( -+ [in] long charIndex, -+ [out, retval] long *hyperlinkIndex -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleHypertext2.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface exposes information about hypertext in a document. -+ -+ The %IAccessibleHypertext2 interface extends the functinality of the -+ %IAccessibleHypertext inteface. -+*/ -+[object, uuid(CF64D89F-8287-4B44-8501-A827453A6077)] -+interface IAccessibleHypertext2 : IAccessibleHypertext -+{ -+ -+ /** @brief Returns the links for this object. -+ -+ The returned IAccessibleHyperlink objects encapsulate the hyperlink and -+ provides several kinds of information describing it. -+ -+ @param [out] hyperlinks -+ This array is allocated by the server. The client must free it with CoTaskMemFree. -+ @param [out] nHyperlinks -+ The number of links returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are no links, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT hyperlinks -+ ( -+ [out, size_is(,*nHyperlinks)] IAccessibleHyperlink ***hyperlinks, -+ [out, retval] long *nHyperlinks -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleTable.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface gives access to a two-dimensional table. -+ -+ Typically all accessible objects that represent cells or cell-clusters of a table -+ will be at the same time children of the table. In this case IAccessible2::indexInParent -+ will return the child index which then can be used when calling IAccessibleTable::rowIndex -+ and IAccessibleTable::columnIndex. -+ -+ However, in some cases that kind of implementation will not be possible. When -+ the table cells are not direct children of a table, the object representing -+ the cell can define a "table-cell-index" object attribute identifying the 0 -+ based table cell index. This object attribute is obtained by parsing the -+ attribute string returned by IAccessible2::attributes. The "table-cell-index" -+ attribute can be used just like a child index of the typical case. ATs should -+ first test for the presence of the "table-cell-index" attribute and if it is not -+ present then IAccessible2::indexInParent can be used as in the typical case -+ where cells are direct children of the table. -+ -+ The range of valid coordinates for this interface are implementation dependent. -+ However, that range includes at least the intervals from the from the first row -+ or column with the index 0 up to the last (but not including) used row or column -+ as returned by IAccessibleTable::nRows and IAccessibleTable::nColumns. -+ -+ Note that newer implementations are now using IAccessibleTable2 and IAccessibleTableCell -+ rather than this interface. -+*/ -+[object, uuid(35AD8070-C20C-4fb4-B094-F4F7275DD469)] -+interface IAccessibleTable : IUnknown -+{ -+ -+ /** @brief Returns the accessible object at the specified row and column in -+ the table. This object could be an IAccessible or an IAccessible2. -+ @param [in] row -+ The 0 based row index for which to retrieve the cell. -+ @param [in] column -+ The 0 based column index for which to retrieve the cell. -+ @param [out] accessible -+ If both row and column index are valid then the corresponding accessible -+ object is returned that represents the requested cell regardless of whether -+ the cell is currently visible (on the screen). -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is NULL -+ */ -+ [propget] HRESULT accessibleAt -+ ( -+ [in] long row, -+ [in] long column, -+ [out, retval] IUnknown **accessible -+ ); -+ -+ /** @brief Returns the caption for the table. The returned object could be -+ an IAccessible or an IAccessible2. -+ @param [out] accessible -+ If the table has a caption then a reference to it is returned, else a NULL -+ pointer is returned. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT caption -+ ( -+ [out, retval] IUnknown **accessible -+ ); -+ -+ /** @brief Translates the given row and column indexes into the corresponding cell index. -+ @param [in] rowIndex -+ 0 based row index for the cell. -+ @param [in] columnIndex -+ 0 based column index for the cell. -+ @param [out] cellIndex -+ Returns the 0 based index of the cell at the specified row and column indexes. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is 0 -+ @note The returned value is not necessarily a child index of the immediate parent. -+ In cases where the table cells are not direct children of the table the index -+ is actually the cell index, i.e. conceptually it's an index into a one dimensional -+ array of cells laid out in row order. -+ */ -+ [propget] HRESULT childIndex -+ ( -+ [in] long rowIndex, -+ [in] long columnIndex, -+ [out, retval] long *cellIndex -+ ); -+ -+ /** @brief Returns the description text of the specified column in the table. -+ @param [in] column -+ The 0 based index of the column for which to retrieve the description. -+ @param [out] description -+ Returns the description text of the specified column in the table if such a -+ description exists. Otherwise a NULL pointer is returned. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @retval E_INVALIDARG if bad [in] passed, [out] value is NULL -+ */ -+ [propget] HRESULT columnDescription -+ ( -+ [in] long column, -+ [out, retval] BSTR *description -+ ); -+ -+ /** @brief Returns the number of columns occupied by the accessible object -+ at the specified row and column in the table. -+ -+ The result is greater than 1 if the specified cell spans multiple columns. -+ @param [in] row -+ 0 based row index of the accessible for which to return the column extent. -+ @param [in] column -+ 0 based column index of the accessible for which to return the column extent. -+ @param [out] nColumnsSpanned -+ Returns the 1 based column extent of the specified cell. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is 0 -+ */ -+ [propget] HRESULT columnExtentAt -+ ( -+ [in] long row, -+ [in] long column, -+ [out, retval] long *nColumnsSpanned -+ ); -+ -+ /** @brief Returns the column headers as an %IAccessibleTable object. -+ -+ Content and size of the returned table are implementation dependent. -+ @param [out] accessibleTable -+ The column header -+ @param [out] startingRowIndex -+ The 0 based row index where the header starts, usually 0. -+ @retval S_OK -+ @retval S_FALSE if there is no header, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT columnHeader -+ ( -+ [out] IAccessibleTable **accessibleTable, -+ [out, retval] long *startingRowIndex -+ ); -+ -+ /** @brief Translates the given cell index into the corresponding column index. -+ @param [in] cellIndex -+ 0 based index of the cell in the parent or closest ancestor table. Typically this -+ is the value returned from IAccessible2::indexInParent, but in the case where the -+ table cells are not direct children of the table this is the cell index specified -+ by the "table-cell-index" object attribute obtained from parsing the attributes -+ string returned by calling IAccessible2::attributes on the cell object. -+ @param [out] columnIndex -+ Returns the 0 based column index of the cell of the specified child or the index of -+ the first column if the child spans multiple columns. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is 0 -+ */ -+ [propget] HRESULT columnIndex -+ ( -+ [in] long cellIndex, -+ [out, retval] long *columnIndex -+ ); -+ -+ /** @brief Returns the total number of columns in table -+ @param [out] columnCount -+ Number of columns in table (including columns outside the current viewport) -+ @retval S_OK -+ */ -+ [propget] HRESULT nColumns -+ ( -+ [out, retval] long *columnCount -+ ); -+ -+ /** @brief Returns the total number of rows in table -+ @param [out] rowCount -+ Number of rows in table (including rows outside the current viewport) -+ @retval S_OK -+ */ -+ [propget] HRESULT nRows -+ ( -+ [out, retval] long *rowCount -+ ); -+ -+ /** @brief Returns the total number of selected cells -+ @param [out] cellCount -+ Number of cells currently selected -+ @retval S_OK -+ */ -+ [propget] HRESULT nSelectedChildren -+ ( -+ [out, retval] long *cellCount -+ ); -+ -+ /** @brief Returns the total number of selected columns -+ @param [out] columnCount -+ Number of columns currently selected -+ @retval S_OK -+ */ -+ [propget] HRESULT nSelectedColumns -+ ( -+ [out, retval] long *columnCount -+ ); -+ -+ /** @brief Returns the total number of selected rows -+ @param [out] rowCount -+ Number of rows currently selected -+ @retval S_OK -+ */ -+ [propget] HRESULT nSelectedRows -+ ( -+ [out, retval] long *rowCount -+ ); -+ -+ /** @brief Returns the description text of the specified row in the table. -+ @param [in] row -+ The 0 based index of the row for which to retrieve the description. -+ @param [out] description -+ Returns the description text of the specified row in the table if such a -+ description exists. Otherwise a NULL pointer is returned. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @retval E_INVALIDARG if bad [in] passed, [out] value is NULL -+ */ -+ [propget] HRESULT rowDescription -+ ( -+ [in] long row, -+ [out, retval] BSTR *description -+ ); -+ -+ /** @brief Returns the number of rows occupied by the accessible object -+ at the specified row and column in the table. -+ -+ The result is greater than 1 if the specified cell spans multiple rows. -+ @param [in] row -+ 0 based row index of the accessible for which to return the row extent. -+ @param [in] column -+ 0 based column index of the accessible for which to return the row extent. -+ @param [out] nRowsSpanned -+ Returns the row extent of the specified cell. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is 0 -+ */ -+ [propget] HRESULT rowExtentAt -+ ( -+ [in] long row, -+ [in] long column, -+ [out, retval] long *nRowsSpanned -+ ); -+ -+ /** @brief Returns the row headers as an %IAccessibleTable object. -+ -+ Content and size of the returned table are implementation dependent. -+ @param [out] accessibleTable -+ The row header. -+ @param [out] startingColumnIndex -+ The 0 based column index where the header starts, usually 0. -+ @retval S_OK -+ @retval S_FALSE if there is no header, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT rowHeader -+ ( -+ [out] IAccessibleTable **accessibleTable, -+ [out, retval] long *startingColumnIndex -+ ); -+ -+ /** @brief Translates the given cell index into a row index. -+ @param [in] cellIndex -+ 0 based index of the cell in the parent or closest ancestor table. Typically this -+ is the value returned from IAccessible2::indexInParent, but in the case where the -+ table cells are not direct children of the table this is the cell index specified -+ by the "table-cell-index" object attribute obtained from parsing the attributes -+ string returned by calling IAccessible2::attributes on the cell object. -+ @param [out] rowIndex -+ 0 based row index -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is 0 -+ */ -+ [propget] HRESULT rowIndex -+ ( -+ [in] long cellIndex, -+ [out, retval] long *rowIndex -+ ); -+ -+ /** @brief Returns a list of cell indexes currently selected (0 based). -+ @param [in] maxChildren -+ This parameter is ignored. Refer to @ref _arrayConsideration -+ "Special Consideration when using Arrays" for more details. -+ @param [out] children -+ An array of cell indexes of selected cells (each index is 0 based), -+ allocated by the server. The client must free it with CoTaskMemFree. -+ @param [out] nChildren -+ The number of cell indexes returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are none, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT selectedChildren -+ ( -+ [in] long maxChildren, -+ [out, size_is(,maxChildren), length_is(,*nChildren)] long **children, -+ [out, retval] long *nChildren -+ ); -+ -+ /** @brief Returns a list of column indexes currently selected (0 based). -+ @param [in] maxColumns -+ This parameter is ignored. Refer to @ref _arrayConsideration -+ "Special Consideration when using Arrays" for more details. -+ @param [out] columns -+ An array of column indexes of selected columns (each index is 0 based), allocated -+ by the server. The client must free it with CoTaskMemFree. -+ @param [out] nColumns -+ The number of column indexes returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are none, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT selectedColumns -+ ( -+ [in] long maxColumns, -+ [out, size_is(,maxColumns), length_is(,*nColumns)] long **columns, -+ [out, retval] long *nColumns -+ ); -+ -+ /** @brief Returns a list of row indexes currently selected (0 based). -+ @param [in] maxRows -+ This parameter is ignored. Refer to @ref _arrayConsideration -+ "Special Consideration when using Arrays" for more details. -+ @param [out] rows -+ An array of row indexes of selected rows (each index is 0 based), allocated -+ by the server. The client must free it with CoTaskMemFree. -+ @param [out] nRows -+ The number of row indexes returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are none, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT selectedRows -+ ( -+ [in] long maxRows, -+ [out, size_is(,maxRows), length_is(,*nRows)] long **rows, -+ [out, retval] long *nRows -+ ); -+ -+ /** @brief Returns the summary description of the table. The returned object could be -+ an IAccessible or an IAccessible2. -+ @param [out] accessible -+ Returns a reference to an implementation dependent accessible object -+ representing the table's summary or a NULL pointer if the table -+ does not support a summary. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT summary -+ ( -+ [out, retval] IUnknown **accessible -+ ); -+ -+ /** @brief Returns a boolean value indicating whether the specified column is -+ completely selected. -+ @param [in] column -+ 0 based index of the column for which to determine whether it is selected. -+ @param [out] isSelected -+ Returns TRUE if the specified column is selected completely and FALSE otherwise. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is FALSE -+ */ -+ [propget] HRESULT isColumnSelected -+ ( -+ [in] long column, -+ [out, retval] boolean *isSelected -+ ); -+ -+ /** @brief Returns a boolean value indicating whether the specified row is completely -+ selected. -+ @param [in] row -+ 0 based index of the row for which to determine whether it is selected. -+ @param [out] isSelected -+ Returns TRUE if the specified row is selected completely and FALSE otherwise. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is FALSE -+ */ -+ [propget] HRESULT isRowSelected -+ ( -+ [in] long row, -+ [out, retval] boolean *isSelected -+ ); -+ -+ /** @brief Returns a boolean value indicating whether the specified cell is selected. -+ @param [in] row -+ 0 based index of the row for the cell to determine whether it is selected. -+ @param [in] column -+ 0 based index of the column for the cell to determine whether it is selected. -+ @param [out] isSelected -+ Returns TRUE if the specified cell is selected and FALSE otherwise. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] value is FALSE -+ */ -+ [propget] HRESULT isSelected -+ ( -+ [in] long row, -+ [in] long column, -+ [out, retval] boolean *isSelected -+ ); -+ -+ /** @brief Selects a row and unselects all previously selected rows. -+ @param [in] row -+ 0 based index of the row to be selected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT selectRow -+ ( -+ [in] long row -+ ); -+ -+ /** @brief Selects a column and unselects all previously selected columns. -+ @param [in] column -+ 0 based index of the column to be selected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT selectColumn -+ ( -+ [in] long column -+ ); -+ -+ /** @brief Unselects one row, leaving other selected rows selected (if any). -+ @param [in] row -+ 0 based index of the row to be unselected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT unselectRow -+ ( -+ [in] long row -+ ); -+ -+ /** @brief Unselects one column, leaving other selected columns selected (if any). -+ @param [in] column -+ 0 based index of the column to be unselected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT unselectColumn -+ ( -+ [in] long column -+ ); -+ -+ /** @brief Given a cell index, gets the row and column indexes and extents of a cell -+ and whether or not it is selected. -+ -+ This is a convenience function. It is not mandatory to implement it. -+ @param [in] index -+ 0 based index of this cell in the table. -+ @param [out] row -+ 0 based row index. -+ @param [out] column -+ 0 based column index. -+ @param [out] rowExtents -+ Number of cells spanned by this cell in this row. -+ @param [out] columnExtents -+ Number of cells spanned by this cell in this column. -+ @param [out] isSelected -+ Indicates if the specified cell is selected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed, [out] values are 0s and FALSE respectively -+ */ -+ [propget] HRESULT rowColumnExtentsAtIndex -+ ( -+ [in] long index, -+ [out] long *row, -+ [out] long *column, -+ [out] long *rowExtents, -+ [out] long *columnExtents, -+ [out, retval] boolean *isSelected -+ ); -+ -+ /** @brief Returns the type and extents describing how a table changed. -+ -+ Provided for use by the IA2_EVENT_TABLE_MODEL_CHANGED event handler. -+ -+ This data is only guaranteed to be valid while the thread notifying the event -+ continues. Once the handler has returned, the validity of the data depends on -+ how the server manages the life cycle of its objects. Also, note that the server -+ may have different life cycle management strategies for controls depending on -+ whether or not a control manages its children. Lists, trees, and tables can have -+ a large number of children and thus it's possible that the child objects for those -+ controls would only be created as needed. Servers should document their life cycle -+ strategy as this will be of interest to assistive technology or script engines -+ accessing data out of process or from other threads. Servers only need to save the -+ most recent row and column values associated with the change and a scope of the -+ entire application is adequate. -+ -+ @param [out] modelChange -+ A struct of (type(insert, delete, update), firstRow, lastRow, firstColumn, lastColumn). -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT modelChange -+ ( -+ [out, retval] IA2TableModelChange *modelChange -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleTable2.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2012 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface gives access to a two-dimensional table. -+ -+ Please also refer to the IAccessibleTableCell interface. -+ -+ If you want to support older applications you should also support the -+ IAccessibleTable inteface. -+*/ -+[object, uuid(6167f295-06f0-4cdd-a1fa-02e25153d869)] -+interface IAccessibleTable2 : IUnknown -+{ -+ -+ /** @brief Returns the accessible object at the specified row and column in -+ the table. This object could be an IAccessible or an IAccessible2. -+ @param [in] row -+ The 0 based row index for which to retrieve the cell. -+ @param [in] column -+ The 0 based column index for which to retrieve the cell. -+ @param [out] cell -+ If both row and column index are valid then the corresponding accessible -+ object is returned that represents the requested cell regardless of whether -+ the cell is currently visible (on the screen). -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT cellAt -+ ( -+ [in] long row, -+ [in] long column, -+ [out, retval] IUnknown **cell -+ ); -+ -+ /** @brief Returns the caption for the table. The returned object could be -+ an IAccessible or an IAccessible2. -+ @param [out] accessible -+ If the table has a caption then a reference to it is returned, else a NULL -+ pointer is returned. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @deprecated use a describedBy relation -+ */ -+ [propget] HRESULT caption -+ ( -+ [out, retval] IUnknown **accessible -+ ); -+ -+ /** @brief Returns the description text of the specified column in the table. -+ @param [in] column -+ The 0 based index of the column for which to retrieve the description. -+ @param [out] description -+ Returns the description text of the specified column in the table if such a -+ description exists. Otherwise a NULL pointer is returned. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT columnDescription -+ ( -+ [in] long column, -+ [out, retval] BSTR *description -+ ); -+ -+ -+ /** @brief Returns the total number of columns in table -+ @param [out] columnCount -+ Number of columns in table (including columns outside the current viewport) -+ @retval S_OK -+ */ -+ [propget] HRESULT nColumns -+ ( -+ [out, retval] long *columnCount -+ ); -+ -+ /** @brief Returns the total number of rows in table -+ @param [out] rowCount -+ Number of rows in table (including rows outside the current viewport) -+ @retval S_OK -+ */ -+ [propget] HRESULT nRows -+ ( -+ [out, retval] long *rowCount -+ ); -+ -+ /** @brief Returns the total number of selected cells -+ @param [out] cellCount -+ Number of cells currently selected -+ @retval S_OK -+ */ -+ [propget] HRESULT nSelectedCells -+ ( -+ [out, retval] long *cellCount -+ ); -+ -+ /** @brief Returns the total number of selected columns -+ @param [out] columnCount -+ Number of columns currently selected -+ @retval S_OK -+ */ -+ [propget] HRESULT nSelectedColumns -+ ( -+ [out, retval] long *columnCount -+ ); -+ -+ /** @brief Returns the total number of selected rows -+ @param [out] rowCount -+ Number of rows currently selected -+ @retval S_OK -+ */ -+ [propget] HRESULT nSelectedRows -+ ( -+ [out, retval] long *rowCount -+ ); -+ -+ /** @brief Returns the description text of the specified row in the table. -+ @param [in] row -+ The 0 based index of the row for which to retrieve the description. -+ @param [out] description -+ Returns the description text of the specified row in the table if such a -+ description exists. Otherwise a NULL pointer is returned. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT rowDescription -+ ( -+ [in] long row, -+ [out, retval] BSTR *description -+ ); -+ -+ /** @brief Returns a list of accessibles currently selected. -+ @param [out] cells -+ Pointer to an array of references to selected accessibles. The array is -+ allocated by the server with CoTaskMemAlloc and freed by the client with -+ CoTaskMemFree. -+ @param [out] nSelectedCells -+ The number of accessibles returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are none, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT selectedCells -+ ( -+ [out, size_is(,*nSelectedCells)] IUnknown ***cells, -+ [out, retval] long *nSelectedCells -+ ); -+ -+ /** @brief Returns a list of column indexes currently selected (0 based). -+ @param [out] selectedColumns -+ A pointer to an array of column indexes of selected columns (each index is -+ 0 based). The array is allocated by the server with CoTaskMemAlloc and -+ freed by the client with CoTaskMemFree. -+ @param [out] nColumns -+ The number of column indexes returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are none, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT selectedColumns -+ ( -+ [out, size_is(,*nColumns)] long **selectedColumns, -+ [out, retval] long *nColumns -+ ); -+ -+ /** @brief Returns a list of row indexes currently selected (0 based). -+ @param [out] selectedRows -+ An array of row indexes of selected rows (each index is 0 based). The array -+ is allocated by the server with CoTaskMemAlloc and freed by the client with -+ CoTaskMemFree. -+ @param [out] nRows -+ The number of row indexes returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there are none, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT selectedRows -+ ( -+ [out, size_is(,*nRows)] long **selectedRows, -+ [out, retval] long *nRows -+ ); -+ -+ /** @brief Returns the summary description of the table. The returned object could be -+ an IAccessible or an IAccessible2. -+ @param [out] accessible -+ Returns a reference to an implementation dependent accessible object -+ representing the table's summary or a NULL pointer if the table -+ does not support a summary. -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ @deprecated Use the labeledBy relation -+ */ -+ [propget] HRESULT summary -+ ( -+ [out, retval] IUnknown **accessible -+ ); -+ -+ /** @brief Returns a boolean value indicating whether the specified column is -+ completely selected. -+ @param [in] column -+ 0 based index of the column for which to determine whether it is selected. -+ @param [out] isSelected -+ Returns TRUE if the specified column is selected completely and FALSE otherwise. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT isColumnSelected -+ ( -+ [in] long column, -+ [out, retval] boolean *isSelected -+ ); -+ -+ /** @brief Returns a boolean value indicating whether the specified row is completely -+ selected. -+ @param [in] row -+ 0 based index of the row for which to determine whether it is selected. -+ @param [out] isSelected -+ Returns TRUE if the specified row is selected completely and FALSE otherwise. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ [propget] HRESULT isRowSelected -+ ( -+ [in] long row, -+ [out, retval] boolean *isSelected -+ ); -+ -+ /** @brief Selects a row and unselects all previously selected rows. -+ -+ The behavior should mimic that of the application, but for those applications -+ which do not have a means in the GUI to select a full row of cells the behavior -+ should be as follows: First any selected rows in the table are unselected. Then -+ the entire row of cells for the specified row is selected. If any of the -+ cells in the selected row span additional rows, the cells in those rows -+ are also selected. -+ @param [in] row -+ 0 based index of the row to be selected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT selectRow -+ ( -+ [in] long row -+ ); -+ -+ /** @brief Selects a column and unselects all previously selected columns. -+ -+ The behavior should mimic that of the application, but for those applications -+ which do not have a means in the GUI to select a full column of cells the behavior -+ should be as follows: First any selected columns in the table are unselected. Then -+ the entire column of cells for the specified column is selected. If any of the -+ cells in the selected column span additional columns, the cells in those columns -+ are also selected. -+ @param [in] column -+ 0 based index of the column to be selected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT selectColumn -+ ( -+ [in] long column -+ ); -+ -+ /** @brief Unselects one row, leaving other selected rows selected (if any). -+ -+ The behavior should mimic that of the application, but for those applications -+ which do not have a means in the GUI to unselect a full row of cells the -+ behavior should be as follows: The entire row of cells for the specified -+ row is unselected. If any of the cells in the selected row span additional -+ rows, the cells in those rows are also unselected. -+ @param [in] row -+ 0 based index of the row to be unselected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT unselectRow -+ ( -+ [in] long row -+ ); -+ -+ /** @brief Unselects one column, leaving other selected columns selected (if any). -+ -+ The behavior should mimic that of the application, but for those applications -+ which do not have a means in the GUI to unselect a full column of cells the -+ behavior should be as follows: The entire column of cells for the specified -+ column is unselected. If any of the cells in the selected column span additional -+ columns, the cells in those columns are also unselected. -+ @param [in] column -+ 0 based index of the column to be unselected. -+ @retval S_OK -+ @retval E_INVALIDARG if bad [in] passed -+ */ -+ HRESULT unselectColumn -+ ( -+ [in] long column -+ ); -+ -+ /** @brief Returns the type and extents describing how a table changed. -+ -+ Provided for use by the IA2_EVENT_TABLE_MODEL_CHANGED event handler. -+ -+ This data is only guaranteed to be valid while the thread notifying the event -+ continues. Once the handler has returned, the validity of the data depends on -+ how the server manages the life cycle of its objects. Also, note that the server -+ may have different life cycle management strategies for controls depending on -+ whether or not a control manages its children. Lists, trees, and tables can have -+ a large number of children and thus it's possible that the child objects for those -+ controls would only be created as needed. Servers should document their life cycle -+ strategy as this will be of interest to assistive technology or script engines -+ accessing data out of process or from other threads. Servers only need to save the -+ most recent row and column values associated with the change and a scope of the -+ entire application is adequate. -+ -+ @param [out] modelChange -+ A struct of (type(insert, delete, update), firstRow, lastRow, firstColumn, lastColumn). -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT modelChange -+ ( -+ [out, retval] IA2TableModelChange *modelChange -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleTableCell.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2013 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface gives access to the cells of a two-dimensional table. -+ -+ Please also refer to the IAccessibleTable2 interface. -+ -+*/ -+[object, uuid(594116B1-C99F-4847-AD06-0A7A86ECE645)] -+interface IAccessibleTableCell : IUnknown -+{ -+ -+ /** @brief Returns the number of columns occupied by this cell accessible. -+ -+ The result is greater than 1 if the specified cell spans multiple columns. -+ @param [out] nColumnsSpanned -+ Returns the 1 based column extent of the specified cell. -+ @retval S_OK -+ */ -+ [propget] HRESULT columnExtent -+ ( -+ [out, retval] long *nColumnsSpanned -+ ); -+ -+ /** @brief Returns the column headers as an array of cell accessibles. -+ -+ @param [out] cellAccessibles -+ Pointer to an array of references to cell accessibles. The array is allocated -+ by the server. The client must free it with CoTaskMemFree. -+ @param [out] nColumnHeaderCells -+ The number of accessibles returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there is no header, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT columnHeaderCells -+ ( -+ [out, size_is(,*nColumnHeaderCells)] IUnknown ***cellAccessibles, -+ [out, retval] long *nColumnHeaderCells -+ ); -+ -+ /** @brief Translates this cell accessible into the corresponding column index. -+ -+ @param [out] columnIndex -+ Returns the 0 based column index of the cell of the specified cell or the index of -+ the first column if the cell spans multiple columns. -+ @retval S_OK -+ */ -+ [propget] HRESULT columnIndex -+ ( -+ [out, retval] long *columnIndex -+ ); -+ -+ /** @brief Returns the number of rows occupied by this cell accessible. -+ -+ @param [out] nRowsSpanned -+ Returns the row extent of the specified cell. -+ @retval S_OK -+ */ -+ [propget] HRESULT rowExtent -+ ( -+ [out, retval] long *nRowsSpanned -+ ); -+ -+ /** @brief Returns the row headers as an array of cell accessibles. -+ -+ @param [out] cellAccessibles -+ Pointer to an array of references to cell accessibles. The array is allocated -+ by the server. The client must free it with CoTaskMemFree. -+ @param [out] nRowHeaderCells -+ The number of accessibles returned; the size of the returned array. -+ @retval S_OK -+ @retval S_FALSE if there is no header, [out] values are NULL and 0 respectively -+ */ -+ [propget] HRESULT rowHeaderCells -+ ( -+ [out, size_is(,*nRowHeaderCells)] IUnknown ***cellAccessibles, -+ [out, retval] long *nRowHeaderCells -+ ); -+ -+ /** @brief Translates this cell accessible into the corresponding row index. -+ -+ @param [out] rowIndex -+ Returns the 0 based row index of the specified cell or the index of -+ the first row if the cell spans multiple rows. -+ @retval S_OK -+ */ -+ [propget] HRESULT rowIndex -+ ( -+ [out, retval] long *rowIndex -+ ); -+ -+ /** @brief Returns a boolean value indicating whether this cell is selected. -+ -+ @param [out] isSelected -+ Returns TRUE if the specified cell is selected and FALSE otherwise. -+ @retval S_OK -+ */ -+ [propget] HRESULT isSelected -+ ( -+ [out, retval] boolean *isSelected -+ ); -+ -+ /** @brief Gets the row and column indexes and extents of this cell accessible -+ and whether or not it is selected. -+ -+ This is a convenience function. It is not mandatory to implement it. -+ @param [out] row -+ 0 based row index. -+ @param [out] column -+ 0 based column index. -+ @param [out] rowExtents -+ Number of cells spanned by this cell in this row. -+ @param [out] columnExtents -+ Number of cells spanned by this cell in this column. -+ @param [out] isSelected -+ Indicates if the specified cell is selected. -+ @retval S_OK -+ */ -+ [propget] HRESULT rowColumnExtents -+ ( -+ [out] long *row, -+ [out] long *column, -+ [out] long *rowExtents, -+ [out] long *columnExtents, -+ [out, retval] boolean *isSelected -+ ); -+ -+ /** @brief Returns a reference to the accessbile of the containing table. -+ -+ @param [out] table -+ Returns a reference to the IUnknown of the containing table. -+ @retval S_OK -+ */ -+ [propget] HRESULT table -+ ( -+ [out, retval] IUnknown **table -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleImage.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface represents images and icons. -+ -+ This interface is used for a representation of images like icons on buttons. -+ %IAccessibleImage only needs to be implemented in certain situations. Some -+ examples are: -+
    -+
  1. The accessible name and description are not enough to fully -+ describe the image, e.g. when the accessible description is used to define the -+ behavior of an actionable image and the image itself conveys semantically -+ significant information. -+
  2. The user can edit the content that includes an -+ image and therefore the user needs to be able to review the image's position. -+
-+*/ -+[object, uuid(FE5ABB3D-615E-4f7b-909F-5F0EDA9E8DDE)] -+interface IAccessibleImage : IUnknown -+{ -+ /** @brief Returns the localized description of the image. -+ @param [out] description -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT description -+ ( -+ [out, retval] BSTR *description -+ ); -+ -+ /** @brief Returns the coordinates of the image. -+ @param [in] coordinateType -+ Specifies whether the returned coordinates should be relative to the screen or the parent object. -+ @param [out] x -+ @param [out] y -+ @retval S_OK -+ */ -+ [propget] HRESULT imagePosition -+ ( -+ [in] enum IA2CoordinateType coordinateType, -+ [out] long *x, -+ [out, retval] long *y -+ ); -+ -+ /** @brief Returns the size of the image in units specified by parent's coordinate system. -+ @param [out] height -+ @param [out] width -+ @retval S_OK -+ */ -+ -+ [propget] HRESULT imageSize -+ ( -+ [out] long *height, -+ [out, retval] long *width -+ ); -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleEventID.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** %IAccessible2 specific event constants -+ -+ This enum defines the event IDs fired by %IAccessible2 objects. The event IDs -+ are in addition to those used by MSAA. -+*/ -+enum IA2EventID { -+ -+ /** The change of the number or attributes of actions of an accessible -+ object is signaled by events of this type. -+ */ -+ IA2_EVENT_ACTION_CHANGED = 0x101, -+ -+ /** Deprecated. The active descendant of a component has changed. -+ -+ Note: This event constant is misspelled and thus is deprecated and will be -+ removed in a later version. Please use the correctly spelled version which -+ follows. -+ */ -+ IA2_EVENT_ACTIVE_DECENDENT_CHANGED, -+ -+ /** The active descendant of a component has changed. The active descendant -+ is used in objects with transient children. -+ -+ Note: Due to the fact that MSAA's WinEvents don't allow the active child index -+ to be passed on the IA2_EVENT_ACTIVE_DESCENDANT_CHANGED event the manages -+ descendants scheme can't be used. Instead the active child object has to fire -+ MSAA's EVENT_OBJECT_FOCUS. In a future release a new event mechanism may be -+ added to provide for event specific data to be passed with the event. At that -+ time the IA2_EVENT_ACTIVE_DECENDENT_CHANGED event and -+ IA2_STATE_MANAGES_DESCENDANTS state would be useful. -+ */ -+ IA2_EVENT_ACTIVE_DESCENDANT_CHANGED = IA2_EVENT_ACTIVE_DECENDENT_CHANGED, -+ -+ /** The document wide attributes of the document object have changed. -+ */ -+ IA2_EVENT_DOCUMENT_ATTRIBUTE_CHANGED, -+ -+ /** The contents of the document have changed. -+ */ -+ IA2_EVENT_DOCUMENT_CONTENT_CHANGED, -+ -+ /** The loading of the document has completed. -+ */ -+ IA2_EVENT_DOCUMENT_LOAD_COMPLETE, -+ -+ /** The loading of the document was interrupted. -+ */ -+ IA2_EVENT_DOCUMENT_LOAD_STOPPED, -+ -+ /** The document contents are being reloaded. -+ */ -+ IA2_EVENT_DOCUMENT_RELOAD, -+ -+ /** The ending index of this link within the containing string has changed. -+ */ -+ IA2_EVENT_HYPERLINK_END_INDEX_CHANGED, -+ -+ /** The number of anchors associated with this hyperlink object has changed. -+ */ -+ IA2_EVENT_HYPERLINK_NUMBER_OF_ANCHORS_CHANGED, -+ -+ /** The hyperlink selected state changed from selected to unselected or -+ from unselected to selected. -+ */ -+ IA2_EVENT_HYPERLINK_SELECTED_LINK_CHANGED, -+ -+ /** One of the links associated with the hypertext object has been activated. -+ */ -+ IA2_EVENT_HYPERTEXT_LINK_ACTIVATED, -+ -+ /** One of the links associated with the hypertext object has been selected. -+ */ -+ IA2_EVENT_HYPERTEXT_LINK_SELECTED, -+ -+ /** The starting index of this link within the containing string has changed. -+ */ -+ IA2_EVENT_HYPERLINK_START_INDEX_CHANGED, -+ -+ /** Focus has changed from one hypertext object to another, or focus moved -+ from a non-hypertext object to a hypertext object, or focus moved from a -+ hypertext object to a non-hypertext object. -+ */ -+ IA2_EVENT_HYPERTEXT_CHANGED, -+ -+ /** The number of hyperlinks associated with a hypertext object changed -+ */ -+ IA2_EVENT_HYPERTEXT_NLINKS_CHANGED, -+ -+ /** An object's attributes changed. -+ Also see ::IA2_EVENT_TEXT_ATTRIBUTE_CHANGED. -+ */ -+ IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED, -+ -+ /** A slide changed in a presentation document or a page boundary was -+ crossed in a word processing document. -+ */ -+ IA2_EVENT_PAGE_CHANGED, -+ -+ /** The caret moved from one section to the next. -+ */ -+ IA2_EVENT_SECTION_CHANGED, -+ -+ /** A table caption changed. -+ */ -+ IA2_EVENT_TABLE_CAPTION_CHANGED, -+ -+ /** A table's column description changed. -+ */ -+ IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED, -+ -+ /** A table's column header changed. -+ */ -+ IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED, -+ -+ /** A table's data changed. -+ */ -+ IA2_EVENT_TABLE_MODEL_CHANGED, -+ -+ /** A table's row description changed. -+ */ -+ IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED, -+ -+ /** A table's row header changed. -+ */ -+ IA2_EVENT_TABLE_ROW_HEADER_CHANGED, -+ -+ /** A table's summary changed. -+ */ -+ IA2_EVENT_TABLE_SUMMARY_CHANGED, -+ -+ /** A text object's attributes changed. -+ Also see ::IA2_EVENT_OBJECT_ATTRIBUTE_CHANGED. -+ */ -+ IA2_EVENT_TEXT_ATTRIBUTE_CHANGED, -+ -+ /** The caret has moved to a new position. -+ */ -+ IA2_EVENT_TEXT_CARET_MOVED, -+ -+ /** Deprecated. This event is equivalent to ::IA2_EVENT_TEXT_UPDATED. -+ */ -+ IA2_EVENT_TEXT_CHANGED, -+ -+ /** The caret moved from one column to the next. -+ */ -+ IA2_EVENT_TEXT_COLUMN_CHANGED, -+ -+ /** Text was inserted. -+ */ -+ IA2_EVENT_TEXT_INSERTED, -+ -+ /** Text was removed. -+ */ -+ IA2_EVENT_TEXT_REMOVED, -+ -+ /** This event indicates general text changes, i.e. changes to text that are -+ exposed through the IAccessibleText interface. For compatibility with ATK/AT-SPI -+ which does not have an equivalent event, servers can alternatively fire -+ ::IA2_EVENT_TEXT_REMOVED and ::IA2_EVENT_TEXT_INSERTED. -+ */ -+ IA2_EVENT_TEXT_UPDATED, -+ -+ /** The text selection changed. Later versions of Microsoft development environments -+ have an equivalent event identified, EVENT_OBJECT_TEXTSELECTIONCHANGED. Servers -+ should use that if it is available and use IA2_EVENT_TEXT_SELECTION_CHANGED otherwise. -+ Clients should be prepared to respond to either event. -+ -+ */ -+ IA2_EVENT_TEXT_SELECTION_CHANGED, -+ -+ /** A visible data event indicates the change of the visual appearance -+ of an accessible object. This includes for example most of the -+ attributes available via the IAccessibleComponent interface. -+ */ -+ IA2_EVENT_VISIBLE_DATA_CHANGED, -+ -+ /** The role changed. This should only be used if the interfaces supported by the object -+ did not also change. If the interfaces need to change, the object should be destroyed -+ and a new object created. -+ */ -+ IA2_EVENT_ROLE_CHANGED -+}; -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleApplication.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2010 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+ -+/** @brief This interface gives access to the application's name and version information. -+ -+ This interface provides the AT with the information it needs to differentiate -+ this application from other applications, from other versions of this -+ application, or from other versions of this application running on different -+ versions of an accessibility bridge or accessibility toolkit. -+ -+ Servers implementing IAccessible2 should provide access to the %IAccessibleApplication -+ interface via QueryService from any object so that ATs can easily determine specific -+ information about the application such as its name or version. -+*/ -+[object, uuid(D49DED83-5B25-43F4-9B95-93B44595979E)] -+interface IAccessibleApplication : IUnknown -+{ -+ -+ /** @brief Returns the application name. -+ @param [out] name -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT appName -+ ( -+ [out, retval] BSTR *name -+ ); -+ -+ /** @brief Returns the application version. -+ @param [out] version -+ The version string must not contain levels when it is know beforehand that -+ this information will never require a change in a client's behavior. -+ For example, use "3.6.0" rather than "3.6.0.v201005131500". -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT appVersion -+ ( -+ [out, retval] BSTR *version -+ ); -+ -+ /** @brief Returns the toolkit/bridge name. -+ @param [out] name -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT toolkitName -+ ( -+ [out, retval] BSTR *name -+ ); -+ -+ /** @brief Returns the toolkit/bridge version. -+ @param [out] version -+ The version string must not contain levels when it is know beforehand that -+ this information will never require a change in a client's behavior. -+ For example, use "3.6.0" rather than "3.6.0.v201005131500". -+ @retval S_OK -+ @retval S_FALSE if there is nothing to return, [out] value is NULL -+ */ -+ [propget] HRESULT toolkitVersion -+ ( -+ [out, retval] BSTR *version -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (AccessibleDocument.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2013 Linux Foundation -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+/** @brief This interface represents documents. -+ -+ This interface is used for a representation of documents. -+*/ -+[object, uuid(C48C7FCF-4AB5-4056-AFA6-902D6E1D1149)] -+interface IAccessibleDocument : IUnknown -+{ -+ /** @brief Returns the most recently used anchor target within a document. -+ -+ A document's most recently targeted in-page anchor is returned. A typical use -+ of this method is to fetch the anchor target within an HTML document. In this -+ case anchor targets are those which has been defined with the tag. -+ -+ @param [out] accessible -+ @retval S_OK -+ @retval S_FALSE if there are no existing valid anchor targets, [out] value is NULL. -+ */ -+ [propget] HRESULT anchorTarget -+ ( -+ [out, retval] IUnknown **accessible -+ ); -+ -+} -+ -+/************************************************************************* -+ * -+ * File Name (IA2TypeLibrary.idl) -+ * -+ * IAccessible2 IDL Specification -+ * -+ * Copyright (c) 2007, 2012 Linux Foundation -+ * Copyright (c) 2006 IBM Corporation -+ * Copyright (c) 2000, 2006 Sun Microsystems, Inc. -+ * All rights reserved. -+ * -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions and the following disclaimer. -+ * -+ * 2. Redistributions in binary form must reproduce the above -+ * copyright notice, this list of conditions and the following -+ * disclaimer in the documentation and/or other materials -+ * provided with the distribution. -+ * -+ * 3. Neither the name of the Linux Foundation nor the names of its -+ * contributors may be used to endorse or promote products -+ * derived from this software without specific prior written -+ * permission. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ * -+ * This BSD License conforms to the Open Source Initiative "Simplified -+ * BSD License" as published at: -+ * http://www.opensource.org/licenses/bsd-license.php -+ * -+ * IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 -+ * mark may be used in accordance with the Linux Foundation Trademark -+ * Policy to indicate compliance with the IAccessible2 specification. -+ * -+ ************************************************************************/ -+ -+// This is not a standalone file. It is to be appended to the end of the -+// merged IDL file. -+ -+cpp_quote("") -+cpp_quote("// Type Library Definitions") -+cpp_quote("") -+ -+[ -+ uuid(CE3F726E-D1D3-44FE-B995-FF1DB3B48B2B), -+ helpstring("IAccessible2 Type Library"), -+ version(1.3), -+] -+ -+library IAccessible2Lib -+{ -+ importlib ("stdole2.tlb"); -+ interface IAccessible2; -+ interface IAccessible2_2; -+ interface IAccessible2_3; -+ interface IAccessibleAction; -+ interface IAccessibleApplication; -+ interface IAccessibleComponent; -+ interface IAccessibleDocument; -+ interface IAccessibleEditableText; -+ interface IAccessibleHyperlink; -+ interface IAccessibleHypertext; -+ interface IAccessibleHypertext2; -+ interface IAccessibleImage; -+ interface IAccessibleRelation; -+ interface IAccessibleTable; -+ interface IAccessibleTable2; -+ interface IAccessibleTableCell; -+ interface IAccessibleText; -+/* interface IAccessibleText2;*/ -+ interface IAccessibleValue; -+ enum IA2CoordinateType; -+ enum IA2EventID; -+ enum IA2Role; -+ enum IA2ScrollType; -+ enum IA2States; -+ enum IA2TableModelChangeType; -+ enum IA2TextBoundaryType; -+ enum IA2TextSpecialOffsets; -+} -From ea147313669c87ed675cbbccf34832aa30b6713d Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Wed, 28 Jul 2021 13:09:32 -0400 -Subject: [PATCH] uiautomationcore: Begin adding IAccessible2 support. - -Incomplete, but enough to get IAccessible2 applications (I.e chromium) -to start firing EVENT_OBJECT_FOCUS events for all accessible objects. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_client.c | 32 +++++++++++++++++++++++++++++ - dlls/uiautomationcore/uia_event.c | 15 +++++++++++++- - dlls/uiautomationcore/uia_private.h | 3 +++ - 3 files changed, 49 insertions(+), 1 deletion(-) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index 46c72f76ddf..b09a8f46363 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -1737,6 +1737,36 @@ HRESULT create_uia_elem_from_raw_provider(IUIAutomationElement **iface, - return S_OK; - } - -+static void uia_test_iaccessible2(IAccessible *acc, INT child_id) -+{ -+ IServiceProvider *serv_prov; -+ IAccessible2 *acc2; -+ HRESULT hr; -+ HWND parent_win; -+ LONG tmp; -+ -+ hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov); -+ if (FAILED(hr)) -+ return; -+ -+ TRACE("Got IServiceProvider, passed first step.\n"); -+ hr = IServiceProvider_QueryService(serv_prov, &IID_IAccessible, &IID_IAccessible2, (void **)&acc2); -+ if (FAILED(hr)) -+ { -+ IServiceProvider_Release(serv_prov); -+ return; -+ } -+ -+ TRACE("Got IAccessible2 interface, success!\n"); -+ hr = IAccessible2_get_uniqueID(acc2, &tmp); -+ hr = IAccessible2_get_windowHandle(acc2, &parent_win); -+ if (SUCCEEDED(hr)) -+ TRACE("Child_id %d, UniqueID %d, hwnd %p!\n", child_id, tmp, parent_win); -+ -+ IServiceProvider_Release(serv_prov); -+ IAccessible2_Release(acc2); -+} -+ - HRESULT create_uia_elem_from_msaa_acc(IUIAutomationElement **iface, - IAccessible *wrap, INT child_id) - { -@@ -1753,5 +1783,7 @@ HRESULT create_uia_elem_from_msaa_acc(IUIAutomationElement **iface, - V_VT(&uia->child_id) = VT_I4; - V_I4(&uia->child_id) = child_id; - -+ uia_test_iaccessible2(wrap, child_id); -+ - return S_OK; - } -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index fcb0907101c..d31bb5192f3 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -276,6 +276,17 @@ static EVENTID uia_msaa_event_to_uia_event_id(LONG obj_id, LONG event) - return 0; - } - -+/* -+ * Event hook callback for IAccessible2 events. -+ */ -+void CALLBACK uia_evl_ia2_event_proc(HWINEVENTHOOK hWinEventHook, DWORD event, -+ HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, -+ DWORD dwmsEventTime) -+{ -+ TRACE("hook %p, event %d, hwnd %p, obj_id %#x, child_id %#x, tid %#x, time %d\n", -+ hWinEventHook, event, hwnd, idObject, idChild, idEventThread, dwmsEventTime); -+} -+ - /* - * Event hook callback for window creation events. - */ -@@ -419,7 +430,8 @@ static HRESULT uia_event_listener_thread_initialize(struct uia_evl *evl) - EVENT_OBJECT_FOCUS, 0, uia_evl_msaa_obj_focus_proc, 0, 0, WINEVENT_OUTOFCONTEXT); - evl->win_creation_hook = SetWinEventHook(EVENT_OBJECT_CREATE, - EVENT_OBJECT_CREATE, 0, uia_evl_window_create_proc, 0, 0, WINEVENT_OUTOFCONTEXT); -- -+ evl->ia2_event_hook = SetWinEventHook(IA2_EVENT_ACTION_CHANGED, IA2_EVENT_ROLE_CHANGED, 0, uia_evl_ia2_event_proc, -+ 0, 0, WINEVENT_OUTOFCONTEXT); - /* - * Create interface to be passed to providers so that they can signal - * events to active listeners. -@@ -437,6 +449,7 @@ static void uia_event_listener_thread_exit(struct uia_evl *evl) - - UnhookWinEvent(evl->object_focus_hook); - UnhookWinEvent(evl->win_creation_hook); -+ UnhookWinEvent(evl->ia2_event_hook); - - CoDisconnectObject((IUnknown *)evl->evlc_iface, 0); - IUIAEvlConnection_Release(evl->evlc_iface); -diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h -index 2f329206251..513738c42f5 100644 ---- a/dlls/uiautomationcore/uia_private.h -+++ b/dlls/uiautomationcore/uia_private.h -@@ -18,6 +18,8 @@ - - #include "uiautomation.h" - #include "oleacc.h" -+#include "ia2api.h" -+#include "servprov.h" - - #include "wine/list.h" - -@@ -95,6 +97,7 @@ struct uia_evl - - HWINEVENTHOOK win_creation_hook; - HWINEVENTHOOK object_focus_hook; -+ HWINEVENTHOOK ia2_event_hook; - IUIAEvlConnection *evlc_iface; - - struct uia_data *data; -From d06aa06904d809afec1cd3c555cce1845d099430 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Wed, 8 Sep 2021 13:11:21 -0400 -Subject: [PATCH] uiautomationcore: Implement bounding rectangle property ID. - -Implement MSAA mappings and default values for -UIA_BoundingRectanglePropertyId. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_client.c | 88 ++++++++++++++++++++++++++++-- - 1 file changed, 84 insertions(+), 4 deletions(-) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index b09a8f46363..312cac97fe7 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -740,6 +740,24 @@ static INT uia_msaa_role_to_uia_control_type(INT role) - return UIA_ButtonControlTypeId; - } - -+static void uia_create_bounding_rect_variant(double left, double top, -+ double width, double height, VARIANT *arr_out) -+{ -+ SAFEARRAYBOUND sab = { 0 }; -+ LPSAFEARRAY lpsa; -+ -+ sab.cElements = 4; -+ lpsa = SafeArrayCreate(VT_R8, 1, &sab); -+ ((double *)lpsa->pvData)[0] = left; -+ ((double *)lpsa->pvData)[1] = top; -+ ((double *)lpsa->pvData)[2] = width; -+ ((double *)lpsa->pvData)[3] = height; -+ -+ VariantInit(arr_out); -+ V_VT(arr_out) = VT_R8 | VT_ARRAY; -+ V_ARRAY(arr_out) = lpsa; -+} -+ - static void uia_get_default_property_val(PROPERTYID propertyId, VARIANT *retVal) - { - switch (propertyId) -@@ -760,6 +778,10 @@ static void uia_get_default_property_val(PROPERTYID propertyId, VARIANT *retVal) - V_BOOL(retVal) = VARIANT_FALSE; - break; - -+ case UIA_BoundingRectanglePropertyId: -+ uia_create_bounding_rect_variant(0, 0, 0, 0, retVal); -+ break; -+ - default: - FIXME("Unimplemented default value for PropertyId %d!\n", propertyId); - V_VT(retVal) = VT_EMPTY; -@@ -775,7 +797,34 @@ static HRESULT uia_get_uia_elem_prov_property_val(IRawElementProviderSimple *ele - - VariantInit(&res); - *use_default = TRUE; -- hr = IRawElementProviderSimple_GetPropertyValue(elem_prov, propertyId, &res); -+ switch (propertyId) -+ { -+ case UIA_BoundingRectanglePropertyId: -+ { -+ IRawElementProviderFragment *elem_frag; -+ -+ hr = IRawElementProviderSimple_QueryInterface(elem_prov, -+ &IID_IRawElementProviderFragment, (void **)&elem_frag); -+ if (SUCCEEDED(hr)) -+ { -+ struct UiaRect rect; -+ -+ hr = IRawElementProviderFragment_get_BoundingRectangle(elem_frag, &rect); -+ IRawElementProviderFragment_Release(elem_frag); -+ if (SUCCEEDED(hr)) -+ { -+ uia_create_bounding_rect_variant(rect.left, rect.top, rect.width, rect.height, &res); -+ break; -+ } -+ } -+ hr = IRawElementProviderSimple_GetPropertyValue(elem_prov, propertyId, &res); -+ } -+ break; -+ -+ default: -+ hr = IRawElementProviderSimple_GetPropertyValue(elem_prov, propertyId, &res); -+ break; -+ } - - /* VT_EMPTY means this PropertyId is unimplemented/unsupported. */ - if (V_VT(&res) != VT_EMPTY && SUCCEEDED(hr)) -@@ -848,6 +897,20 @@ static HRESULT uia_get_msaa_acc_property_val(IAccessible *acc, - } - break; - -+ case UIA_BoundingRectanglePropertyId: -+ { -+ LONG left, top, width, height; -+ -+ hr = IAccessible_accLocation(acc, &left, &top, &width, &height, child_id); -+ if (SUCCEEDED(hr)) -+ { -+ uia_create_bounding_rect_variant((double)left, (double)top, -+ (double)width, (double)height, retVal); -+ *use_default = FALSE; -+ } -+ } -+ break; -+ - default: - FIXME("UIA PropertyId %d unimplemented for IAccessible!\n", propertyId); - break; -@@ -1284,9 +1347,26 @@ static HRESULT WINAPI uia_elem_get_CurrentItemStatus(IUIAutomationElement *iface - static HRESULT WINAPI uia_elem_get_CurrentBoundingRectangle(IUIAutomationElement *iface, - RECT *retVal) - { -- struct uia_elem_data *This = impl_from_IUIAutomationElement(iface); -- FIXME("%p\n", This); -- return E_NOTIMPL; -+ VARIANT res; -+ HRESULT hr; -+ -+ TRACE("%p %p\n", iface, retVal); -+ -+ memset(retVal, 0, sizeof(*retVal)); -+ hr = IUIAutomationElement_GetCurrentPropertyValue(iface, -+ UIA_BoundingRectanglePropertyId, &res); -+ if (FAILED(hr)) -+ return hr; -+ -+ if (V_VT(&res) == (VT_R8 | VT_ARRAY)) -+ { -+ retVal->left = (LONG)((double *)V_ARRAY(&res)->pvData)[0]; -+ retVal->top = (LONG)((double *)V_ARRAY(&res)->pvData)[1]; -+ retVal->right = retVal->left + (LONG)((double *)V_ARRAY(&res)->pvData)[2]; -+ retVal->bottom = retVal->top + (LONG)((double *)V_ARRAY(&res)->pvData)[3]; -+ } -+ -+ return S_OK; - } - - static HRESULT WINAPI uia_elem_get_CurrentLabeledBy(IUIAutomationElement *iface, -From 6ca562b432aa52fafbcacd1109ec730e1d5a417e Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Wed, 8 Sep 2021 18:04:33 -0400 -Subject: [PATCH] tabtip: Retrieve bounding rectangle for focused element. - -Retrieve the bounding rectangle of the focused accessible object, and -pass this data to the steam OSK link if it's retrieved. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - programs/tabtip/tabtip.c | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c -index 18b8ae32ef8..18c87042658 100644 ---- a/programs/tabtip/tabtip.c -+++ b/programs/tabtip/tabtip.c -@@ -155,12 +155,14 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - WINE_TRACE("This %p, sender %p\n", This, sender); - if (sender) - { -+ RECT rect = { 0 }; - VARIANT var; - INT ct_id; - BSTR name; - - IUIAutomationElement_get_CurrentControlType(sender, &ct_id); - IUIAutomationElement_get_CurrentName(sender, &name); -+ IUIAutomationElement_get_CurrentBoundingRectangle(sender, &rect); - IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); - - if ((last_keyup_event < (GetTickCount() - 5000)) && -@@ -170,7 +172,16 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - { - WINE_TRACE("Keyboard up!\n"); - keyboard_up = TRUE; -- ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); -+ if (rect.left || rect.top || rect.right || rect.bottom) -+ { -+ WCHAR link_buf[1024]; -+ -+ wsprintfW(link_buf, L"steam://open/keyboard?XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", -+ rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); -+ ShellExecuteW(NULL, NULL, link_buf, NULL, NULL, SW_SHOWNOACTIVATE); -+ } -+ else -+ ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); - - last_keyup_event = GetTickCount(); - } -@@ -189,7 +200,8 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - else - ct_id = 0; - -- WINE_TRACE("element name: %s, ct_id %s\n", wine_dbgstr_w(name), ct_id_str[ct_id]); -+ WINE_TRACE("element name: %s, ct_id %s, rect { %d, %d } - { %d, %d }\n", wine_dbgstr_w(name), ct_id_str[ct_id], -+ rect.left, rect.top, rect.right, rect.bottom); - } - - return S_OK; -From 590f393df6e72993f9cfae8de7360514a2b4fd43 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Thu, 9 Sep 2021 14:02:08 -0400 -Subject: [PATCH] tabtip: Only trigger steam OSK link if we're running on Steam - Deck. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - programs/tabtip/tabtip.c | 16 +++++++++++++++- - 1 file changed, 15 insertions(+), 1 deletion(-) - -diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c -index 18c87042658..6938eb3924f 100644 ---- a/programs/tabtip/tabtip.c -+++ b/programs/tabtip/tabtip.c -@@ -55,6 +55,7 @@ typedef struct { - - DWORD last_keyup_event; - BOOL keyboard_up; -+BOOL use_steam_osk; - - static const char *ct_id_str[] = { - "UIA_ButtonControlTypeId (50000)", -@@ -165,7 +166,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - IUIAutomationElement_get_CurrentBoundingRectangle(sender, &rect); - IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); - -- if ((last_keyup_event < (GetTickCount() - 5000)) && -+ if (use_steam_osk && (last_keyup_event < (GetTickCount() - 5000)) && - ct_id == UIA_EditControlTypeId && (V_VT(&var) == VT_BOOL && V_BOOL(&var))) - { - if (!keyboard_up) -@@ -259,6 +260,18 @@ static DWORD WINAPI tabtip_exit_watcher(LPVOID lpParam) - return 0; - } - -+static void tabtip_use_osk_check(void) -+{ -+ const char *var = getenv("SteamDeck"); -+ -+ if (var && !strcmp(var, "1")) -+ use_steam_osk = TRUE; -+ else -+ use_steam_osk = FALSE; -+ -+ WINE_TRACE("use_steam_osk=%d\n", use_steam_osk); -+} -+ - int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) - { - HANDLE wine_exit_event, pgm_exit_event, started_event; -@@ -275,6 +288,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine - wine_exit_event = pgm_exit_event = started_event = NULL; - last_keyup_event = 0; - keyboard_up = FALSE; -+ tabtip_use_osk_check(); - - NtSetInformationProcess( GetCurrentProcess(), ProcessWineMakeProcessSystem, - &wine_exit_event, sizeof(HANDLE *) ); -From 64a7057ed114dfce6135c6471797a59ea7b65d9e Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 23 Aug 2021 10:24:29 -0400 -Subject: [PATCH] uiautomationcore: Added UiaRaiseStructureChangedEvent stub. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/uiautomationcore/uia_main.c | 10 ++++++++++ - dlls/uiautomationcore/uiautomationcore.spec | 2 +- - include/uiautomationcoreapi.h | 2 ++ - 3 files changed, 13 insertions(+), 1 deletion(-) - -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index 952a9d47a0d..c2466aa2697 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -428,6 +428,16 @@ HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple - return S_OK; - } - -+/*********************************************************************** -+ * UiaRaiseStructureChangedEvent (uiautomationcore.@) -+ */ -+HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, -+ int *runtime_id, int runtime_id_len) -+{ -+ FIXME("(%p, %d, %p, %d): stub\n", provider, struct_change_type, runtime_id, runtime_id_len); -+ return S_OK; -+} -+ - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) - { - FIXME("(%p): stub\n", callback); -diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec -index 93d4e130799..15e0d4dd3c7 100644 ---- a/dlls/uiautomationcore/uiautomationcore.spec -+++ b/dlls/uiautomationcore/uiautomationcore.spec -@@ -89,7 +89,7 @@ - @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) - #@ stub UiaRaiseChangesEvent - #@ stub UiaRaiseNotificationEvent --@ stub UiaRaiseStructureChangedEvent -+@ stdcall UiaRaiseStructureChangedEvent(ptr long ptr long) - #@ stub UiaRaiseTextEditTextChangedEvent - @ stdcall UiaRegisterProviderCallback(ptr) - @ stub UiaRemoveEvent -diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h -index 563d5c602bd..0cdf9e4b6bb 100644 ---- a/include/uiautomationcoreapi.h -+++ b/include/uiautomationcoreapi.h -@@ -67,6 +67,8 @@ int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid); - BOOL WINAPI UiaPatternRelease(HUIAPATTERNOBJECT hobj); - HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVENTID id); - HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple *provider, PROPERTYID id, VARIANT old, VARIANT new); -+HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, -+ int *runtime_id, int runtime_id_len); - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); - LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *elprov); - BOOL WINAPI UiaTextRangeRelease(HUIATEXTRANGE hobj); -From 075f6f028e60373fe3df1b246bf441967164b0bd Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 26 Jul 2021 23:18:46 -0400 -Subject: [PATCH] wineboot: HACK: Run tabtip.exe on startup. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - programs/wineboot/wineboot.c | 37 ++++++++++++++++++++++++++++++++++++ - 1 file changed, 37 insertions(+) - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 14d12883813..8c4e253100f 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -1296,6 +1296,40 @@ static BOOL start_services_process(void) - return TRUE; - } - -+static BOOL start_tabtip_process(void) -+{ -+ static const WCHAR tabtip_started_event[] = L"TABTIP_STARTED_EVENT"; -+ PROCESS_INFORMATION pi; -+ STARTUPINFOW si = { sizeof(si) }; -+ HANDLE wait_handles[2]; -+ -+ if (!CreateProcessW(L"C:\\windows\\system32\\tabtip.exe", NULL, -+ NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi)) -+ { -+ WINE_ERR("Couldn't start tabtip.exe: error %u\n", GetLastError()); -+ return FALSE; -+ } -+ CloseHandle(pi.hThread); -+ -+ wait_handles[0] = CreateEventW(NULL, TRUE, FALSE, tabtip_started_event); -+ wait_handles[1] = pi.hProcess; -+ -+ /* wait for the event to become available or the process to exit */ -+ if ((WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE)) == WAIT_OBJECT_0 + 1) -+ { -+ DWORD exit_code; -+ GetExitCodeProcess(pi.hProcess, &exit_code); -+ WINE_ERR("Unexpected termination of tabtip.exe - exit code %d\n", exit_code); -+ CloseHandle(pi.hProcess); -+ CloseHandle(wait_handles[0]); -+ return FALSE; -+ } -+ -+ CloseHandle(pi.hProcess); -+ CloseHandle(wait_handles[0]); -+ return TRUE; -+} -+ - static HANDLE start_rundll32( const WCHAR *inf_path, const WCHAR *install, WORD machine ) - { - WCHAR app[MAX_PATH + ARRAY_SIZE(L"\\rundll32.exe" )]; -@@ -1713,6 +1747,9 @@ int __cdecl main( int argc, char *argv[] ) - { - ProcessRunKeys( HKEY_LOCAL_MACHINE, L"RunServices", FALSE, FALSE ); - start_services_process(); -+ -+ /* FIXME: hack, run tabtip.exe on startup. */ -+ start_tabtip_process(); - } - if (init || update) update_wineprefix( update ); - -From c51eac4533e7ef2b60854d43a90257cc1b14b85f Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Thu, 29 Jul 2021 20:34:33 -0400 -Subject: [PATCH] HACK: setupapi: Make sure dlls are updated in proton wine - prefix. - -Due to Proton's wine prefix containing read-only symlinks to dll files, -install_fake_dll fails to get a valid file handle to write to, which -means register_fake_dll is never called. To get around this, check if we -got a read-only file handle, and if the sizes match, set the handle to -NUL so the write completes and the dll ends up registered. - -Signed-off-by: Connor McAdams -CW-Bug-Id: #18351 ---- - dlls/setupapi/fakedll.c | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/dlls/setupapi/fakedll.c b/dlls/setupapi/fakedll.c -index 1ce15d937eb..a930baf7da8 100644 ---- a/dlls/setupapi/fakedll.c -+++ b/dlls/setupapi/fakedll.c -@@ -503,6 +503,7 @@ static HANDLE create_dest_file( const WCHAR *name, BOOL delete ) - } - else if (!delete) - { -+ if (GetLastError() == ERROR_ACCESS_DENIED) return 0; - if (GetLastError() == ERROR_PATH_NOT_FOUND) create_directories( name ); - - h = CreateFileW( name, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL ); -@@ -512,6 +513,28 @@ static HANDLE create_dest_file( const WCHAR *name, BOOL delete ) - return h; - } - -+static HANDLE check_dest_file_size_match( const WCHAR *name, SIZE_T size ) -+{ -+ HANDLE h = CreateFileW( name, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL ); -+ if (h && h != INVALID_HANDLE_VALUE) -+ { -+ LARGE_INTEGER li; -+ -+ if (GetFileSizeEx(h, &li) && (size == li.QuadPart)) -+ { -+ CloseHandle( h ); -+ h = CreateFileW( L"nul", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL ); -+ } -+ else -+ { -+ ERR( "Incorrect file size for %s, not registering!\n", debugstr_w(name) ); -+ CloseHandle ( h ); -+ h = 0; -+ } -+ } -+ return h; -+} -+ - /* XML parsing code copied from ntdll */ - - typedef struct -@@ -909,6 +932,17 @@ static int install_fake_dll( WCHAR *dest, WCHAR *file, BOOL delete, struct list - { - HANDLE h = create_dest_file( dest, delete ); - -+ /* -+ * In Proton, prefixes contain read-only symlinks to dll's, so there's -+ * no need to copy anything. However, we still want to make sure new -+ * dll's are registered properly. So, check if we seem to have a -+ * matching file by checking if their sizes match, and if we do, -+ * just set the handle to NUL for the write and allow register_fake_dll -+ * to run. -+ */ -+ if (!h && GetLastError() == ERROR_ACCESS_DENIED) -+ h = check_dest_file_size_match( dest, size ); -+ - if (h && h != INVALID_HANDLE_VALUE) - { - TRACE( "%s -> %s\n", debugstr_w(file), debugstr_w(dest) ); -From a8fb837cd58181ff3883709df12280ee69bfe39b Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 11 Oct 2021 20:21:00 -0400 -Subject: [PATCH] uiautomationcore: Add UiaRaiseAsyncContentLoadedEvent stub. - -Signed-off-by: Connor McAdams ---- - dlls/uiautomationcore/uia_main.c | 11 +++++++++++ - dlls/uiautomationcore/uiautomationcore.spec | 2 +- - include/uiautomationcoreapi.h | 8 ++++++++ - 3 files changed, 20 insertions(+), 1 deletion(-) - -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index c2466aa2697..ca5b0062080 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -438,6 +438,17 @@ HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider - return S_OK; - } - -+/*********************************************************************** -+ * UiaRaiseAsyncContentLoadedEvent (uiautomationcore.@) -+ */ -+HRESULT WINAPI UiaRaiseAsyncContentLoadedEvent(IRawElementProviderSimple *provider, -+ enum AsyncContentLoadedState async_content_loaded_state, -+ double percent_complete) -+{ -+ FIXME("(%p, %d, %f): stub\n", provider, async_content_loaded_state, percent_complete); -+ return S_OK; -+} -+ - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) - { - FIXME("(%p): stub\n", callback); -diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec -index 15e0d4dd3c7..161c4f6a734 100644 ---- a/dlls/uiautomationcore/uiautomationcore.spec -+++ b/dlls/uiautomationcore/uiautomationcore.spec -@@ -84,7 +84,7 @@ - @ stub UiaPatternRelease - #@ stub UiaProviderForNonClient - #@ stub UiaProviderFromIAccessible --@ stub UiaRaiseAsyncContentLoadedEvent -+@ stdcall UiaRaiseAsyncContentLoadedEvent(ptr long double) - @ stdcall UiaRaiseAutomationEvent(ptr long) - @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) - #@ stub UiaRaiseChangesEvent -diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h -index 0cdf9e4b6bb..8f5ebe91ea9 100644 ---- a/include/uiautomationcoreapi.h -+++ b/include/uiautomationcoreapi.h -@@ -59,6 +59,12 @@ enum ProviderType - ProviderType_NonClientArea, - }; - -+enum AsyncContentLoadedState { -+ AsyncContentLoadedState_Beginning, -+ AsyncContentLoadedState_Progress, -+ AsyncContentLoadedState_Completed, -+}; -+ - typedef SAFEARRAY * WINAPI UiaProviderCallback(HWND hwnd,enum ProviderType providerType); - - HRESULT WINAPI UiaGetReservedMixedAttributeValue(IUnknown **value); -@@ -67,6 +73,8 @@ int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid); - BOOL WINAPI UiaPatternRelease(HUIAPATTERNOBJECT hobj); - HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVENTID id); - HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple *provider, PROPERTYID id, VARIANT old, VARIANT new); -+HRESULT WINAPI UiaRaiseAsyncContentLoadedEvent(IRawElementProviderSimple *provider, -+ enum AsyncContentLoadedState async_content_loaded_state, double percent_complete); - HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, - int *runtime_id, int runtime_id_len); - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); -From 7f6ca308619f76d3b84a7526a7b924a198a43f1e Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 11 Oct 2021 20:26:30 -0400 -Subject: [PATCH] uiautomationcore: Add UiaRaiseTextEditTextChangedEvent stub. - -Signed-off-by: Connor McAdams ---- - dlls/uiautomationcore/uia_main.c | 10 ++++++++++ - dlls/uiautomationcore/uiautomationcore.spec | 2 +- - include/uiautomationcoreapi.h | 2 ++ - 3 files changed, 13 insertions(+), 1 deletion(-) - -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index ca5b0062080..384191d5350 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -449,6 +449,16 @@ HRESULT WINAPI UiaRaiseAsyncContentLoadedEvent(IRawElementProviderSimple *provid - return S_OK; - } - -+/*********************************************************************** -+ * UiaRaiseTextEditTextChangedEvent (uiautomationcore.@) -+ */ -+HRESULT WINAPI UiaRaiseTextEditTextChangedEvent(IRawElementProviderSimple *provider, -+ enum TextEditChangeType text_edit_change_type, SAFEARRAY *changed_data) -+{ -+ FIXME("(%p, %d, %p): stub\n", provider, text_edit_change_type, changed_data); -+ return S_OK; -+} -+ - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) - { - FIXME("(%p): stub\n", callback); -diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec -index 161c4f6a734..ef7195a5bf1 100644 ---- a/dlls/uiautomationcore/uiautomationcore.spec -+++ b/dlls/uiautomationcore/uiautomationcore.spec -@@ -90,7 +90,7 @@ - #@ stub UiaRaiseChangesEvent - #@ stub UiaRaiseNotificationEvent - @ stdcall UiaRaiseStructureChangedEvent(ptr long ptr long) --#@ stub UiaRaiseTextEditTextChangedEvent -+@ stdcall UiaRaiseTextEditTextChangedEvent(ptr long ptr) - @ stdcall UiaRegisterProviderCallback(ptr) - @ stub UiaRemoveEvent - @ stdcall UiaReturnRawElementProvider(long long long ptr) -diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h -index 8f5ebe91ea9..e74f37a125e 100644 ---- a/include/uiautomationcoreapi.h -+++ b/include/uiautomationcoreapi.h -@@ -75,6 +75,8 @@ HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVEN - HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple *provider, PROPERTYID id, VARIANT old, VARIANT new); - HRESULT WINAPI UiaRaiseAsyncContentLoadedEvent(IRawElementProviderSimple *provider, - enum AsyncContentLoadedState async_content_loaded_state, double percent_complete); -+HRESULT WINAPI UiaRaiseTextEditTextChangedEvent(IRawElementProviderSimple *provider, enum TextEditChangeType text_edit_change_type, -+ SAFEARRAY *changed_data); - HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, - int *runtime_id, int runtime_id_len); - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); -From 75b41c07a758de023a97a17334ea500e9bfcd830 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 11 Oct 2021 20:30:28 -0400 -Subject: [PATCH] uiautomationcore: Add UiaRaiseNotificationEvent stub. - -Signed-off-by: Connor McAdams ---- - dlls/uiautomationcore/uia_main.c | 12 ++++++++++++ - dlls/uiautomationcore/uiautomationcore.spec | 2 +- - include/uiautomationcore.idl | 16 ++++++++++++++++ - include/uiautomationcoreapi.h | 2 ++ - 4 files changed, 31 insertions(+), 1 deletion(-) - -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index 384191d5350..750e7d19372 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -459,6 +459,18 @@ HRESULT WINAPI UiaRaiseTextEditTextChangedEvent(IRawElementProviderSimple *provi - return S_OK; - } - -+/*********************************************************************** -+ * UiaRaiseNotificationEvent (uiautomationcore.@) -+ */ -+HRESULT WINAPI UiaRaiseNotificationEvent(IRawElementProviderSimple *provider, -+ enum NotificationKind notification_kind, enum NotificationProcessing notification_processing, -+ BSTR display_str, BSTR activity_id) -+{ -+ FIXME("(%p, %d, %d, %s, %s): stub\n", provider, notification_kind, notification_processing, -+ debugstr_w(display_str), debugstr_w(activity_id)); -+ return S_OK; -+} -+ - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) - { - FIXME("(%p): stub\n", callback); -diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec -index ef7195a5bf1..52c09926fb1 100644 ---- a/dlls/uiautomationcore/uiautomationcore.spec -+++ b/dlls/uiautomationcore/uiautomationcore.spec -@@ -88,7 +88,7 @@ - @ stdcall UiaRaiseAutomationEvent(ptr long) - @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) - #@ stub UiaRaiseChangesEvent --#@ stub UiaRaiseNotificationEvent -+@ stdcall UiaRaiseNotificationEvent(ptr long long wstr wstr) - @ stdcall UiaRaiseStructureChangedEvent(ptr long ptr long) - @ stdcall UiaRaiseTextEditTextChangedEvent(ptr long ptr) - @ stdcall UiaRegisterProviderCallback(ptr) -diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl -index 7d33bde45a4..32c80ec8d5f 100644 ---- a/include/uiautomationcore.idl -+++ b/include/uiautomationcore.idl -@@ -152,6 +152,22 @@ enum ZoomUnit { - ZoomUnit_SmallIncrement = 0x0004, - }; - -+enum NotificationProcessing { -+ NotificationProcessing_ImportantAll = 0x0000, -+ NotificationProcessing_ImportantMostRecent = 0x0001, -+ NotificationProcessing_All = 0x0002, -+ NotificationProcessing_MostRecent = 0x0003, -+ NotificationProcessing_CurrentThenMostRecent = 0x0004, -+}; -+ -+enum NotificationKind { -+ NotificationKind_ItemAdded = 0x0000, -+ NotificationKind_ItemRemoved = 0x0001, -+ NotificationKind_ActionCompleted = 0x0002, -+ NotificationKind_ActionAborted = 0x0003, -+ NotificationKind_Other = 0x0004, -+}; -+ - typedef int PROPERTYID; - typedef int PATTERNID; - typedef int EVENTID; -diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h -index e74f37a125e..9c1a7ffa3d5 100644 ---- a/include/uiautomationcoreapi.h -+++ b/include/uiautomationcoreapi.h -@@ -79,6 +79,8 @@ HRESULT WINAPI UiaRaiseTextEditTextChangedEvent(IRawElementProviderSimple *provi - SAFEARRAY *changed_data); - HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider, enum StructureChangeType struct_change_type, - int *runtime_id, int runtime_id_len); -+HRESULT WINAPI UiaRaiseNotificationEvent(IRawElementProviderSimple *provider, enum NotificationKind notification_kind, -+ enum NotificationProcessing notification_processing, BSTR display_str, BSTR activity_id); - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); - LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *elprov); - BOOL WINAPI UiaTextRangeRelease(HUIATEXTRANGE hobj); -From ba9c0676b8c3139b99840713e8daf234afdb9fec Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 11 Oct 2021 20:35:28 -0400 -Subject: [PATCH] uiautomationcore: Add UiaRaiseChangesEvent stub. - -Signed-off-by: Connor McAdams ---- - dlls/uiautomationcore/uia_main.c | 10 ++++++++++ - dlls/uiautomationcore/uiautomationcore.spec | 2 +- - include/uiautomationcoreapi.h | 1 + - 3 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c -index 750e7d19372..2eccd77eb71 100644 ---- a/dlls/uiautomationcore/uia_main.c -+++ b/dlls/uiautomationcore/uia_main.c -@@ -471,6 +471,16 @@ HRESULT WINAPI UiaRaiseNotificationEvent(IRawElementProviderSimple *provider, - return S_OK; - } - -+/*********************************************************************** -+ * UiaRaiseChangesEvent (uiautomationcore.@) -+ */ -+HRESULT WINAPI UiaRaiseChangesEvent(IRawElementProviderSimple *provider, int event_id_count, -+ struct UiaChangeInfo *uia_changes) -+{ -+ FIXME("(%p, %d, %p): stub\n", provider, event_id_count, uia_changes); -+ return S_OK; -+} -+ - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) - { - FIXME("(%p): stub\n", callback); -diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec -index 52c09926fb1..084c9e9f144 100644 ---- a/dlls/uiautomationcore/uiautomationcore.spec -+++ b/dlls/uiautomationcore/uiautomationcore.spec -@@ -87,7 +87,7 @@ - @ stdcall UiaRaiseAsyncContentLoadedEvent(ptr long double) - @ stdcall UiaRaiseAutomationEvent(ptr long) - @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) --#@ stub UiaRaiseChangesEvent -+@ stdcall UiaRaiseChangesEvent(ptr long ptr) - @ stdcall UiaRaiseNotificationEvent(ptr long long wstr wstr) - @ stdcall UiaRaiseStructureChangedEvent(ptr long ptr long) - @ stdcall UiaRaiseTextEditTextChangedEvent(ptr long ptr) -diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h -index 9c1a7ffa3d5..c8e77e9cc9f 100644 ---- a/include/uiautomationcoreapi.h -+++ b/include/uiautomationcoreapi.h -@@ -81,6 +81,7 @@ HRESULT WINAPI UiaRaiseStructureChangedEvent(IRawElementProviderSimple *provider - int *runtime_id, int runtime_id_len); - HRESULT WINAPI UiaRaiseNotificationEvent(IRawElementProviderSimple *provider, enum NotificationKind notification_kind, - enum NotificationProcessing notification_processing, BSTR display_str, BSTR activity_id); -+HRESULT WINAPI UiaRaiseChangesEvent(IRawElementProviderSimple *provider, int event_id_count, struct UiaChangeInfo *uia_changes); - void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); - LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *elprov); - BOOL WINAPI UiaTextRangeRelease(HUIATEXTRANGE hobj); -From b8a175ff4bc65ff494df415e4bbf11ca661dc3e9 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Thu, 4 Nov 2021 11:00:56 -0400 -Subject: [PATCH] HACK: user32: Handle OBJID_QUERYCLASSNAMEIDX for user32 edit - control. - -Due to Wine's implementation of RealGetWindowClass being broken for -subclassed controls, we'll need to respond to OBJID_QUERYCLASSNAMEIDX to -know that we have an edit control. - -Signed-off-by: Connor McAdams - -CW-Bug-Id: #18351 ---- - dlls/user32/edit.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dlls/user32/edit.c b/dlls/user32/edit.c -index 73885566d3b..b5da20f8b73 100644 ---- a/dlls/user32/edit.c -+++ b/dlls/user32/edit.c -@@ -5231,6 +5231,12 @@ LRESULT EditWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, B - } - break; - -+ case WM_GETOBJECT: -+ if (lParam == (DWORD)OBJID_QUERYCLASSNAMEIDX) -+ result = 0x10004; -+ -+ break; -+ - default: - result = DefWindowProcT(hwnd, msg, wParam, lParam, unicode); - break; -From 8362d1581f6622e7db518fa982b95bb55317242a Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Thu, 4 Nov 2021 11:54:50 -0400 -Subject: [PATCH] tabtip: Close keyboard upon focus loss. - -Call new "steam://close/keyboard" link upon edit control focus loss, to -make sure keyboard is closed. - -Signed-off-by: Connor McAdams - -CW-Bug-Id: #18351 ---- - programs/tabtip/tabtip.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c -index 6938eb3924f..2bb554a4694 100644 ---- a/programs/tabtip/tabtip.c -+++ b/programs/tabtip/tabtip.c -@@ -192,6 +192,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - if (keyboard_up) - { - WINE_TRACE("Keyboard down!\n"); -+ ShellExecuteW(NULL, NULL, L"steam://close/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); - keyboard_up = FALSE; - } - } -From a2b52ab831cb8a1e0089e6fc36cc02b403444ddc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 30 Nov 2021 09:29:21 +0100 -Subject: [PATCH] tabtip: Set started event before creating a window. - -CW-Bug-Id: #18351 -CW-Bug-Id: #19584 ---- - programs/tabtip/tabtip.c | 30 +++++++++++++++--------------- - 1 file changed, 15 insertions(+), 15 deletions(-) - -diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c -index 2bb554a4694..89e66267593 100644 ---- a/programs/tabtip/tabtip.c -+++ b/programs/tabtip/tabtip.c -@@ -303,6 +303,21 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine - goto exit; - } - -+ if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) -+ { -+ ERR("CoInitialize failed!\n"); -+ ret = -1; -+ goto exit; -+ } -+ -+ if (FAILED(create_uia_event_handler(&uia_iface, &data))) -+ { -+ ret = -1; -+ goto exit; -+ } -+ -+ SetEvent(started_event); -+ - wc.lpfnWndProc = WindowProc; - wc.hInstance = hInstance; - wc.lpszClassName = CLASS_NAME; -@@ -320,24 +335,9 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine - goto exit; - } - -- if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) -- { -- ERR("CoInitialize failed!\n"); -- ret = -1; -- goto exit; -- } -- -- if (FAILED(create_uia_event_handler(&uia_iface, &data))) -- { -- ret = -1; -- goto exit; -- } -- - t_data.events[EVENT_WINE_EXIT] = wine_exit_event; - t_data.events[EVENT_PGM_EXIT] = pgm_exit_event; - t_data.main_hwnd = hwnd; -- -- SetEvent(started_event); - CreateThread(NULL, 0, tabtip_exit_watcher, &t_data, 0, NULL); - - while (GetMessageW(&msg, NULL, 0, 0)) -From 4f2d430ca3c0354607c284ab9a7940c109d3a0ea Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 23 Nov 2021 17:04:40 -0500 -Subject: [PATCH] uiautomationcore: Implement UIA_ValueIsReadOnlyPropertyId. - -Signed-off-by: Connor McAdams ---- - dlls/uiautomationcore/uia_client.c | 117 +++++++++++++++++++++++++++++ - 1 file changed, 117 insertions(+) - -diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c -index 312cac97fe7..d486a1b50ac 100644 ---- a/dlls/uiautomationcore/uia_client.c -+++ b/dlls/uiautomationcore/uia_client.c -@@ -758,6 +758,79 @@ static void uia_create_bounding_rect_variant(double left, double top, - V_ARRAY(arr_out) = lpsa; - } - -+struct uia_pattern_id_info { -+ PATTERNID pattern_id; -+ REFIID pattern_iid; -+}; -+ -+static const struct uia_pattern_id_info uia_pattern_ids[] = { -+ { UIA_AnnotationPatternId, &IID_IAnnotationProvider }, -+ { UIA_CustomNavigationPatternId, &IID_ICustomNavigationProvider }, -+ { UIA_DockPatternId, &IID_IDockProvider }, -+ { UIA_DragPatternId, &IID_IDragProvider }, -+ { UIA_DropTargetPatternId, &IID_IDropTargetProvider }, -+ { UIA_ExpandCollapsePatternId, &IID_IExpandCollapseProvider }, -+ { UIA_GridItemPatternId, &IID_IGridItemProvider }, -+ { UIA_GridPatternId, &IID_IGridProvider }, -+ { UIA_InvokePatternId, &IID_IInvokeProvider }, -+ { UIA_ItemContainerPatternId, &IID_IItemContainerProvider }, -+ { UIA_LegacyIAccessiblePatternId, &IID_ILegacyIAccessibleProvider }, -+ { UIA_MultipleViewPatternId, &IID_IMultipleViewProvider }, -+ { UIA_ObjectModelPatternId, &IID_IObjectModelProvider }, -+ { UIA_RangeValuePatternId, &IID_IRangeValueProvider }, -+ { UIA_ScrollItemPatternId, &IID_IScrollItemProvider }, -+ { UIA_ScrollPatternId, &IID_IScrollProvider }, -+ { UIA_SelectionItemPatternId, &IID_ISelectionItemProvider, }, -+ { UIA_SelectionPatternId, &IID_ISelectionProvider, }, -+ { UIA_SpreadsheetPatternId, &IID_ISpreadsheetProvider, }, -+ { UIA_SpreadsheetItemPatternId, &IID_ISpreadsheetItemProvider, }, -+ { UIA_StylesPatternId, &IID_IStylesProvider, }, -+ { UIA_SynchronizedInputPatternId, &IID_ISynchronizedInputProvider, }, -+ { UIA_TableItemPatternId, &IID_ITableItemProvider, }, -+ /* GridPattern should also be checked if TablePattern is. */ -+ { UIA_TablePatternId, &IID_ITableProvider, }, -+ { UIA_TextChildPatternId, &IID_ITextChildProvider, }, -+ { UIA_TextEditPatternId, &IID_ITextEditProvider, }, -+ { UIA_TextPatternId, &IID_ITextProvider, }, -+ { UIA_TextPattern2Id, &IID_ITextProvider2, }, -+ { UIA_TogglePatternId, &IID_IToggleProvider, }, -+ { UIA_TransformPatternId, &IID_ITransformProvider, }, -+ { UIA_TransformPattern2Id, &IID_ITransformProvider2, }, -+ { UIA_ValuePatternId, &IID_IValueProvider, }, -+ { UIA_VirtualizedItemPatternId, &IID_IVirtualizedItemProvider, }, -+ { UIA_WindowPatternId, &IID_IWindowProvider, }, -+}; -+ -+static const struct uia_pattern_id_info *uia_get_pattern_id_info(PATTERNID pattern_id) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(uia_pattern_ids); i++) -+ { -+ if (uia_pattern_ids[i].pattern_id == pattern_id) -+ return &uia_pattern_ids[i]; -+ } -+ -+ return NULL; -+} -+ -+static HRESULT uia_get_pattern_provider(IRawElementProviderSimple *elem_prov, -+ PATTERNID pattern_id, void **pattern_prov_iface) -+{ -+ const struct uia_pattern_id_info *pattern_info = uia_get_pattern_id_info(pattern_id); -+ IUnknown *pattern_unk = NULL; -+ HRESULT hr; -+ -+ *pattern_prov_iface = NULL; -+ if (!pattern_info) -+ return E_FAIL; -+ -+ hr = IRawElementProviderSimple_GetPatternProvider(elem_prov, pattern_id, &pattern_unk); -+ if (FAILED(hr) || !pattern_unk) return hr; -+ -+ return IUnknown_QueryInterface(pattern_unk, pattern_info->pattern_iid, pattern_prov_iface); -+} -+ - static void uia_get_default_property_val(PROPERTYID propertyId, VARIANT *retVal) - { - switch (propertyId) -@@ -782,6 +855,11 @@ static void uia_get_default_property_val(PROPERTYID propertyId, VARIANT *retVal) - uia_create_bounding_rect_variant(0, 0, 0, 0, retVal); - break; - -+ case UIA_ValueIsReadOnlyPropertyId: -+ V_VT(retVal) = VT_BOOL; -+ V_BOOL(retVal) = VARIANT_TRUE; -+ break; -+ - default: - FIXME("Unimplemented default value for PropertyId %d!\n", propertyId); - V_VT(retVal) = VT_EMPTY; -@@ -821,6 +899,29 @@ static HRESULT uia_get_uia_elem_prov_property_val(IRawElementProviderSimple *ele - } - break; - -+ case UIA_ValueIsReadOnlyPropertyId: -+ { -+ IValueProvider *val_prov; -+ BOOL ret; -+ -+ hr = uia_get_pattern_provider(elem_prov, UIA_ValuePatternId, (void **)&val_prov); -+ if (FAILED(hr) || !val_prov) -+ break; -+ -+ hr = IValueProvider_get_IsReadOnly(val_prov, &ret); -+ if (FAILED(hr)) -+ break; -+ -+ V_VT(&res) = VT_BOOL; -+ if (ret) -+ V_BOOL(&res) = VARIANT_TRUE; -+ else -+ V_BOOL(&res) = VARIANT_FALSE; -+ -+ IValueProvider_Release(val_prov); -+ } -+ break; -+ - default: - hr = IRawElementProviderSimple_GetPropertyValue(elem_prov, propertyId, &res); - break; -@@ -911,6 +1012,22 @@ static HRESULT uia_get_msaa_acc_property_val(IAccessible *acc, - } - break; - -+ case UIA_ValueIsReadOnlyPropertyId: -+ { -+ hr = IAccessible_get_accState(acc, child_id, &res); -+ if (SUCCEEDED(hr) && V_VT(&res) == VT_I4) -+ { -+ V_VT(retVal) = VT_BOOL; -+ if (V_I4(&res) & STATE_SYSTEM_READONLY) -+ V_BOOL(retVal) = VARIANT_TRUE; -+ else -+ V_BOOL(retVal) = VARIANT_FALSE; -+ -+ *use_default = FALSE; -+ } -+ } -+ break; -+ - default: - FIXME("UIA PropertyId %d unimplemented for IAccessible!\n", propertyId); - break; -From ea603cf47d280d22270bf66c75969ba607a63fb9 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 23 Nov 2021 17:09:13 -0500 -Subject: [PATCH] tabtip: Check UIA_ValueIsReadOnlyPropertyId before triggering - OSK. - -Signed-off-by: Connor McAdams ---- - programs/tabtip/tabtip.c | 13 +++++++++++-- - 1 file changed, 11 insertions(+), 2 deletions(-) - -diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c -index 89e66267593..cb2c52c1db2 100644 ---- a/programs/tabtip/tabtip.c -+++ b/programs/tabtip/tabtip.c -@@ -147,6 +147,14 @@ ULONG WINAPI uia_focus_event_Release(IUIAutomationFocusChangedEventHandler* ifac - return ref; - } - -+static BOOL variant_to_bool(VARIANT *v) -+{ -+ if (V_VT(v) == VT_BOOL && (V_BOOL(v) == VARIANT_TRUE)) -+ return TRUE; -+ -+ return FALSE; -+} -+ - /*** IUIAutomationFocusChangedEventHandler methods ***/ - HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChangedEventHandler *iface, - IUIAutomationElement *sender) -@@ -157,7 +165,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - if (sender) - { - RECT rect = { 0 }; -- VARIANT var; -+ VARIANT var, var2; - INT ct_id; - BSTR name; - -@@ -165,9 +173,10 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - IUIAutomationElement_get_CurrentName(sender, &name); - IUIAutomationElement_get_CurrentBoundingRectangle(sender, &rect); - IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); -+ IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_ValueIsReadOnlyPropertyId, &var2); - - if (use_steam_osk && (last_keyup_event < (GetTickCount() - 5000)) && -- ct_id == UIA_EditControlTypeId && (V_VT(&var) == VT_BOOL && V_BOOL(&var))) -+ (ct_id == UIA_EditControlTypeId) && variant_to_bool(&var) && !variant_to_bool(&var2)) - { - if (!keyboard_up) - { -From a73a8c988c3f9abc50f2e633d87c4291d144ba48 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 23 Nov 2021 17:11:26 -0500 -Subject: [PATCH] tabtip: Free returned UI Automation element name string. - -Signed-off-by: Connor McAdams ---- - programs/tabtip/Makefile.in | 2 +- - programs/tabtip/tabtip.c | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/programs/tabtip/Makefile.in b/programs/tabtip/Makefile.in -index 846b813be69..d60a4eafd89 100644 ---- a/programs/tabtip/Makefile.in -+++ b/programs/tabtip/Makefile.in -@@ -1,5 +1,5 @@ - MODULE = tabtip.exe --IMPORTS = uuid ole32 user32 oleacc uiautomationcore rpcrt4 shell32 -+IMPORTS = uuid ole32 user32 oleacc uiautomationcore rpcrt4 shell32 oleaut32 - - EXTRADLLFLAGS = -mconsole -municode -mno-cygwin - -diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c -index cb2c52c1db2..bf5936ed719 100644 ---- a/programs/tabtip/tabtip.c -+++ b/programs/tabtip/tabtip.c -@@ -213,6 +213,7 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - - WINE_TRACE("element name: %s, ct_id %s, rect { %d, %d } - { %d, %d }\n", wine_dbgstr_w(name), ct_id_str[ct_id], - rect.left, rect.top, rect.right, rect.bottom); -+ SysFreeString(name); - } - - return S_OK; -From 58cbc0b829f1376fe9d3e191a999fd69aeb10fc5 Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Tue, 23 Nov 2021 17:14:15 -0500 -Subject: [PATCH] tabtip: Simplify OSK triggering conditions. - -Get rid of old, no longer necessary OSK trigger conditions. First is the -delay between subsequent OSK trigger events, which was necessary when -the big picture mode OSK would steal focus, but no longer applies here. -Also allow for the OSK to be triggered even if the last focused control -triggered the OSK, as sometimes a subsequent text field is selected -without a non-edit control inbetween. - -Signed-off-by: Connor McAdams ---- - programs/tabtip/tabtip.c | 31 ++++++++++++------------------- - 1 file changed, 12 insertions(+), 19 deletions(-) - -diff --git a/programs/tabtip/tabtip.c b/programs/tabtip/tabtip.c -index bf5936ed719..9f844151ad9 100644 ---- a/programs/tabtip/tabtip.c -+++ b/programs/tabtip/tabtip.c -@@ -53,7 +53,6 @@ typedef struct { - LONG ref; - } event_data; - --DWORD last_keyup_event; - BOOL keyboard_up; - BOOL use_steam_osk; - -@@ -175,26 +174,21 @@ HRESULT WINAPI uia_focus_event_HandleFocusChangedEvent(IUIAutomationFocusChanged - IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_IsKeyboardFocusablePropertyId, &var); - IUIAutomationElement_GetCurrentPropertyValue(sender, UIA_ValueIsReadOnlyPropertyId, &var2); - -- if (use_steam_osk && (last_keyup_event < (GetTickCount() - 5000)) && -- (ct_id == UIA_EditControlTypeId) && variant_to_bool(&var) && !variant_to_bool(&var2)) -+ if (use_steam_osk && (ct_id == UIA_EditControlTypeId) && variant_to_bool(&var) && -+ !variant_to_bool(&var2)) - { -- if (!keyboard_up) -+ WINE_TRACE("Keyboard up!\n"); -+ keyboard_up = TRUE; -+ if (rect.left || rect.top || rect.right || rect.bottom) - { -- WINE_TRACE("Keyboard up!\n"); -- keyboard_up = TRUE; -- if (rect.left || rect.top || rect.right || rect.bottom) -- { -- WCHAR link_buf[1024]; -- -- wsprintfW(link_buf, L"steam://open/keyboard?XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", -- rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); -- ShellExecuteW(NULL, NULL, link_buf, NULL, NULL, SW_SHOWNOACTIVATE); -- } -- else -- ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); -- -- last_keyup_event = GetTickCount(); -+ WCHAR link_buf[1024]; -+ -+ wsprintfW(link_buf, L"steam://open/keyboard?XPosition=%d&YPosition=%d&Width=%d&Height=%d&Mode=0", -+ rect.left, rect.top, (rect.right - rect.left), (rect.bottom - rect.top)); -+ ShellExecuteW(NULL, NULL, link_buf, NULL, NULL, SW_SHOWNOACTIVATE); - } -+ else -+ ShellExecuteW(NULL, NULL, L"steam://open/keyboard", NULL, NULL, SW_SHOWNOACTIVATE); - } - else - { -@@ -297,7 +291,6 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine - HWND hwnd; - - wine_exit_event = pgm_exit_event = started_event = NULL; -- last_keyup_event = 0; - keyboard_up = FALSE; - tabtip_use_osk_check(); - -From fb7fb08936c2f99fa92fdd283cd3e1600993a5df Mon Sep 17 00:00:00 2001 -From: Connor McAdams -Date: Mon, 22 Nov 2021 10:31:56 -0500 -Subject: [PATCH] include: Add UI Automation provider interface definitions. - -Signed-off-by: Connor McAdams ---- - include/uiautomationcore.idl | 554 +++++++++++++++++++++++++++++++++++ - 1 file changed, 554 insertions(+) - -diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl -index 32c80ec8d5f..7d1a0e43480 100644 ---- a/include/uiautomationcore.idl -+++ b/include/uiautomationcore.idl -@@ -324,4 +324,558 @@ library UIA - [out, retval] VARIANT *val); - } - #endif -+ [ -+ object, -+ uuid(159bc72c-4ad3-485e-9637-d7052edf0146), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IDockProvider : IUnknown { -+ HRESULT SetDockPosition([in]enum DockPosition dockPosition); -+ [propget]HRESULT DockPosition([out, retval]enum DockPosition *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(d847d3a5-cab0-4a98-8c32-ecb45c59ad24), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IExpandCollapseProvider : IUnknown { -+ HRESULT Expand(); -+ HRESULT Collapse(); -+ [propget]HRESULT ExpandCollapseState([out, retval]enum ExpandCollapseState *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(b17d6187-0907-464b-a168-0ef17a1572b1), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IGridProvider : IUnknown { -+ HRESULT GetItem([in]int row, -+ [in]int column, -+ [out, retval]IRawElementProviderSimple **pRetVal); -+ [propget]HRESULT RowCount([out, retval]int *pRetVal); -+ [propget]HRESULT ColumnCount([out, retval]int *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(d02541f1-fb81-4d64-ae32-f520f8a6dbd1), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IGridItemProvider : IUnknown { -+ [propget]HRESULT Row([out, retval]int *pRetVal); -+ [propget]HRESULT Column([out, retval]int *pRetVal); -+ [propget]HRESULT RowSpan([out, retval]int *pRetVal); -+ [propget]HRESULT ColumnSpan([out, retval]int *pRetVal); -+ [propget]HRESULT ContainingGrid([out, retval]IRawElementProviderSimple **pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(54fcb24b-e18e-47a2-b4d3-eccbe77599a2), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IInvokeProvider : IUnknown { -+ HRESULT Invoke(); -+ }; -+ -+ [ -+ object, -+ uuid(6278cab1-b556-4a1a-b4e0-418acc523201), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IMultipleViewProvider : IUnknown { -+ HRESULT GetViewName([in]int viewId, [out, retval]BSTR *pRetVal); -+ HRESULT SetCurrentView([in]int viewId); -+ [propget]HRESULT CurrentView([out, retval]int *pRetVal); -+ HRESULT GetSupportedViews([out, retval]SAFEARRAY(int) *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(36dc7aef-33e6-4691-afe1-2be7274b3d33), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IRangeValueProvider : IUnknown { -+ HRESULT SetValue([in]double val); -+ [propget]HRESULT Value([out, retval]double *pRetVal); -+ [propget]HRESULT IsReadOnly([out, retval]BOOL *pRetVal); -+ [propget]HRESULT Maximum([out, retval]double *pRetVal); -+ [propget]HRESULT Minimum([out, retval]double *pRetVal); -+ [propget]HRESULT LargeChange([out, retval]double *pRetVal); -+ [propget]HRESULT SmallChange([out, retval]double *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(2360c714-4bf1-4b26-ba65-9b21316127eb), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IScrollItemProvider : IUnknown { -+ HRESULT ScrollIntoView (); -+ }; -+ -+ [ -+ object, -+ uuid(fb8b03af-3bdf-48d4-bd36-1a65793be168), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ISelectionProvider : IUnknown { -+ /* SAFEARRAY(IUnknown *) currently unsupported by WIDL. */ -+/* HRESULT GetSelection([out, retval]SAFEARRAY(IRawElementProviderSimple *) *pRetVal);*/ -+ HRESULT GetSelection([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ [propget]HRESULT CanSelectMultiple([out, retval]BOOL *pRetVal); -+ [propget]HRESULT IsSelectionRequired([out, retval]BOOL *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(14f68475-ee1c-44f6-a869-d239381f0fe7), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ISelectionProvider2 : ISelectionProvider { -+ [propget]HRESULT FirstSelectedItem([out, retval]IRawElementProviderSimple **retVal); -+ [propget]HRESULT LastSelectedItem([out, retval]IRawElementProviderSimple **retVal); -+ [propget]HRESULT CurrentSelectedItem([out, retval]IRawElementProviderSimple **retVal); -+ [propget]HRESULT ItemCount([out, retval]int *retVal); -+ }; -+ -+ [ -+ object, -+ uuid(b38b8077-1fc3-42a5-8cae-d40c2215055a), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IScrollProvider : IUnknown { -+ HRESULT Scroll([in]enum ScrollAmount horizontalAmount, -+ [in]enum ScrollAmount verticalAmount); -+ HRESULT SetScrollPercent([in]double horizontalPercent, -+ [in]double verticalPercent); -+ -+ [propget]HRESULT HorizontalScrollPercent([out, retval]double *pRetVal); -+ [propget]HRESULT VerticalScrollPercent([out, retval]double *pRetVal); -+ [propget]HRESULT HorizontalViewSize([out, retval]double *pRetVal); -+ [propget]HRESULT VerticalViewSize([out, retval]double *pRetVal); -+ [propget]HRESULT HorizontallyScrollable([out, retval]BOOL *pRetVal); -+ [propget]HRESULT VerticallyScrollable([out, retval]BOOL *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(2acad808-b2d4-452d-a407-91ff1ad167b2), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ISelectionItemProvider : IUnknown { -+ HRESULT Select(); -+ HRESULT AddToSelection(); -+ HRESULT RemoveFromSelection(); -+ [propget]HRESULT IsSelected([out, retval]BOOL *pRetVal); -+ [propget]HRESULT SelectionContainer([out, retval]IRawElementProviderSimple **pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(29db1a06-02ce-4cf7-9b42-565d4fab20ee), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ISynchronizedInputProvider : IUnknown { -+ HRESULT StartListening([in]enum SynchronizedInputType inputType); -+ HRESULT Cancel(); -+ }; -+ -+ [ -+ object, -+ uuid(9c860395-97b3-490a-b52a-858cc22af166), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITableProvider : IUnknown { -+ /* SAFEARRAY(IUnknown *) currently unsupported by WIDL. */ -+/* -+ HRESULT GetRowHeaders([out, retval]SAFEARRAY(IRawElementProviderSimple*) *pRetVal); -+ HRESULT GetColumnHeaders([out, retval]SAFEARRAY(IRawElementProviderSimple*) *pRetVal); -+*/ -+ HRESULT GetRowHeaders([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ HRESULT GetColumnHeaders([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ [propget]HRESULT RowOrColumnMajor([out, retval]enum RowOrColumnMajor *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(b9734fa6-771f-4d78-9c90-2517999349cd), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITableItemProvider : IUnknown { -+ /* SAFEARRAY(IUnknown *) currently unsupported by WIDL. */ -+/* -+ HRESULT GetRowHeaderItems([out, retval]SAFEARRAY(IRawElementProviderSimple*) *pRetVal); -+ HRESULT GetColumnHeaderItems([out, retval]SAFEARRAY(IRawElementProviderSimple*) *pRetVal); -+*/ -+ HRESULT GetRowHeaderItems([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ HRESULT GetColumnHeaderItems([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ }; -+ -+ [object, uuid(56d00bd0-c4f4-433c-a836-1a52a57e0892), pointer_default(unique), oleautomation] -+ interface IToggleProvider : IUnknown { -+ HRESULT Toggle(); -+ [propget]HRESULT ToggleState([out, retval]enum ToggleState *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(6829ddc4-4f91-4ffa-b86f-bd3e2987cb4c), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITransformProvider : IUnknown { -+ HRESULT Move([in]double x, [in]double y); -+ HRESULT Resize([in]double width, [in]double height); -+ HRESULT Rotate([in]double degrees); -+ [propget]HRESULT CanMove([out, retval]BOOL *pRetVal); -+ [propget]HRESULT CanResize([out, retval]BOOL *pRetVal); -+ [propget]HRESULT CanRotate([out, retval]BOOL *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(c7935180-6fb3-4201-b174-7df73adbf64a), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IValueProvider : IUnknown { -+ /* -+ * HACK: Make SetValue's argument a BSTR since LPCWSTR marshaling is -+ * currently unsupported. -+ */ -+/* HRESULT SetValue([in]LPCWSTR val);*/ -+ HRESULT SetValue([in]BSTR val); -+ [propget]HRESULT Value([out, retval]BSTR *pRetVal); -+ [propget]HRESULT IsReadOnly([out, retval]BOOL *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(987df77b-db06-4d77-8f8a-86a9c3bb90b9), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IWindowProvider : IUnknown { -+ HRESULT SetVisualState([in]enum WindowVisualState state); -+ HRESULT Close(); -+ HRESULT WaitForInputIdle([in]int milliseconds, [out, retval]BOOL *pRetVal); -+ -+ [propget]HRESULT CanMaximize([out, retval]BOOL *pRetVal); -+ [propget]HRESULT CanMinimize ([out, retval]BOOL *pRetVal); -+ [propget]HRESULT IsModal([out, retval]BOOL *pRetVal); -+ [propget]HRESULT WindowVisualState ([out, retval]enum WindowVisualState *pRetVal); -+ [propget]HRESULT WindowInteractionState([out, retval]enum WindowInteractionState *pRetVal); -+ [propget]HRESULT IsTopmost([out, retval]BOOL *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(e44c3566-915d-4070-99c6-047bff5a08f5), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ILegacyIAccessibleProvider : IUnknown { -+ HRESULT Select( long flagsSelect ); -+ HRESULT DoDefaultAction(); -+ HRESULT SetValue(LPCWSTR szValue); -+ HRESULT GetIAccessible([out, retval]IAccessible **ppAccessible); -+ -+ [propget]HRESULT ChildId([out, retval]int *pRetVal); -+ [propget]HRESULT Name([out, retval]BSTR *pszName); -+ [propget]HRESULT Value([out, retval]BSTR *pszValue); -+ [propget]HRESULT Description([out, retval]BSTR *pszDescription); -+ [propget]HRESULT Role([out, retval]DWORD *pdwRole); -+ [propget]HRESULT State([out, retval]DWORD *pdwState); -+ [propget]HRESULT Help([out, retval]BSTR *pszHelp); -+ [propget]HRESULT KeyboardShortcut([out, retval]BSTR *pszKeyboardShortcut); -+ -+ /* SAFEARRAY(IUnknown *) currently unsupported by WIDL. */ -+/* HRESULT GetSelection([out, retval]SAFEARRAY(IRawElementProviderSimple *) *pvarSelectedChildren);*/ -+ HRESULT GetSelection([out, retval]SAFEARRAY(VARIANT) *pvarSelectedChildren); -+ -+ [propget]HRESULT DefaultAction([out, retval]BSTR *pszDefaultAction); -+ }; -+ -+ [ -+ object, -+ uuid(e747770b-39ce-4382-ab30-d8fb3f336f24), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IItemContainerProvider : IUnknown { -+ HRESULT FindItemByProperty([in]IRawElementProviderSimple *pStartAfter, -+ [in]PROPERTYID propertyId, -+ [in]VARIANT value, -+ [out, retval]IRawElementProviderSimple **pFound); -+ }; -+ -+ [ -+ object, -+ uuid(cb98b665-2d35-4fac-ad35-f3c60d0c0b8b), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IVirtualizedItemProvider : IUnknown { -+ HRESULT Realize(); -+ }; -+ -+ [ -+ object, -+ uuid(3ad86ebd-f5ef-483d-bb18-b1042a475d64), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IObjectModelProvider : IUnknown { -+ HRESULT GetUnderlyingObjectModel([out, retval]IUnknown **ppUnknown); -+ }; -+ -+ [ -+ object, -+ uuid(f95c7e80-bd63-4601-9782-445ebff011fc), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IAnnotationProvider : IUnknown { -+ [propget]HRESULT AnnotationTypeId([out, retval] int *retVal); -+ [propget]HRESULT AnnotationTypeName([out, retval]BSTR *retVal); -+ [propget]HRESULT Author([out, retval]BSTR *retVal); -+ [propget]HRESULT DateTime([out, retval] BSTR *retVal); -+ [propget]HRESULT Target([out, retval]IRawElementProviderSimple **retVal); -+ }; -+ -+ [ -+ object, -+ uuid(19b6b649-f5d7-4a6d-bdcb-129252be588a), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IStylesProvider : IUnknown { -+ [propget]HRESULT StyleId([out, retval]int *retVal); -+ [propget]HRESULT StyleName([out, retval]BSTR *retVal); -+ [propget]HRESULT FillColor([out, retval]int *retVal); -+ [propget]HRESULT FillPatternStyle([out, retval]BSTR *retVal); -+ [propget]HRESULT Shape([out, retval]BSTR *retVal); -+ [propget]HRESULT FillPatternColor([out, retval]int *retVal); -+ [propget]HRESULT ExtendedProperties([out, retval]BSTR *retVal); -+ }; -+ -+ [ -+ object, -+ uuid(6f6b5d35-5525-4f80-b758-85473832ffc7), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ISpreadsheetProvider : IUnknown { -+ HRESULT GetItemByName([in]LPCWSTR name, -+ [out, retval]IRawElementProviderSimple **pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(eaed4660-7b3d-4879-a2e6-365ce603f3d0), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ISpreadsheetItemProvider : IUnknown { -+ [propget]HRESULT Formula([out, retval]BSTR *pRetVal); -+ -+ /* SAFEARRAY(IUnknown *) currently unsupported by WIDL. */ -+/* HRESULT GetAnnotationObjects([out, retval]SAFEARRAY(IRawElementProviderSimple*) *pRetVal);*/ -+ HRESULT GetAnnotationObjects([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ -+ HRESULT GetAnnotationTypes([out, retval]SAFEARRAY(int) *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(4758742f-7ac2-460c-bc48-09fc09308a93), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITransformProvider2 : ITransformProvider { -+ HRESULT Zoom([in]double zoom); -+ -+ [propget]HRESULT CanZoom([out, retval]BOOL *pRetVal); -+ [propget]HRESULT ZoomLevel([out, retval]double *pRetVal); -+ [propget]HRESULT ZoomMinimum([out, retval]double *pRetVal); -+ [propget]HRESULT ZoomMaximum([out, retval]double *pRetVal); -+ -+ HRESULT ZoomByUnit([in]enum ZoomUnit zoomUnit); -+ } -+ -+ [ -+ object, -+ uuid(6aa7bbbb-7ff9-497d-904f-d20b897929d8), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IDragProvider : IUnknown { -+ [propget]HRESULT IsGrabbed([out, retval]BOOL *pRetVal); -+ [propget]HRESULT DropEffect([out, retval]BSTR *pRetVal); -+ [propget]HRESULT DropEffects([out, retval]SAFEARRAY(BSTR) *pRetVal); -+ -+ /* SAFEARRAY(IUnknown *) currently unsupported by WIDL. */ -+/* HRESULT GetGrabbedItems([out, retval]SAFEARRAY(IRawElementProviderSimple*) *pRetVal);*/ -+ HRESULT GetGrabbedItems([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(bae82bfd-358a-481c-85a0-d8b4d90a5d61), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface IDropTargetProvider : IUnknown { -+ [propget]HRESULT DropTargetEffect([out, retval]BSTR *pRetVal); -+ [propget]HRESULT DropTargetEffects([out, retval]SAFEARRAY(BSTR) *pRetVal); -+ }; -+ -+ interface ITextRangeProvider; -+ [ -+ object, -+ uuid(3589c92c-63f3-4367-99bb-ada653b77cf2), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITextProvider : IUnknown { -+ /* SAFEARRAY(IUnknown *) currently unsupported by WIDL. */ -+/* -+ HRESULT GetSelection([out, retval]SAFEARRAY(ITextRangeProvider *) *pRetVal); -+ HRESULT GetVisibleRanges([out, retval]SAFEARRAY(ITextRangeProvider *) *pRetVal); -+*/ -+ HRESULT GetSelection([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ HRESULT GetVisibleRanges([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ HRESULT RangeFromChild([in]IRawElementProviderSimple *childElement, -+ [out, retval]ITextRangeProvider **pRetVal); -+ HRESULT RangeFromPoint([in]struct UiaPoint point, -+ [out, retval]ITextRangeProvider **pRetVal); -+ -+ [propget]HRESULT DocumentRange([out, retval]ITextRangeProvider **pRetVal); -+ [propget]HRESULT SupportedTextSelection([out, retval]enum SupportedTextSelection *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(0dc5e6ed-3e16-4bf1-8f9a-a979878bc195), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITextProvider2 : ITextProvider { -+ HRESULT RangeFromAnnotation([in]IRawElementProviderSimple *annotationElement, -+ [out, retval]ITextRangeProvider **pRetVal); -+ -+ HRESULT GetCaretRange([out]BOOL *isActive, -+ [out, retval]ITextRangeProvider **pRetVal); -+ } -+ -+ [ -+ object, -+ uuid(EA3605B4-3A05-400E-B5F9-4E91B40F6176), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITextEditProvider : ITextProvider { -+ HRESULT GetActiveComposition([out, retval]ITextRangeProvider **pRetVal); -+ HRESULT GetConversionTarget([out, retval]ITextRangeProvider **pRetVal); -+ } -+ -+ [ -+ object, -+ uuid(5347ad7b-c355-46f8-aff5-909033582f63), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITextRangeProvider : IUnknown { -+ HRESULT Clone([out, retval]ITextRangeProvider **pRetVal); -+ HRESULT Compare([in]ITextRangeProvider *range, -+ [out, retval]BOOL *pRetVal); -+ HRESULT CompareEndpoints([in]enum TextPatternRangeEndpoint endpoint, -+ [in]ITextRangeProvider *targetRange, -+ [in]enum TextPatternRangeEndpoint targetEndpoint, -+ [out, retval]int *pRetVal); -+ HRESULT ExpandToEnclosingUnit([in]enum TextUnit unit); -+ HRESULT FindAttribute([in]TEXTATTRIBUTEID attributeId, -+ [in]VARIANT val, -+ [in]BOOL backward, -+ [out, retval]ITextRangeProvider **pRetVal); -+ HRESULT FindText([in]BSTR text, -+ [in]BOOL backward, -+ [in]BOOL ignoreCase, -+ [out, retval]ITextRangeProvider **pRetVal); -+ HRESULT GetAttributeValue([in]TEXTATTRIBUTEID attributeId, -+ [out, retval]VARIANT *pRetVal); -+ HRESULT GetBoundingRectangles([out, retval]SAFEARRAY(double) *pRetVal); -+ HRESULT GetEnclosingElement([out, retval]IRawElementProviderSimple **pRetVal); -+ HRESULT GetText([in]int maxLength, -+ [out, retval]BSTR *pRetVal); -+ HRESULT Move([in]enum TextUnit unit, -+ [in]int count, -+ [out, retval]int *pRetVal); -+ HRESULT MoveEndpointByUnit( -+ [in]enum TextPatternRangeEndpoint endpoint, -+ [in]enum TextUnit unit, -+ [in]int count, -+ [out, retval]int *pRetVal); -+ HRESULT MoveEndpointByRange([in]enum TextPatternRangeEndpoint endpoint, -+ [in]ITextRangeProvider *targetRange, -+ [in]enum TextPatternRangeEndpoint targetEndpoint); -+ HRESULT Select(); -+ HRESULT AddToSelection(); -+ HRESULT RemoveFromSelection(); -+ HRESULT ScrollIntoView([in]BOOL alignToTop); -+ /* SAFEARRAY(IUnknown *) currently unsupported by WIDL. */ -+/* HRESULT GetChildren([out, retval]SAFEARRAY(IRawElementProviderSimple*) *pRetVal);*/ -+ HRESULT GetChildren([out, retval]SAFEARRAY(VARIANT) *pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(9BBCE42C-1921-4F18-89CA-DBA1910A0386), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITextRangeProvider2 : ITextRangeProvider { -+ HRESULT ShowContextMenu(); -+ } -+ -+ [ -+ object, -+ uuid(4c2de2b9-c88f-4f88-a111-f1d336b7d1a9), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ITextChildProvider : IUnknown { -+ [propget]HRESULT TextContainer([out, retval]IRawElementProviderSimple **pRetVal); -+ -+ [propget]HRESULT TextRange([out, retval]ITextRangeProvider **pRetVal); -+ }; -+ -+ [ -+ object, -+ uuid(2062A28A-8C07-4B94-8E12-7037C622AEB8), -+ pointer_default(unique), -+ oleautomation -+ ] -+ interface ICustomNavigationProvider : IUnknown { -+ HRESULT Navigate([in]enum NavigateDirection direction, -+ [out, retval]IRawElementProviderSimple **pRetVal); -+ } - } diff --git a/patches/proton/fshack/01-vulkan-1-prefer-builtin.patch b/patches/proton/fshack/01-vulkan-1-prefer-builtin.patch deleted file mode 100644 index 9ba8cebf0..000000000 --- a/patches/proton/fshack/01-vulkan-1-prefer-builtin.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 642bef6793e45282c5bb10e50c7407a4cecb08bc Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 21 Jan 2021 11:54:10 -0600 -Subject: [PATCH] vulkan-1: Prefer builtin - -Games that ship their own vulkan-1 will be broken with your VR wrappers. ---- - dlls/vulkan-1/Makefile.in | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/dlls/vulkan-1/Makefile.in b/dlls/vulkan-1/Makefile.in -index a4a10bc8e93..551ef146cd7 100644 ---- a/dlls/vulkan-1/Makefile.in -+++ b/dlls/vulkan-1/Makefile.in -@@ -2,6 +2,4 @@ MODULE = vulkan-1.dll - IMPORTS = winevulkan - IMPORTLIB = vulkan-1 - --EXTRADLLFLAGS = -Wb,--prefer-native -- - RC_SRCS = version.rc - diff --git a/patches/proton/fshack/02-vulkan-childwindow.patch b/patches/proton/fshack/02-vulkan-childwindow.patch deleted file mode 100644 index f6f491560..000000000 --- a/patches/proton/fshack/02-vulkan-childwindow.patch +++ /dev/null @@ -1,1018 +0,0 @@ -From 055346363a41aba711a286a6bce35a7a679e2fa3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 12 Mar 2021 18:27:41 +0100 -Subject: [PATCH] winex11.drv: Store swapchain surfaces associations. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Based on a patch from Felix Hädicke . -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/vulkan.c | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c -index d805b3c8be4..948e963b12b 100644 ---- a/dlls/winex11.drv/vulkan.c -+++ b/dlls/winex11.drv/vulkan.c -@@ -54,6 +54,7 @@ static CRITICAL_SECTION_DEBUG critsect_debug = - static CRITICAL_SECTION context_section = { &critsect_debug, -1, 0, 0, 0, 0 }; - - static XContext vulkan_hwnd_context; -+static XContext vulkan_swapchain_context; - - #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000 - -@@ -143,6 +144,7 @@ static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context) - #undef LOAD_OPTIONAL_FUNCPTR - - vulkan_hwnd_context = XUniqueContext(); -+ vulkan_swapchain_context = XUniqueContext(); - - return TRUE; - -@@ -303,6 +305,8 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, - { - struct wine_vk_surface *x11_surface = surface_from_handle(create_info->surface); - VkSwapchainCreateInfoKHR create_info_host; -+ VkResult result; -+ - TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain); - - if (allocator) -@@ -314,7 +318,14 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, - create_info_host = *create_info; - create_info_host.surface = x11_surface->surface; - -- return pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); -+ result = pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); -+ if (result == VK_SUCCESS) -+ { -+ EnterCriticalSection(&context_section); -+ XSaveContext(gdi_display, (XID)(*swapchain), vulkan_swapchain_context, (char *)wine_vk_surface_grab(x11_surface)); -+ LeaveCriticalSection(&context_section); -+ } -+ return result; - } - - static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, -@@ -426,12 +437,20 @@ static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface - static void X11DRV_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, - const VkAllocationCallbacks *allocator) - { -+ struct wine_vk_surface *surface; -+ - TRACE("%p, 0x%s %p\n", device, wine_dbgstr_longlong(swapchain), allocator); - - if (allocator) - FIXME("Support for allocation callbacks not implemented yet\n"); - - pvkDestroySwapchainKHR(device, swapchain, NULL /* allocator */); -+ -+ EnterCriticalSection(&context_section); -+ if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface)) -+ wine_vk_surface_release(surface); -+ XDeleteContext(gdi_display, (XID)swapchain, vulkan_swapchain_context); -+ LeaveCriticalSection(&context_section); - } - - static VkResult X11DRV_vkEnumerateInstanceExtensionProperties(const char *layer_name, -From 6f66c2d03485428ba639457225eceedfe2d46a25 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 22 Apr 2021 23:38:16 +0200 -Subject: [PATCH] winex11.drv: Hook vkAcquireNextImage(2)KHR functions. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 ---- - dlls/winemac.drv/vulkan.c | 2 ++ - dlls/winevulkan/make_vulkan | 2 ++ - dlls/winex11.drv/vulkan.c | 19 +++++++++++++++++++ - include/wine/vulkan_driver.h | 6 ++++++ - 4 files changed, 29 insertions(+) - -diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c -index bc2128df275..6de6832fbd7 100644 ---- a/dlls/winemac.drv/vulkan.c -+++ b/dlls/winemac.drv/vulkan.c -@@ -589,6 +589,8 @@ static VkSurfaceKHR macdrv_wine_get_native_surface(VkSurfaceKHR surface) - - static const struct vulkan_funcs vulkan_funcs = - { -+ NULL, -+ NULL, - macdrv_vkCreateInstance, - macdrv_vkCreateSwapchainKHR, - macdrv_vkCreateWin32SurfaceKHR, -diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan -index e198256b31c..360b2087eb9 100755 ---- a/dlls/winevulkan/make_vulkan -+++ b/dlls/winevulkan/make_vulkan -@@ -227,6 +227,8 @@ FUNCTION_OVERRIDES = { - "vkGetPhysicalDeviceWin32PresentationSupportKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, - - # VK_KHR_swapchain -+ "vkAcquireNextImageKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, -+ "vkAcquireNextImage2KHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, - "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, - "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, - "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, -diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c -index 948e963b12b..c844ad35bb3 100644 ---- a/dlls/winex11.drv/vulkan.c -+++ b/dlls/winex11.drv/vulkan.c -@@ -79,6 +79,7 @@ typedef struct VkXlibSurfaceCreateInfoKHR - Window window; - } VkXlibSurfaceCreateInfoKHR; - -+static VkResult (*pvkAcquireNextImageKHR)(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t *); - static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); - static VkResult (*pvkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *); - static VkResult (*pvkCreateXlibSurfaceKHR)(VkInstance, const VkXlibSurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *); -@@ -120,6 +121,7 @@ static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context) - - #define LOAD_FUNCPTR(f) if (!(p##f = dlsym(vulkan_handle, #f))) goto fail - #define LOAD_OPTIONAL_FUNCPTR(f) p##f = dlsym(vulkan_handle, #f) -+ LOAD_FUNCPTR(vkAcquireNextImageKHR); - LOAD_FUNCPTR(vkCreateInstance); - LOAD_FUNCPTR(vkCreateSwapchainKHR); - LOAD_FUNCPTR(vkCreateXlibSurfaceKHR); -@@ -293,6 +295,21 @@ static VkResult X11DRV_create_vk_instance_with_callback(const VkInstanceCreateIn - return res; - } - -+static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, -+ VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, -+ VkFence fence, uint32_t *image_index) -+{ -+ return pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); -+} -+ -+static VkResult X11DRV_vkAcquireNextImage2KHR(VkDevice device, -+ const VkAcquireNextImageInfoKHR *acquire_info, uint32_t *image_index) -+{ -+ static int once; -+ if (!once++) FIXME("Emulating vkGetPhysicalDeviceSurfaceCapabilities2KHR with vkGetPhysicalDeviceSurfaceCapabilitiesKHR, pNext is ignored.\n"); -+ return X11DRV_vkAcquireNextImageKHR(device, acquire_info->swapchain, acquire_info->timeout, acquire_info->semaphore, acquire_info->fence, image_index); -+} -+ - static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, - const VkAllocationCallbacks *allocator, VkInstance *instance) - { -@@ -719,6 +736,8 @@ static VkSurfaceKHR X11DRV_wine_get_native_surface(VkSurfaceKHR surface) - - static const struct vulkan_funcs vulkan_funcs = - { -+ X11DRV_vkAcquireNextImage2KHR, -+ X11DRV_vkAcquireNextImageKHR, - X11DRV_vkCreateInstance, - X11DRV_vkCreateSwapchainKHR, - X11DRV_vkCreateWin32SurfaceKHR, -diff --git a/include/wine/vulkan_driver.h b/include/wine/vulkan_driver.h -index 09b94d2775f..f244e44ecf1 100644 ---- a/include/wine/vulkan_driver.h -+++ b/include/wine/vulkan_driver.h -@@ -21,6 +21,8 @@ struct vulkan_funcs - * needs to provide. Other function calls will be provided indirectly by dispatch - * tables part of dispatchable Vulkan objects such as VkInstance or vkDevice. - */ -+ VkResult (*p_vkAcquireNextImage2KHR)(VkDevice, const VkAcquireNextImageInfoKHR *, uint32_t *); -+ VkResult (*p_vkAcquireNextImageKHR)(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t *); - VkResult (*p_vkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); - VkResult (*p_vkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *); - VkResult (*p_vkCreateWin32SurfaceKHR)(VkInstance, const VkWin32SurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *); -@@ -55,6 +57,10 @@ static inline void *get_vulkan_driver_device_proc_addr( - - name += 2; - -+ if (!strcmp(name, "AcquireNextImage2KHR")) -+ return vulkan_funcs->p_vkAcquireNextImage2KHR; -+ if (!strcmp(name, "AcquireNextImageKHR")) -+ return vulkan_funcs->p_vkAcquireNextImageKHR; - if (!strcmp(name, "CreateSwapchainKHR")) - return vulkan_funcs->p_vkCreateSwapchainKHR; - if (!strcmp(name, "DestroySwapchainKHR")) -From 861c624e111454245326a0dcabeb2059ad15890c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 22 Oct 2021 00:23:49 +0200 -Subject: [PATCH] winex11.drv: Rename X11DRV_FLUSH_GL_DRAWABLE to - X11DRV_PRESENT_DRAWABLE. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/init.c | 8 ++++---- - dlls/winex11.drv/opengl.c | 40 +++++++++++++++++++-------------------- - dlls/winex11.drv/x11drv.h | 8 ++++---- - 3 files changed, 28 insertions(+), 28 deletions(-) - -diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c -index 5b31c352a23..0e8d2ffbf9e 100644 ---- a/dlls/winex11.drv/init.c -+++ b/dlls/winex11.drv/init.c -@@ -230,16 +230,16 @@ static INT CDECL X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOI - return TRUE; - } - break; -- case X11DRV_FLUSH_GL_DRAWABLE: -- if (in_count >= sizeof(struct x11drv_escape_flush_gl_drawable)) -+ case X11DRV_PRESENT_DRAWABLE: -+ if (in_count >= sizeof(struct x11drv_escape_present_drawable)) - { -- const struct x11drv_escape_flush_gl_drawable *data = in_data; -+ const struct x11drv_escape_present_drawable *data = in_data; - RECT rect = physDev->dc_rect; - - OffsetRect( &rect, -physDev->dc_rect.left, -physDev->dc_rect.top ); - if (data->flush) XFlush( gdi_display ); - XSetFunction( gdi_display, physDev->gc, GXcopy ); -- XCopyArea( gdi_display, data->gl_drawable, physDev->drawable, physDev->gc, -+ XCopyArea( gdi_display, data->drawable, physDev->drawable, physDev->gc, - 0, 0, rect.right, rect.bottom, - physDev->dc_rect.left, physDev->dc_rect.top ); - add_device_bounds( physDev, &rect ); -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 567205f742c..3f3deae59ba 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -1942,20 +1942,20 @@ static BOOL WINAPI glxdrv_wglShareLists(struct wgl_context *org, struct wgl_cont - - static void wglFinish(void) - { -- struct x11drv_escape_flush_gl_drawable escape; -+ struct x11drv_escape_present_drawable escape; - struct gl_drawable *gl; - struct wgl_context *ctx = NtCurrentTeb()->glContext; - -- escape.code = X11DRV_FLUSH_GL_DRAWABLE; -- escape.gl_drawable = 0; -+ escape.code = X11DRV_PRESENT_DRAWABLE; -+ escape.drawable = 0; - escape.flush = FALSE; - - if ((gl = get_gl_drawable( WindowFromDC( ctx->hdc ), 0 ))) - { - switch (gl->type) - { -- case DC_GL_PIXMAP_WIN: escape.gl_drawable = gl->pixmap; break; -- case DC_GL_CHILD_WIN: escape.gl_drawable = gl->window; break; -+ case DC_GL_PIXMAP_WIN: escape.drawable = gl->pixmap; break; -+ case DC_GL_CHILD_WIN: escape.drawable = gl->window; break; - default: break; - } - sync_context(ctx); -@@ -1963,25 +1963,25 @@ static void wglFinish(void) - } - - pglFinish(); -- if (escape.gl_drawable) ExtEscape( ctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); -+ if (escape.drawable) ExtEscape( ctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); - } - - static void wglFlush(void) - { -- struct x11drv_escape_flush_gl_drawable escape; -+ struct x11drv_escape_present_drawable escape; - struct gl_drawable *gl; - struct wgl_context *ctx = NtCurrentTeb()->glContext; - -- escape.code = X11DRV_FLUSH_GL_DRAWABLE; -- escape.gl_drawable = 0; -+ escape.code = X11DRV_PRESENT_DRAWABLE; -+ escape.drawable = 0; - escape.flush = FALSE; - - if ((gl = get_gl_drawable( WindowFromDC( ctx->hdc ), 0 ))) - { - switch (gl->type) - { -- case DC_GL_PIXMAP_WIN: escape.gl_drawable = gl->pixmap; break; -- case DC_GL_CHILD_WIN: escape.gl_drawable = gl->window; break; -+ case DC_GL_PIXMAP_WIN: escape.drawable = gl->pixmap; break; -+ case DC_GL_CHILD_WIN: escape.drawable = gl->window; break; - default: break; - } - sync_context(ctx); -@@ -1989,7 +1989,7 @@ static void wglFlush(void) - } - - pglFlush(); -- if (escape.gl_drawable) ExtEscape( ctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); -+ if (escape.drawable) ExtEscape( ctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); - } - - static const GLubyte *wglGetString(GLenum name) -@@ -3304,15 +3304,15 @@ static void X11DRV_WineGL_LoadExtensions(void) - */ - static BOOL WINAPI glxdrv_wglSwapBuffers( HDC hdc ) - { -- struct x11drv_escape_flush_gl_drawable escape; -+ struct x11drv_escape_present_drawable escape; - struct gl_drawable *gl; - struct wgl_context *ctx = NtCurrentTeb()->glContext; - INT64 ust, msc, sbc, target_sbc = 0; - - TRACE("(%p)\n", hdc); - -- escape.code = X11DRV_FLUSH_GL_DRAWABLE; -- escape.gl_drawable = 0; -+ escape.code = X11DRV_PRESENT_DRAWABLE; -+ escape.drawable = 0; - escape.flush = !pglXWaitForSbcOML; - - if (!(gl = get_gl_drawable( WindowFromDC( hdc ), hdc ))) -@@ -3333,7 +3333,7 @@ static BOOL WINAPI glxdrv_wglSwapBuffers( HDC hdc ) - { - case DC_GL_PIXMAP_WIN: - if (ctx) sync_context( ctx ); -- escape.gl_drawable = gl->pixmap; -+ escape.drawable = gl->pixmap; - if (pglXCopySubBufferMESA) { - /* (glX)SwapBuffers has an implicit glFlush effect, however - * GLX_MESA_copy_sub_buffer doesn't. Make sure GL is flushed before -@@ -3354,10 +3354,10 @@ static BOOL WINAPI glxdrv_wglSwapBuffers( HDC hdc ) - case DC_GL_WINDOW: - case DC_GL_CHILD_WIN: - if (ctx) sync_context( ctx ); -- if (gl->type == DC_GL_CHILD_WIN) escape.gl_drawable = gl->window; -+ if (gl->type == DC_GL_CHILD_WIN) escape.drawable = gl->window; - /* fall through */ - default: -- if (escape.gl_drawable && pglXSwapBuffersMscOML) -+ if (escape.drawable && pglXSwapBuffersMscOML) - { - pglFlush(); - target_sbc = pglXSwapBuffersMscOML( gdi_display, gl->drawable, 0, 0, 0 ); -@@ -3367,12 +3367,12 @@ static BOOL WINAPI glxdrv_wglSwapBuffers( HDC hdc ) - break; - } - -- if (escape.gl_drawable && pglXWaitForSbcOML) -+ if (escape.drawable && pglXWaitForSbcOML) - pglXWaitForSbcOML( gdi_display, gl->drawable, target_sbc, &ust, &msc, &sbc ); - - release_gl_drawable( gl ); - -- if (escape.gl_drawable) ExtEscape( ctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); -+ if (escape.drawable) ExtEscape( ctx->hdc, X11DRV_ESCAPE, sizeof(escape), (LPSTR)&escape, 0, NULL ); - return TRUE; - } - -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index f389f3e0836..33b2fc485ef 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -291,7 +291,7 @@ enum x11drv_escape_codes - X11DRV_SET_DRAWABLE, /* set current drawable for a DC */ - X11DRV_START_EXPOSURES, /* start graphics exposures */ - X11DRV_END_EXPOSURES, /* end graphics exposures */ -- X11DRV_FLUSH_GL_DRAWABLE, /* flush changes made to the gl drawable */ -+ X11DRV_PRESENT_DRAWABLE, /* present the drawable on screen */ - X11DRV_FLUSH_GDI_DISPLAY /* flush the gdi display */ - }; - -@@ -357,10 +357,10 @@ struct x11drv_escape_get_drawable - int pixel_format; /* internal GL pixel format */ - }; - --struct x11drv_escape_flush_gl_drawable -+struct x11drv_escape_present_drawable - { -- enum x11drv_escape_codes code; /* escape code (X11DRV_FLUSH_GL_DRAWABLE) */ -- Drawable gl_drawable; /* GL drawable */ -+ enum x11drv_escape_codes code; /* escape code (X11DRV_PRESENT_DRAWABLE) */ -+ Drawable drawable; /* GL / VK drawable */ - BOOL flush; /* flush X11 before copying */ - }; - -From 6e57f48457f8df1d67a894a7497b1d70d43f784f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 22 Oct 2021 00:30:19 +0200 -Subject: [PATCH] winex11.drv: Support child window vulkan rendering. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Based on a patch from Felix Hädicke . -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/vulkan.c | 90 +++++++++++++++++++++++++++++++++++---- - dlls/winex11.drv/window.c | 15 +++++++ - dlls/winex11.drv/x11drv.h | 1 + - 3 files changed, 97 insertions(+), 9 deletions(-) - -diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c -index c844ad35bb3..d702105c64b 100644 ---- a/dlls/winex11.drv/vulkan.c -+++ b/dlls/winex11.drv/vulkan.c -@@ -32,6 +32,7 @@ - #include "wine/debug.h" - #include "wine/heap.h" - #include "x11drv.h" -+#include "xcomposite.h" - - #define VK_NO_PROTOTYPES - #define WINE_VK_HOST -@@ -66,6 +67,8 @@ struct wine_vk_surface - struct list entry; - Window window; - VkSurfaceKHR surface; /* native surface */ -+ BOOL offscreen; /* drawable is offscreen */ -+ HDC hdc; - HWND hwnd; - DWORD hwnd_thread_id; - }; -@@ -231,15 +234,54 @@ static void wine_vk_surface_release(struct wine_vk_surface *surface) - void wine_vk_surface_destroy(HWND hwnd) - { - struct wine_vk_surface *surface; -+ HDC hdc = 0; -+ - EnterCriticalSection(&context_section); - if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) - { -+ hdc = surface->hdc; - surface->hwnd_thread_id = 0; -- surface->hwnd = NULL; -+ surface->hwnd = 0; -+ surface->hdc = 0; - wine_vk_surface_release(surface); - } - XDeleteContext(gdi_display, (XID)hwnd, vulkan_hwnd_context); - LeaveCriticalSection(&context_section); -+ if (hdc) ReleaseDC(hwnd, hdc); -+} -+ -+static BOOL wine_vk_surface_set_offscreen(struct wine_vk_surface *surface, BOOL offscreen) -+{ -+#ifdef SONAME_LIBXCOMPOSITE -+ if (usexcomposite) -+ { -+ if (!surface->offscreen && offscreen) -+ { -+ FIXME("Redirecting vulkan surface offscreen, expect degraded performance.\n"); -+ pXCompositeRedirectWindow(gdi_display, surface->window, CompositeRedirectManual); -+ } -+ else if (surface->offscreen && !offscreen) -+ { -+ FIXME("Putting vulkan surface back onscreen, expect standard performance.\n"); -+ pXCompositeUnredirectWindow(gdi_display, surface->window, CompositeRedirectManual); -+ } -+ surface->offscreen = offscreen; -+ return TRUE; -+ } -+#endif -+ -+ if (offscreen) FIXME("Application requires child window rendering, which is not implemented yet!\n"); -+ surface->offscreen = offscreen; -+ return !offscreen; -+} -+ -+void sync_vk_surface(HWND hwnd, BOOL known_child) -+{ -+ struct wine_vk_surface *surface; -+ EnterCriticalSection(&context_section); -+ if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface)) -+ wine_vk_surface_set_offscreen(surface, known_child); -+ LeaveCriticalSection(&context_section); - } - - void vulkan_thread_detach(void) -@@ -299,7 +341,30 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, - VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, - VkFence fence, uint32_t *image_index) - { -- return pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); -+ struct x11drv_escape_present_drawable escape; -+ struct wine_vk_surface *surface = NULL; -+ VkResult result; -+ HDC hdc = 0; -+ -+ EnterCriticalSection(&context_section); -+ if (!XFindContext(gdi_display, (XID)swapchain, vulkan_swapchain_context, (char **)&surface)) -+ { -+ wine_vk_surface_grab(surface); -+ hdc = surface->hdc; -+ } -+ LeaveCriticalSection(&context_section); -+ -+ result = pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); -+ if (result == VK_SUCCESS && hdc && surface && surface->offscreen) -+ { -+ escape.code = X11DRV_PRESENT_DRAWABLE; -+ escape.drawable = surface->window; -+ escape.flush = TRUE; -+ ExtEscape(hdc, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL); -+ } -+ -+ if (surface) wine_vk_surface_release(surface); -+ return result; - } - - static VkResult X11DRV_vkAcquireNextImage2KHR(VkDevice device, -@@ -358,13 +423,6 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, - if (allocator) - FIXME("Support for allocation callbacks not implemented yet\n"); - -- /* TODO: support child window rendering. */ -- if (create_info->hwnd && GetAncestor(create_info->hwnd, GA_PARENT) != GetDesktopWindow()) -- { -- FIXME("Application requires child window rendering, which is not implemented yet!\n"); -- return VK_ERROR_INCOMPATIBLE_DRIVER; -- } -- - x11_surface = heap_alloc_zero(sizeof(*x11_surface)); - if (!x11_surface) - return VK_ERROR_OUT_OF_HOST_MEMORY; -@@ -373,6 +431,7 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, - x11_surface->hwnd = create_info->hwnd; - if (x11_surface->hwnd) - { -+ x11_surface->hdc = GetDC(create_info->hwnd); - x11_surface->window = create_client_window(create_info->hwnd, &default_visual); - x11_surface->hwnd_thread_id = GetWindowThreadProcessId(x11_surface->hwnd, NULL); - } -@@ -390,6 +449,15 @@ static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance, - goto err; - } - -+ if (create_info->hwnd && (GetWindow( create_info->hwnd, GW_CHILD ) || GetAncestor( create_info->hwnd, GA_PARENT ) != GetDesktopWindow())) -+ { -+ if (!wine_vk_surface_set_offscreen(x11_surface, TRUE)) -+ { -+ res = VK_ERROR_INCOMPATIBLE_DRIVER; -+ goto err; -+ } -+ } -+ - create_info_host.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - create_info_host.pNext = NULL; - create_info_host.flags = 0; /* reserved */ -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 916350c685a..77c5d4ea480 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1741,6 +1741,15 @@ void CDECL X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) - { - struct x11drv_win_data *data; - DWORD changed = style->styleNew ^ style->styleOld; -+ HWND parent = GetAncestor( hwnd, GA_PARENT ); -+ -+ if (offset == GWL_STYLE && (changed & WS_CHILD)) -+ { -+ if (GetWindow( parent, GW_CHILD ) || GetAncestor( parent, GA_PARENT ) != GetDesktopWindow()) -+ sync_vk_surface( parent, TRUE ); -+ else -+ sync_vk_surface( parent, FALSE ); -+ } - - if (hwnd == GetDesktopWindow()) return; - if (!(data = get_win_data( hwnd ))) return; -@@ -1767,6 +1776,10 @@ void CDECL X11DRV_DestroyWindow( HWND hwnd ) - { - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - struct x11drv_win_data *data; -+ HWND parent = GetAncestor( hwnd, GA_PARENT ); -+ -+ if (!GetWindow( parent, GW_CHILD ) && GetAncestor( parent, GA_PARENT ) == GetDesktopWindow()) -+ sync_vk_surface( parent, FALSE ); - - if (!(data = get_win_data( hwnd ))) return; - -@@ -1980,6 +1993,7 @@ static struct x11drv_win_data *X11DRV_create_win_data( HWND hwnd, const RECT *wi - * that will need clipping support. - */ - sync_gl_drawable( parent, TRUE ); -+ sync_vk_surface( parent, TRUE ); - - display = thread_init_display(); - init_clip_window(); /* make sure the clip window is initialized in this thread */ -@@ -2318,6 +2332,7 @@ void CDECL X11DRV_SetParent( HWND hwnd, HWND parent, HWND old_parent ) - * that will need clipping support. - */ - sync_gl_drawable( parent, TRUE ); -+ sync_vk_surface( parent, TRUE ); - - fetch_icon_data( hwnd, 0, 0 ); - } -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 33b2fc485ef..9c8def1b068 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -646,6 +646,7 @@ extern void sync_gl_drawable( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; - extern void set_gl_drawable_parent( HWND hwnd, HWND parent ) DECLSPEC_HIDDEN; - extern void destroy_gl_drawable( HWND hwnd ) DECLSPEC_HIDDEN; - extern void wine_vk_surface_destroy( HWND hwnd ) DECLSPEC_HIDDEN; -+extern void sync_vk_surface( HWND hwnd, BOOL known_child ) DECLSPEC_HIDDEN; - extern void vulkan_thread_detach(void) DECLSPEC_HIDDEN; - - extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN; - -From 15cf1fe27d3431e6c77d7de0e3f04809198d2572 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 22 Oct 2021 00:49:09 +0200 -Subject: [PATCH] winex11.drv: Wait on vkAcquireNextImageKHR before flushing. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -To prevent tearing, when present mode is mailbox or fifo. - -Based on a patch from Felix Hädicke . -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/vulkan.c | 35 +++++++++++++++++++++++++++++++++++ - 1 file changed, 35 insertions(+) - -diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c -index d702105c64b..1a077d9323e 100644 ---- a/dlls/winex11.drv/vulkan.c -+++ b/dlls/winex11.drv/vulkan.c -@@ -67,6 +67,7 @@ struct wine_vk_surface - struct list entry; - Window window; - VkSurfaceKHR surface; /* native surface */ -+ VkPresentModeKHR present_mode; - BOOL offscreen; /* drawable is offscreen */ - HDC hdc; - HWND hwnd; -@@ -103,6 +104,9 @@ static VkResult (*pvkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint3 - static VkBool32 (*pvkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice, uint32_t, Display *, VisualID); - static VkResult (*pvkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *); - static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *); -+static VkResult (*pvkWaitForFences)(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout); -+static VkResult (*pvkCreateFence)(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence); -+static void (*pvkDestroyFence)(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator); - - static void *X11DRV_get_vk_device_proc_addr(const char *name); - static void *X11DRV_get_vk_instance_proc_addr(VkInstance instance, const char *name); -@@ -145,6 +149,9 @@ static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context) - LOAD_FUNCPTR(vkQueuePresentKHR); - LOAD_OPTIONAL_FUNCPTR(vkGetDeviceGroupSurfacePresentModesKHR); - LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDevicePresentRectanglesKHR); -+ LOAD_FUNCPTR(vkWaitForFences); -+ LOAD_FUNCPTR(vkCreateFence); -+ LOAD_FUNCPTR(vkDestroyFence); - #undef LOAD_FUNCPTR - #undef LOAD_OPTIONAL_FUNCPTR - -@@ -341,9 +348,12 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, - VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, - VkFence fence, uint32_t *image_index) - { -+ static int once; - struct x11drv_escape_present_drawable escape; - struct wine_vk_surface *surface = NULL; - VkResult result; -+ VkFence orig_fence; -+ BOOL wait_fence = FALSE; - HDC hdc = 0; - - EnterCriticalSection(&context_section); -@@ -354,15 +364,35 @@ static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, - } - LeaveCriticalSection(&context_section); - -+ if (!surface || !surface->offscreen) -+ wait_fence = FALSE; -+ else if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR || -+ surface->present_mode == VK_PRESENT_MODE_FIFO_KHR) -+ wait_fence = TRUE; -+ -+ orig_fence = fence; -+ if (wait_fence && !fence) -+ { -+ VkFenceCreateInfo create_info; -+ create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; -+ create_info.pNext = NULL; -+ create_info.flags = 0; -+ pvkCreateFence(device, &create_info, NULL, &fence); -+ } -+ - result = pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, image_index); - if (result == VK_SUCCESS && hdc && surface && surface->offscreen) - { -+ if (wait_fence) pvkWaitForFences(device, 1, &fence, 0, timeout); - escape.code = X11DRV_PRESENT_DRAWABLE; - escape.drawable = surface->window; - escape.flush = TRUE; - ExtEscape(hdc, X11DRV_ESCAPE, sizeof(escape), (char *)&escape, 0, NULL); -+ if (surface->present_mode == VK_PRESENT_MODE_MAILBOX_KHR) -+ if (once++) FIXME("Application requires child window rendering with mailbox present mode, expect possible tearing!\n"); - } - -+ if (fence != orig_fence) pvkDestroyFence(device, fence, NULL); - if (surface) wine_vk_surface_release(surface); - return result; - } -@@ -400,6 +430,11 @@ static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device, - create_info_host = *create_info; - create_info_host.surface = x11_surface->surface; - -+ /* force fifo when running offscreen so the acquire fence is more likely to be vsynced */ -+ if (x11_surface->offscreen && create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR) -+ create_info_host.presentMode = VK_PRESENT_MODE_FIFO_KHR; -+ x11_surface->present_mode = create_info->presentMode; -+ - result = pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain); - if (result == VK_SUCCESS) - { -From 96b82203f192eade6910f4ac2ecb188e27d22feb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 11 Mar 2021 23:27:57 +0100 -Subject: [PATCH] winex11.drv: Remove unused X11DRV_GET_DRAWABLE ExtEscape - code. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/init.c | 8 -------- - dlls/winex11.drv/x11drv.h | 9 --------- - 2 files changed, 17 deletions(-) - -diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c -index 0e8d2ffbf9e..8f152eedc69 100644 ---- a/dlls/winex11.drv/init.c -+++ b/dlls/winex11.drv/init.c -@@ -222,14 +222,6 @@ static INT CDECL X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOI - return TRUE; - } - break; -- case X11DRV_GET_DRAWABLE: -- if (out_count >= sizeof(struct x11drv_escape_get_drawable)) -- { -- struct x11drv_escape_get_drawable *data = out_data; -- data->drawable = physDev->drawable; -- return TRUE; -- } -- break; - case X11DRV_PRESENT_DRAWABLE: - if (in_count >= sizeof(struct x11drv_escape_present_drawable)) - { -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 9c8def1b068..dd7b9be0524 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -335,7 +335,6 @@ extern int *get_window_surface_mapping( int bpp, int *mapping ) DECLSPEC_HIDDEN; - enum x11drv_escape_codes - { - X11DRV_SET_DRAWABLE, /* set current drawable for a DC */ -- X11DRV_GET_DRAWABLE, /* get current drawable for a DC */ - X11DRV_START_EXPOSURES, /* start graphics exposures */ - X11DRV_END_EXPOSURES, /* end graphics exposures */ - X11DRV_PRESENT_DRAWABLE, /* present the drawable on screen */ -@@ -349,14 +348,6 @@ struct x11drv_escape_set_drawable - RECT dc_rect; /* DC rectangle relative to drawable */ - }; - --struct x11drv_escape_get_drawable --{ -- enum x11drv_escape_codes code; /* escape code (X11DRV_GET_DRAWABLE) */ -- Drawable drawable; /* X drawable */ -- Drawable gl_drawable; /* GL drawable */ -- int pixel_format; /* internal GL pixel format */ --}; -- - struct x11drv_escape_present_drawable - { - enum x11drv_escape_codes code; /* escape code (X11DRV_PRESENT_DRAWABLE) */ -From f06b97c57d0abd9ab25289d3ccce12737beef51a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 12 Mar 2021 00:10:49 +0100 -Subject: [PATCH] winex11.drv: Move Xfixes extension query to process_attach. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45277 -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/clipboard.c | 26 ++------------ - dlls/winex11.drv/x11drv.h | 2 ++ - dlls/winex11.drv/x11drv_main.c | 63 ++++++++++++++++++++++++++++++++++ - dlls/winex11.drv/xfixes.h | 36 +++++++++++++++++++ - 4 files changed, 103 insertions(+), 24 deletions(-) - create mode 100644 dlls/winex11.drv/xfixes.h - -diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c -index a13d0a55b76..7953ae5d925 100644 ---- a/dlls/winex11.drv/clipboard.c -+++ b/dlls/winex11.drv/clipboard.c -@@ -77,6 +77,7 @@ - #include - - #include "x11drv.h" -+#include "xfixes.h" - - #ifdef HAVE_X11_EXTENSIONS_XFIXES_H - #include -@@ -196,7 +197,6 @@ static UINT rendered_formats; - static ULONG64 last_clipboard_update; - static struct clipboard_format **current_x11_formats; - static unsigned int nb_current_x11_formats; --static BOOL use_xfixes; - - Display *clipboard_display = NULL; - -@@ -1975,28 +1975,6 @@ static BOOL selection_notify_event( HWND hwnd, XEvent *event ) - static void xfixes_init(void) - { - #ifdef SONAME_LIBXFIXES -- typeof(XFixesSelectSelectionInput) *pXFixesSelectSelectionInput; -- typeof(XFixesQueryExtension) *pXFixesQueryExtension; -- typeof(XFixesQueryVersion) *pXFixesQueryVersion; -- -- int event_base, error_base; -- int major = 3, minor = 0; -- void *handle; -- -- handle = dlopen(SONAME_LIBXFIXES, RTLD_NOW); -- if (!handle) return; -- -- pXFixesQueryExtension = dlsym(handle, "XFixesQueryExtension"); -- if (!pXFixesQueryExtension) return; -- pXFixesQueryVersion = dlsym(handle, "XFixesQueryVersion"); -- if (!pXFixesQueryVersion) return; -- pXFixesSelectSelectionInput = dlsym(handle, "XFixesSelectSelectionInput"); -- if (!pXFixesSelectSelectionInput) return; -- -- if (!pXFixesQueryExtension(clipboard_display, &event_base, &error_base)) -- return; -- pXFixesQueryVersion(clipboard_display, &major, &minor); -- use_xfixes = (major >= 1); - if (!use_xfixes) return; - - pXFixesSelectSelectionInput(clipboard_display, import_window, x11drv_atom(CLIPBOARD), -@@ -2010,7 +1988,7 @@ static void xfixes_init(void) - XFixesSelectionWindowDestroyNotifyMask | - XFixesSelectionClientCloseNotifyMask); - } -- X11DRV_register_event_handler(event_base + XFixesSelectionNotify, -+ X11DRV_register_event_handler(xfixes_event_base + XFixesSelectionNotify, - selection_notify_event, "XFixesSelectionNotify"); - TRACE("xfixes succesully initialized\n"); - #else -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index dd7b9be0524..8dc74aa2e39 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -435,6 +435,7 @@ extern BOOL show_systray DECLSPEC_HIDDEN; - extern BOOL grab_pointer DECLSPEC_HIDDEN; - extern BOOL grab_fullscreen DECLSPEC_HIDDEN; - extern BOOL usexcomposite DECLSPEC_HIDDEN; -+extern BOOL use_xfixes DECLSPEC_HIDDEN; - extern BOOL managed_mode DECLSPEC_HIDDEN; - extern BOOL decorated_mode DECLSPEC_HIDDEN; - extern BOOL private_color_map DECLSPEC_HIDDEN; -@@ -442,6 +443,7 @@ extern int primary_monitor DECLSPEC_HIDDEN; - extern int copy_default_colors DECLSPEC_HIDDEN; - extern int alloc_system_colors DECLSPEC_HIDDEN; - extern int xrender_error_base DECLSPEC_HIDDEN; -+extern int xfixes_event_base DECLSPEC_HIDDEN; - extern HMODULE x11drv_module DECLSPEC_HIDDEN; - extern char *process_name DECLSPEC_HIDDEN; - extern Display *clipboard_display DECLSPEC_HIDDEN; -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 32beb84a009..bf5cbaf7ef9 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -46,6 +46,7 @@ - - #include "x11drv.h" - #include "xcomposite.h" -+#include "xfixes.h" - #include "wine/server.h" - #include "wine/unicode.h" - #include "wine/debug.h" -@@ -65,6 +66,7 @@ Window root_window; - BOOL usexvidmode = TRUE; - BOOL usexrandr = TRUE; - BOOL usexcomposite = TRUE; -+BOOL use_xfixes = FALSE; - BOOL use_xkb = TRUE; - BOOL use_take_focus = TRUE; - BOOL use_primary_selection = FALSE; -@@ -83,6 +85,7 @@ int copy_default_colors = 128; - int alloc_system_colors = 256; - DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES; - int xrender_error_base = 0; -+int xfixes_event_base = 0; - HMODULE x11drv_module = 0; - char *process_name = NULL; - -@@ -510,6 +513,63 @@ static void X11DRV_XComposite_Init(void) - } - #endif /* defined(SONAME_LIBXCOMPOSITE) */ - -+#ifdef SONAME_LIBXFIXES -+ -+#define MAKE_FUNCPTR(f) typeof(f) * p##f; -+MAKE_FUNCPTR(XFixesQueryExtension) -+MAKE_FUNCPTR(XFixesQueryVersion) -+MAKE_FUNCPTR(XFixesCreateRegion) -+MAKE_FUNCPTR(XFixesCreateRegionFromGC) -+MAKE_FUNCPTR(XFixesSelectSelectionInput) -+#undef MAKE_FUNCPTR -+ -+static void x11drv_load_xfixes(void) -+{ -+ int event, error, major = 3, minor = 0; -+ void *xfixes; -+ -+ if (!(xfixes = dlopen(SONAME_LIBXFIXES, RTLD_NOW))) -+ { -+ WARN("Xfixes library %s not found, disabled.\n", SONAME_LIBXFIXES); -+ return; -+ } -+ -+#define LOAD_FUNCPTR(f) \ -+ if (!(p##f = dlsym(xfixes, #f))) \ -+ { \ -+ WARN("Xfixes function %s not found, disabled\n", #f); \ -+ dlclose(xfixes); \ -+ return; \ -+ } -+ LOAD_FUNCPTR(XFixesQueryExtension) -+ LOAD_FUNCPTR(XFixesQueryVersion) -+ LOAD_FUNCPTR(XFixesCreateRegion) -+ LOAD_FUNCPTR(XFixesCreateRegionFromGC) -+ LOAD_FUNCPTR(XFixesSelectSelectionInput) -+#undef LOAD_FUNCPTR -+ -+ if (!pXFixesQueryExtension(gdi_display, &event, &error)) -+ { -+ WARN("Xfixes extension not found, disabled.\n"); -+ dlclose(xfixes); -+ return; -+ } -+ -+ if (!pXFixesQueryVersion(gdi_display, &major, &minor) || -+ major < 2) -+ { -+ WARN("Xfixes version 2.0 not found, disabled.\n"); -+ dlclose(xfixes); -+ return; -+ } -+ -+ TRACE("Xfixes, error %d, event %d, version %d.%d found\n", -+ error, event, major, minor); -+ use_xfixes = TRUE; -+ xfixes_event_base = event; -+} -+#endif /* SONAME_LIBXFIXES */ -+ - static void init_visuals( Display *display, int screen ) - { - int count; -@@ -616,6 +676,9 @@ static BOOL process_attach(void) - X11DRV_XF86VM_Init(); - /* initialize XRandR */ - X11DRV_XRandR_Init(); -+#ifdef SONAME_LIBXFIXES -+ x11drv_load_xfixes(); -+#endif - #ifdef SONAME_LIBXCOMPOSITE - X11DRV_XComposite_Init(); - #endif -diff --git a/dlls/winex11.drv/xfixes.h b/dlls/winex11.drv/xfixes.h -new file mode 100644 -index 00000000000..3ab31201d3d ---- /dev/null -+++ b/dlls/winex11.drv/xfixes.h -@@ -0,0 +1,36 @@ -+/* -+ * Wine X11DRV Xfixes interface -+ * -+ * 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 -+ */ -+#ifndef __WINE_XFIXES_H -+#define __WINE_XFIXES_H -+ -+#ifndef __WINE_CONFIG_H -+# error You must include config.h to use this header -+#endif -+ -+#ifdef SONAME_LIBXFIXES -+#include -+#define MAKE_FUNCPTR(f) extern typeof(f) * p##f DECLSPEC_HIDDEN; -+MAKE_FUNCPTR(XFixesQueryExtension) -+MAKE_FUNCPTR(XFixesQueryVersion) -+MAKE_FUNCPTR(XFixesSelectSelectionInput) -+#undef MAKE_FUNCPTR -+#endif /* defined(SONAME_LIBXFIXES) */ -+ -+#endif /* __WINE_XFIXES_H */ diff --git a/patches/proton/fshack/03-window-manager-fixes.patch b/patches/proton/fshack/03-window-manager-fixes.patch deleted file mode 100644 index 37f518942..000000000 --- a/patches/proton/fshack/03-window-manager-fixes.patch +++ /dev/null @@ -1,1346 +0,0 @@ -From a412390af147ece7fb1fb6c381fc6822cbc44915 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 30 Jan 2020 14:44:00 -0600 -Subject: [PATCH] HACK: user32: Don't resize new windows to fit the display. - ---- - dlls/user32/win.c | 4 ++-- - dlls/user32/winpos.c | 2 -- - 2 files changed, 2 insertions(+), 4 deletions(-) - -diff --git a/dlls/user32/win.c b/dlls/user32/win.c -index 4f1f70d9802..0783daee5d9 100644 ---- a/dlls/user32/win.c -+++ b/dlls/user32/win.c -@@ -1739,8 +1739,8 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, - if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) - { - MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd ); -- cx = max( min( cx, info.ptMaxTrackSize.x ), info.ptMinTrackSize.x ); -- cy = max( min( cy, info.ptMaxTrackSize.y ), info.ptMinTrackSize.y ); -+ cx = max( cx, info.ptMinTrackSize.x ); -+ cy = max( cy, info.ptMinTrackSize.y ); - } - - if (cx < 0) cx = 0; -diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c -index ff23206b395..e03f1149914 100644 ---- a/dlls/user32/winpos.c -+++ b/dlls/user32/winpos.c -@@ -1663,8 +1663,6 @@ LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos ) - if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0)) - { - MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd ); -- winpos->cx = min( winpos->cx, info.ptMaxTrackSize.x ); -- winpos->cy = min( winpos->cy, info.ptMaxTrackSize.y ); - if (!(style & WS_MINIMIZE)) - { - winpos->cx = max( winpos->cx, info.ptMinTrackSize.x ); -From 728e589b581520fc430bcdbaca9ee618a2c873df Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 26 Feb 2021 08:59:56 -0600 -Subject: [PATCH] HACK: winex11.drv: Add WM detection code. - ---- - dlls/winex11.drv/window.c | 78 ++++++++++++++++++++++++++++++++++ - dlls/winex11.drv/x11drv.h | 6 +++ - dlls/winex11.drv/x11drv_main.c | 4 ++ - include/wine/gdi_driver.h | 18 ++++++++ - 4 files changed, 106 insertions(+) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index f76e020323a..99d8fd3871e 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -106,6 +106,82 @@ static CRITICAL_SECTION_DEBUG critsect_debug = - static CRITICAL_SECTION win_data_section = { &critsect_debug, -1, 0, 0, 0, 0 }; - - -+static int detect_wm(Display *dpy) -+{ -+ Display *display = dpy ? dpy : thread_init_display(); /* DefaultRootWindow is a macro... */ -+ Window root = DefaultRootWindow(display), *wm_check; -+ Atom type; -+ int format; -+ unsigned long count, remaining; -+ char *wm_name; -+ -+ static int cached = -1; -+ -+ if(cached < 0){ -+ -+ if (XGetWindowProperty( display, root, x11drv_atom(_NET_SUPPORTING_WM_CHECK), 0, -+ sizeof(*wm_check)/sizeof(CARD32), False, x11drv_atom(WINDOW), -+ &type, &format, &count, &remaining, (unsigned char **)&wm_check ) == Success){ -+ if (type == x11drv_atom(WINDOW)){ -+ if(XGetWindowProperty( display, *wm_check, x11drv_atom(_NET_WM_NAME), 0, -+ 256/sizeof(CARD32), False, x11drv_atom(UTF8_STRING), -+ &type, &format, &count, &remaining, (unsigned char **)&wm_name) == Success && -+ type == x11drv_atom(UTF8_STRING)){ -+ /* noop */ -+ }else if(XGetWindowProperty( display, *wm_check, x11drv_atom(WM_NAME), 0, -+ 256/sizeof(CARD32), False, x11drv_atom(STRING), -+ &type, &format, &count, &remaining, (unsigned char **)&wm_name) == Success && -+ type == x11drv_atom(STRING)){ -+ /* noop */ -+ }else -+ wm_name = NULL; -+ -+ if(wm_name){ -+ TRACE("Got WM name %s\n", wm_name); -+ -+ if((strcmp(wm_name, "GNOME Shell") == 0) || -+ (strcmp(wm_name, "Mutter") == 0)) -+ cached = WINE_WM_X11_MUTTER; -+ else if(strcmp(wm_name, "steamcompmgr") == 0) -+ cached = WINE_WM_X11_STEAMCOMPMGR; -+ else if(strcmp(wm_name, "KWin") == 0) -+ cached = WINE_WM_X11_KDE; -+ else -+ cached = WINE_WM_UNKNOWN; -+ -+ XFree(wm_name); -+ }else{ -+ TRACE("WM did not set _NET_WM_NAME or WM_NAME\n"); -+ cached = WINE_WM_UNKNOWN; -+ } -+ }else -+ cached = WINE_WM_UNKNOWN; -+ -+ XFree(wm_check); -+ }else -+ cached = WINE_WM_UNKNOWN; -+ -+ __wine_set_window_manager(cached); -+ } -+ -+ return cached; -+} -+ -+BOOL wm_is_mutter(Display *display) -+{ -+ return detect_wm(display) == WINE_WM_X11_MUTTER; -+} -+ -+BOOL wm_is_kde(Display *display) -+{ -+ return detect_wm(display) == WINE_WM_X11_KDE; -+} -+ -+BOOL wm_is_steamcompmgr(Display *display) -+{ -+ return detect_wm(display) == WINE_WM_X11_STEAMCOMPMGR; -+} -+ - /*********************************************************************** - * http://standards.freedesktop.org/startup-notification-spec - */ -@@ -1843,6 +1919,8 @@ BOOL CDECL X11DRV_CreateDesktopWindow( HWND hwnd ) - { - unsigned int width, height; - -+ detect_wm( gdi_display ); -+ - /* retrieve the real size of the desktop */ - SERVER_START_REQ( get_window_rectangles ) - { -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 4e6dcceb441..91cb02b902e 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -462,6 +462,7 @@ enum x11drv_atoms - XATOM_TEXT, - XATOM_TIMESTAMP, - XATOM_UTF8_STRING, -+ XATOM_STRING, - XATOM_RAW_ASCENT, - XATOM_RAW_DESCENT, - XATOM_RAW_CAP_HEIGHT, -@@ -469,6 +470,7 @@ enum x11drv_atoms - XATOM_Rel_Y, - XATOM_WM_PROTOCOLS, - XATOM_WM_DELETE_WINDOW, -+ XATOM_WM_NAME, - XATOM_WM_STATE, - XATOM_WM_TAKE_FOCUS, - XATOM_DndProtocol, -@@ -478,6 +480,7 @@ enum x11drv_atoms - XATOM__NET_STARTUP_INFO_BEGIN, - XATOM__NET_STARTUP_INFO, - XATOM__NET_SUPPORTED, -+ XATOM__NET_SUPPORTING_WM_CHECK, - XATOM__NET_SYSTEM_TRAY_OPCODE, - XATOM__NET_SYSTEM_TRAY_S0, - XATOM__NET_SYSTEM_TRAY_VISUAL, -@@ -528,6 +531,7 @@ enum x11drv_atoms - XATOM_WCF_SYLK, - XATOM_WCF_TIFF, - XATOM_WCF_WAVE, -+ XATOM_WINDOW, - XATOM_image_bmp, - XATOM_image_gif, - XATOM_image_jpeg, -@@ -654,6 +658,8 @@ extern void change_systray_owner( Display *display, Window systray_window ) DECL - extern void update_systray_balloon_position(void) DECLSPEC_HIDDEN; - extern HWND create_foreign_window( Display *display, Window window ) DECLSPEC_HIDDEN; - extern BOOL update_clipboard( HWND hwnd ) DECLSPEC_HIDDEN; -+extern BOOL wm_is_mutter(Display *) DECLSPEC_HIDDEN; -+extern BOOL wm_is_steamcompmgr(Display *) DECLSPEC_HIDDEN; - - static inline void mirror_rect( const RECT *window_rect, RECT *rect ) - { -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 6bf4a0a4211..c979f968877 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -146,6 +146,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "TEXT", - "TIMESTAMP", - "UTF8_STRING", -+ "STRING", - "RAW_ASCENT", - "RAW_DESCENT", - "RAW_CAP_HEIGHT", -@@ -153,6 +154,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "Rel Y", - "WM_PROTOCOLS", - "WM_DELETE_WINDOW", -+ "WM_NAME", - "WM_STATE", - "WM_TAKE_FOCUS", - "DndProtocol", -@@ -162,6 +164,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "_NET_STARTUP_INFO_BEGIN", - "_NET_STARTUP_INFO", - "_NET_SUPPORTED", -+ "_NET_SUPPORTING_WM_CHECK", - "_NET_SYSTEM_TRAY_OPCODE", - "_NET_SYSTEM_TRAY_S0", - "_NET_SYSTEM_TRAY_VISUAL", -@@ -212,6 +215,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "WCF_SYLK", - "WCF_TIFF", - "WCF_WAVE", -+ "WINDOW", - "image/bmp", - "image/gif", - "image/jpeg", -diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h -index 567a6c21608..7e0135430e1 100644 ---- a/include/wine/gdi_driver.h -+++ b/include/wine/gdi_driver.h -@@ -349,4 +349,22 @@ extern void CDECL __wine_set_display_driver( struct user_driver_funcs *funcs, UI - extern struct opengl_funcs * CDECL __wine_get_wgl_driver( HDC hdc, UINT version ); - extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver( UINT version ); - -+/* HACK: We use some WM specific hacks in user32 and we need the user -+ * driver to export that information. */ -+ -+#define WINE_WM_UNKNOWN 0 -+#define WINE_WM_X11_MUTTER 1 -+#define WINE_WM_X11_STEAMCOMPMGR 2 -+#define WINE_WM_X11_KDE 3 -+ -+static inline LONG_PTR __wine_get_window_manager(void) -+{ -+ return (LONG_PTR)GetPropA(GetDesktopWindow(), "__wine_window_manager"); -+} -+ -+static inline void __wine_set_window_manager(LONG_PTR window_manager) -+{ -+ SetPropA(GetDesktopWindow(), "__wine_window_manager", (HANDLE)window_manager); -+} -+ - #endif /* __WINE_WINE_GDI_DRIVER_H */ - -From 376cf4fd52c091b39b1373c4fc42d56b0c755512 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 12 Mar 2020 15:53:07 +0100 -Subject: [PATCH] HACK: gamescope: user32: On steamcompmgr, don't limit window - size to screen size - ---- - dlls/user32/win.c | 10 ++++++++++ - dlls/user32/winpos.c | 10 ++++++++++ - 2 files changed, 20 insertions(+) - -diff --git a/dlls/user32/win.c b/dlls/user32/win.c -index 0783daee5d9..4618c73d95f 100644 ---- a/dlls/user32/win.c -+++ b/dlls/user32/win.c -@@ -1739,6 +1739,16 @@ HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, - if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) - { - MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd ); -+ -+ /* HACK: This code changes the window's size to fit the display. However, -+ * some games (Bayonetta, Dragon's Dogma) will then have the incorrect -+ * render size. So just let windows be too big to fit the display. */ -+ if (__wine_get_window_manager() != WINE_WM_X11_STEAMCOMPMGR) -+ { -+ cx = min( cx, info.ptMaxTrackSize.x ); -+ cy = min( cy, info.ptMaxTrackSize.y ); -+ } -+ - cx = max( cx, info.ptMinTrackSize.x ); - cy = max( cy, info.ptMinTrackSize.y ); - } -diff --git a/dlls/user32/winpos.c b/dlls/user32/winpos.c -index e03f1149914..c5ecffa561c 100644 ---- a/dlls/user32/winpos.c -+++ b/dlls/user32/winpos.c -@@ -1663,6 +1663,16 @@ LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos ) - if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0)) - { - MINMAXINFO info = WINPOS_GetMinMaxInfo( hwnd ); -+ -+ /* HACK: This code changes the window's size to fit the display. However, -+ * some games (Bayonetta, Dragon's Dogma) will then have the incorrect -+ * render size. So just let windows be too big to fit the display. */ -+ if (__wine_get_window_manager() != WINE_WM_X11_STEAMCOMPMGR) -+ { -+ winpos->cx = min( winpos->cx, info.ptMaxTrackSize.x ); -+ winpos->cy = min( winpos->cy, info.ptMaxTrackSize.y ); -+ } -+ - if (!(style & WS_MINIMIZE)) - { - winpos->cx = max( winpos->cx, info.ptMinTrackSize.x ); -From 8e7dcb8367325d91cfa2b7d6bd5e4495cda71889 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 16 Mar 2020 19:52:52 +0100 -Subject: [PATCH] HACK: gamescope: user32: Pretend that windows are undecorated - with gamescope. - -The original commit made all window have their client rect always match -their window rects. This was to make sure games always use the full -available window size, even when windowed, and end up with an optimal -rendering area. - -Some games, such as Bayonetta or Dragon's Dogma: Dark Arisen, ask for an -optimal window size, but, when in windowed mode, the client rect is then -adjusted to add a title bar and borders. On Windows, the back buffer is -always the requested size, but the rendering is then scaled to match the -client rect. With Proton and gamescope, we want to avoid this suboptimal -scaling, and make sure both front and back buffer are optimally sized, -including when in windowed mode. - -Then, we still need to keep adjustments on WS_POPUP / WS_EX_TOOLWINDOW -windows: - -This styles usually translates into a single pixel border, and is used -for splash screens. Several of them do not expect their client rect to -be sized as the window rect and it causes a visible 1px white border on -the bottom and the right of the window. - -WS_EX_TOOLWINDOW should be safe enough, as it means the window is not -supposed to be displayed in the taskbar or in the alt-tab menu, which is -unlikely for an actual game window. WS_POPUP otoh means that only a 1px -border is used, which should not make much of a difference with an -undecorated window (although it could cause suboptimal client rect -sizes, which we wanted to solve in the first place). - -CW-Bug-Id: #17639 -CW-Bug-Id: #20038 ---- - dlls/user32/nonclient.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/dlls/user32/nonclient.c b/dlls/user32/nonclient.c -index b47616bb639..ff9f9b8e197 100644 ---- a/dlls/user32/nonclient.c -+++ b/dlls/user32/nonclient.c -@@ -28,6 +28,7 @@ - #include "user_private.h" - #include "controls.h" - #include "wine/debug.h" -+#include "wine/gdi_driver.h" - - WINE_DEFAULT_DEBUG_CHANNEL(nonclient); - -@@ -60,6 +61,9 @@ static void adjust_window_rect( RECT *rect, DWORD style, BOOL menu, DWORD exStyl - { - int adjust = 0; - -+ if (__wine_get_window_manager() == WINE_WM_X11_STEAMCOMPMGR && !((style & WS_POPUP) && (exStyle & WS_EX_TOOLWINDOW))) -+ return; -+ - if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) - adjust = 1; /* for the outer frame always present */ - else if ((exStyle & WS_EX_DLGMODALFRAME) || (style & (WS_THICKFRAME|WS_DLGFRAME))) -@@ -357,6 +361,9 @@ LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect ) - if (winRect == NULL) - return 0; - -+ if (__wine_get_window_manager() == WINE_WM_X11_STEAMCOMPMGR && !((style & WS_POPUP) && (exStyle & WS_EX_TOOLWINDOW))) -+ return 0; -+ - if (!(style & WS_MINIMIZE)) - { - -From 132d293262d95a5ab8810ebbda13028fac2e9f78 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 28 May 2021 17:41:43 +0200 -Subject: [PATCH] HACK: gamescope: winex11.drv: Disable gamescope hacks for - Street Fighter V. - -CW-Bug-Id: #18903 ---- - dlls/winex11.drv/window.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 99d8fd3871e..01b12f96e03 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -114,6 +114,7 @@ static int detect_wm(Display *dpy) - int format; - unsigned long count, remaining; - char *wm_name; -+ char const *sgi = getenv("SteamGameId"); - - static int cached = -1; - -@@ -161,6 +162,11 @@ static int detect_wm(Display *dpy) - }else - cached = WINE_WM_UNKNOWN; - -+ /* Street Fighter V expects a certain sequence of window resizes -+ or gets stuck on startup. The AdjustWindowRect / WM_NCCALCSIZE -+ hacks confuse it completely, so let's disable them */ -+ if (sgi && !strcmp(sgi, "310950")) cached = WINE_WM_UNKNOWN; -+ - __wine_set_window_manager(cached); - } - -From 7563c241f385299b4639c3b939558c2ba430886e Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 18 Sep 2018 14:48:58 -0500 -Subject: [PATCH] winex11.drv: Allow the application to change window size and - states during PropertyNotify. - -On focus loss, fullscreened DDLC changes to a 1x1 pixel window and -minimizes. On restore, it un-minimizes and changes back to fullscreen -size. However, this restoring happens during the PropertyNotify handler, -which means we didn't update size or the NET_WM_STATEs. ---- - dlls/winex11.drv/window.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 01b12f96e03..294d84bfccc 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -2615,7 +2615,7 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags - } - - /* don't change position if we are about to minimize or maximize a managed window */ -- if (!event_type && -+ if ((!event_type || event_type == PropertyNotify) && - !(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) - sync_window_position( data, swp_flags, &old_window_rect, &old_whole_rect, &old_client_rect ); - -@@ -2649,7 +2649,7 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags - else - { - if (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)) set_wm_hints( data ); -- if (!event_type) update_net_wm_states( data ); -+ if (!event_type || event_type == PropertyNotify) update_net_wm_states( data ); - } - } - -From 32821e17a97f4e0afb703eaf17280cadb8030a16 Mon Sep 17 00:00:00 2001 -From: Alexey Prokhin -Date: Wed, 17 Oct 2018 19:55:27 +0300 -Subject: [PATCH] winex11.drv: Ignore clip_reset when trying to clip the mouse - after the desktop has been resized. - -This fixes the mouse clipping when the desktop is resized multiple times in a row. ---- - dlls/winex11.drv/mouse.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index d02163cbaa8..d2ff071a9f2 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -579,9 +579,10 @@ BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) - release_win_data( data ); - if (!fullscreen) return FALSE; - if (!(thread_data = x11drv_thread_data())) return FALSE; -- if (GetTickCount() - thread_data->clip_reset < 1000) return FALSE; -- if (!reset && clipping_cursor && thread_data->clip_hwnd) return FALSE; /* already clipping */ -- -+ if (!reset) { -+ if (GetTickCount() - thread_data->clip_reset < 1000) return FALSE; -+ if (!reset && clipping_cursor && thread_data->clip_hwnd) return FALSE; /* already clipping */ -+ } - monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ); - if (!monitor) return FALSE; - monitor_info.cbSize = sizeof(monitor_info); -From 36535de250f26fbfd46c6383179e4c9bfe2ce956 Mon Sep 17 00:00:00 2001 -From: Alexey Prokhin -Date: Sat, 20 Oct 2018 18:07:12 +0300 -Subject: [PATCH] winex11.drv: Enable fullscreen clipping even if not already - clipping. - ---- - dlls/winex11.drv/mouse.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index d2ff071a9f2..9635d264e14 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -1571,12 +1571,12 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) - { - if (grab_clipping_window( clip )) return TRUE; - } -- else /* if currently clipping, check if we should switch to fullscreen clipping */ -+ else /* check if we should switch to fullscreen clipping */ - { - struct x11drv_thread_data *data = x11drv_thread_data(); -- if (data && data->clip_hwnd) -+ if (data) - { -- if (EqualRect( clip, &clip_rect ) || clip_fullscreen_window( foreground, TRUE )) -+ if ((data->clip_hwnd && EqualRect( clip, &clip_rect ) && !EqualRect(&clip_rect, &virtual_rect)) || clip_fullscreen_window( foreground, TRUE )) - return TRUE; - } - } -From 3ebc519f891b4fe027e1161bebdcfd4eeed7c079 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 11 Jan 2019 11:31:13 -0600 -Subject: [PATCH] winex11.drv: Don't show border if WS_CAPTION is unset. - -Into the Breach wants a borderless window with WS_THICKFRAME. If we -leave the BORDER and RESIZEH styles on, then we get a window with a -border and a caption on Linux. ---- - dlls/winex11.drv/window.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 294d84bfccc..319a28d6fa3 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -414,7 +414,10 @@ static unsigned long get_mwm_decorations( struct x11drv_win_data *data, - if (style & WS_MAXIMIZEBOX) ret |= MWM_DECOR_MAXIMIZE; - } - if (ex_style & WS_EX_DLGMODALFRAME) ret |= MWM_DECOR_BORDER; -- else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH; -+ else if (style & WS_THICKFRAME){ -+ if((style & WS_CAPTION) == WS_CAPTION) -+ ret |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH; -+ } - else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) ret |= MWM_DECOR_BORDER; - return ret; - } -From 24d7f2bda1e98905206476fa3664ea8fa7bd7dd1 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Fri, 11 Jan 2019 11:34:03 -0600 -Subject: [PATCH] winex11.drv: Ignore ConfigureNotify messages if there is a - FULLSCREEN WM state pending. - -Into the Breach goes fullscreen by first maximizing, then setting the -window to fullscreen in a separate call. Mutter processes the maximize -request _after_ Wine has sent the fullscreen request. As a result, we -get a ConfigureNotify for the size of the workspace when we expect the -window to be fullscreened. We then notify ITB that it is no longer -fullscreen, which begins the process over again, causing an infinite -loop. - -This fixes that by setting a flag if we have a fullscreen request -pending and ignoring ConfigureNotify requests if it is set. We unset it -when we receive a _NET_WM_STATE PropertyNotify event that contains the -FULLSCREEN flag. ---- - dlls/winex11.drv/event.c | 35 +++++++++++++++++++++++++++++++++++ - dlls/winex11.drv/window.c | 3 +++ - dlls/winex11.drv/x11drv.h | 1 + - 3 files changed, 39 insertions(+) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index b7f5614f222..42c66f911ce 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -1129,6 +1129,12 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) - event->serial, data->configure_serial ); - goto done; - } -+ if (data->pending_fullscreen) -+ { -+ TRACE( "win %p/%lx event %d,%d,%dx%d pending_fullscreen is pending, so ignoring\n", -+ hwnd, data->whole_window, event->x, event->y, event->width, event->height ); -+ goto done; -+ } - - /* Get geometry */ - -@@ -1362,15 +1368,44 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat - } - - -+static void handle__net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) -+{ -+ struct x11drv_win_data *data = get_win_data( hwnd ); -+ -+ if(data->pending_fullscreen) -+ { -+ read_net_wm_states( event->display, data ); -+ if(data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)){ -+ data->pending_fullscreen = FALSE; -+ TRACE("PropertyNotify _NET_WM_STATE, now 0x%x, pending_fullscreen no longer pending.\n", -+ data->net_wm_state); -+ }else -+ TRACE("PropertyNotify _NET_WM_STATE, now 0x%x, pending_fullscreen still pending.\n", -+ data->net_wm_state); -+ } -+ -+ release_win_data( data ); -+} -+ -+ - /*********************************************************************** - * X11DRV_PropertyNotify - */ - static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) - { - XPropertyEvent *event = &xev->xproperty; -+ char *name; - - if (!hwnd) return FALSE; -+ -+ name = XGetAtomName(event->display, event->atom); -+ if(name){ -+ TRACE("win %p PropertyNotify atom: %s, state: 0x%x\n", hwnd, name, event->state); -+ XFree(name); -+ } -+ - if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE ); -+ else if (event->atom == x11drv_atom(_NET_WM_STATE)) handle__net_wm_state_notify( hwnd, event ); - return TRUE; - } - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 319a28d6fa3..1d42801291c 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1260,6 +1260,7 @@ static void unmap_window( HWND hwnd ) - - data->mapped = FALSE; - data->net_wm_state = 0; -+ data->pending_fullscreen = FALSE; - } - release_win_data( data ); - } -@@ -1276,6 +1277,7 @@ void make_window_embedded( struct x11drv_win_data *data ) - if (!data->managed) XUnmapWindow( data->display, data->whole_window ); - else XWithdrawWindow( data->display, data->whole_window, data->vis.screen ); - data->net_wm_state = 0; -+ data->pending_fullscreen = FALSE; - } - data->embedded = TRUE; - data->managed = TRUE; -@@ -1759,6 +1761,7 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des - data->whole_colormap = 0; - data->wm_state = WithdrawnState; - data->net_wm_state = 0; -+ data->pending_fullscreen = FALSE; - data->mapped = FALSE; - if (data->xic) - { -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 91cb02b902e..9767fdcf681 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -621,6 +621,7 @@ struct x11drv_win_data - BOOL use_alpha : 1; /* does window use an alpha channel? */ - BOOL skip_taskbar : 1; /* does window should be deleted from taskbar */ - BOOL add_taskbar : 1; /* does window should be added to taskbar regardless of style */ -+ BOOL pending_fullscreen : 1; - int wm_state; /* current value of the WM_STATE property */ - DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ - Window embedder; /* window id of embedder */ -From c00373fafc69068a300e44a188b4a139ab274abb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 21 Jan 2020 21:05:05 +0100 -Subject: [PATCH] winex11.drv: Ignore ClipCursor if desktop window is - foreground. - ---- - dlls/winex11.drv/mouse.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 9635d264e14..321b631d6ca 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -1556,6 +1556,13 @@ BOOL CDECL X11DRV_ClipCursor( LPCRECT clip ) - HWND foreground = GetForegroundWindow(); - DWORD tid, pid; - -+ if (foreground == GetDesktopWindow()) -+ { -+ WARN( "desktop is foreground, ignoring ClipCursor\n" ); -+ ungrab_clipping_window(); -+ return TRUE; -+ } -+ - /* forward request to the foreground window if it's in a different thread */ - tid = GetWindowThreadProcessId( foreground, &pid ); - if (tid && tid != GetCurrentThreadId() && pid == GetCurrentProcessId()) -From b036845239c5b01f3715ef0d3b24e5044137836c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 26 Jun 2019 18:42:37 +0200 -Subject: [PATCH] HACK: mutter: winex11.drv: Workaround mutter issue #649. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When decorations are modified too quickly, mutter loses tracks of the -reparenting requests and does not gives focus back to the window. - -Signed-off-by: Rémi Bernon ---- - dlls/winex11.drv/window.c | 43 ++++++++++++++++++++++++++++++++++++++- - dlls/winex11.drv/x11drv.h | 4 ++++ - 2 files changed, 46 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 1d42801291c..1b292df11fe 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -48,7 +48,6 @@ - #include "x11drv.h" - #include "wine/debug.h" - #include "wine/server.h" --#include "mwm.h" - - WINE_DEFAULT_DEBUG_CHANNEL(x11drv); - -@@ -814,6 +813,13 @@ static void set_size_hints( struct x11drv_win_data *data, DWORD style ) - XFree( size_hints ); - } - -+static Bool is_unmap_notify( Display *display, XEvent *event, XPointer arg ) -+{ -+ struct x11drv_win_data *data = (struct x11drv_win_data *)arg; -+ return event->xany.serial >= data->unmapnotify_serial && -+ event->xany.window == data->whole_window && -+ event->type == UnmapNotify; -+} - - /*********************************************************************** - * set_mwm_hints -@@ -821,6 +827,7 @@ static void set_size_hints( struct x11drv_win_data *data, DWORD style ) - static void set_mwm_hints( struct x11drv_win_data *data, DWORD style, DWORD ex_style ) - { - MwmHints mwm_hints; -+ int enable_mutter_workaround, mapped; - - if (data->hwnd == GetDesktopWindow()) - { -@@ -848,12 +855,46 @@ static void set_mwm_hints( struct x11drv_win_data *data, DWORD style, DWORD ex_s - TRACE( "%p setting mwm hints to %lx,%lx (style %x exstyle %x)\n", - data->hwnd, mwm_hints.decorations, mwm_hints.functions, style, ex_style ); - -+ enable_mutter_workaround = wm_is_mutter(data->display) && GetFocus() == data->hwnd && -+ !!data->prev_hints.decorations != !!mwm_hints.decorations && -+ root_window == DefaultRootWindow(data->display); -+ -+ /* workaround for mutter gitlab bug #649, we cannot trust the -+ * data->mapped flag as mapping is asynchronous. -+ */ -+ if (enable_mutter_workaround) -+ { -+ XWindowAttributes attr; -+ -+ mapped = data->mapped; -+ if (XGetWindowAttributes( data->display, data->whole_window, &attr )) -+ mapped = (attr.map_state != IsUnmapped); -+ } -+ - mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; - mwm_hints.input_mode = 0; - mwm_hints.status = 0; -+ data->unmapnotify_serial = NextRequest( data->display ); - XChangeProperty( data->display, data->whole_window, x11drv_atom(_MOTIF_WM_HINTS), - x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace, - (unsigned char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) ); -+ -+ if (enable_mutter_workaround) -+ { -+ XEvent event; -+ -+ /* workaround for mutter gitlab bug #649, wait for the map notify -+ * event each time the decorations are modified before modifying -+ * them again. -+ */ -+ if (mapped) -+ { -+ TRACE("workaround mutter bug #649, waiting for UnmapNotify\n"); -+ XPeekIfEvent( data->display, &event, is_unmap_notify, (XPointer)data ); -+ } -+ } -+ -+ data->prev_hints = mwm_hints; - } - - -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 9767fdcf681..bd8492c57b7 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -62,6 +62,8 @@ typedef int Status; - #include "wine/gdi_driver.h" - #include "wine/list.h" - -+#include "mwm.h" -+ - #define MAX_DASHLEN 16 - - #define WINE_XDND_VERSION 5 -@@ -625,12 +627,14 @@ struct x11drv_win_data - int wm_state; /* current value of the WM_STATE property */ - DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ - Window embedder; /* window id of embedder */ -+ unsigned long unmapnotify_serial; /* serial number of last UnmapNotify event */ - unsigned long configure_serial; /* serial number of last configure request */ - struct window_surface *surface; - Pixmap icon_pixmap; - Pixmap icon_mask; - unsigned long *icon_bits; - unsigned int icon_size; -+ MwmHints prev_hints; - }; - - extern struct x11drv_win_data *get_win_data( HWND hwnd ) DECLSPEC_HIDDEN; -From fd82e3a50b586a6c1d05246b3ceb86cb00b59d9e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 24 Jul 2019 11:34:15 +0200 -Subject: [PATCH] HACK: mutter: winex11.drv: Workaround mutter issue #676. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Changing decorations of a fullscreen and unredirected window breaks -compositing. So, we now ignore any decoration changes while window is -bypassing the compositor. - -Decoration state will be restored as soon as the window changes its -state again. The windows are only bypassing compositor if they are also -fullscreen, so this should not have any visible side effect. - -Signed-off-by: Rémi Bernon ---- - dlls/winex11.drv/event.c | 13 +++++++++++++ - dlls/winex11.drv/window.c | 29 ++++++++++++++++++++++++++++- - dlls/winex11.drv/x11drv.h | 3 +++ - dlls/winex11.drv/x11drv_main.c | 1 + - 4 files changed, 45 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 42c66f911ce..f29e1bd7d1f 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -1404,6 +1404,19 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) - XFree(name); - } - -+ if (event->atom == x11drv_atom(_NET_WM_BYPASS_COMPOSITOR)) -+ { -+ struct x11drv_win_data *data = get_win_data( hwnd ); -+ if (!data) return TRUE; -+ -+ /* workaround for mutter gitlab bug #676, changing decorations of a -+ * fullscreen and unredirected window freezes the compositing. -+ */ -+ if (wm_is_mutter( data->display )) set_wm_hints( data ); -+ -+ release_win_data( data ); -+ } -+ - if (event->atom == x11drv_atom(WM_STATE)) handle_wm_state_notify( hwnd, event, TRUE ); - else if (event->atom == x11drv_atom(_NET_WM_STATE)) handle__net_wm_state_notify( hwnd, event ); - return TRUE; -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 1b292df11fe..2c3a9c32bc6 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -829,6 +829,33 @@ static void set_mwm_hints( struct x11drv_win_data *data, DWORD style, DWORD ex_s - MwmHints mwm_hints; - int enable_mutter_workaround, mapped; - -+ /* workaround for mutter gitlab bug #676, changing decorations of a -+ * fullscreen and unredirected window freezes the compositing. -+ * The window style will be updated again once the window has returned -+ * from fullscreen. -+ */ -+ if (wm_is_mutter(data->display) && (data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN))) -+ { -+ Atom type; -+ int format; -+ unsigned long *property, net_wm_bypass_compositor = 0, count, remaining; -+ -+ if (XGetWindowProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_BYPASS_COMPOSITOR), 0, -+ 1, False, XA_CARDINAL, &type, &format, &count, &remaining, -+ (unsigned char **)&property ) == Success && -+ property) -+ { -+ net_wm_bypass_compositor = *property; -+ XFree(property); -+ } -+ -+ if (net_wm_bypass_compositor) -+ { -+ TRACE("workaround mutter bug, ignoring decorations while compositor is bypassed\n"); -+ return; -+ } -+ } -+ - if (data->hwnd == GetDesktopWindow()) - { - if (is_desktop_fullscreen()) mwm_hints.decorations = 0; -@@ -1040,7 +1067,7 @@ static void make_owner_managed( HWND hwnd ) - * - * Set all the window manager hints for a window. - */ --static void set_wm_hints( struct x11drv_win_data *data ) -+void set_wm_hints( struct x11drv_win_data *data ) - { - DWORD style, ex_style; - -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index bd8492c57b7..86d44997f43 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -486,6 +486,7 @@ enum x11drv_atoms - XATOM__NET_SYSTEM_TRAY_OPCODE, - XATOM__NET_SYSTEM_TRAY_S0, - XATOM__NET_SYSTEM_TRAY_VISUAL, -+ XATOM__NET_WM_BYPASS_COMPOSITOR, - XATOM__NET_WM_ICON, - XATOM__NET_WM_MOVERESIZE, - XATOM__NET_WM_NAME, -@@ -666,6 +667,8 @@ extern BOOL update_clipboard( HWND hwnd ) DECLSPEC_HIDDEN; - extern BOOL wm_is_mutter(Display *) DECLSPEC_HIDDEN; - extern BOOL wm_is_steamcompmgr(Display *) DECLSPEC_HIDDEN; - -+extern void set_wm_hints( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; -+ - static inline void mirror_rect( const RECT *window_rect, RECT *rect ) - { - int width = window_rect->right - window_rect->left; -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index c979f968877..1e7c140641f 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -168,6 +168,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "_NET_SYSTEM_TRAY_OPCODE", - "_NET_SYSTEM_TRAY_S0", - "_NET_SYSTEM_TRAY_VISUAL", -+ "_NET_WM_BYPASS_COMPOSITOR", - "_NET_WM_ICON", - "_NET_WM_MOVERESIZE", - "_NET_WM_NAME", -From 27dd29bb185d04018493cdd2a025ff4961121769 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 9 Dec 2019 20:28:20 +0100 -Subject: [PATCH] HACK: mutter: winex11.drv: Add a bit of delay before - restoring mouse grabs on FocusIn. - ---- - dlls/winex11.drv/event.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index f29e1bd7d1f..77d2990f01e 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -821,6 +821,14 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - if (event->detail == NotifyPointer) return FALSE; - if (hwnd == GetDesktopWindow()) return FALSE; - -+ /* Focus was just restored but it can be right after super was -+ * pressed and gnome-shell needs a bit of time to respond and -+ * toggle the activity view. If we grab the cursor right away -+ * it will cancel it and super key will do nothing. -+ */ -+ if (event->mode == NotifyUngrab && wm_is_mutter(event->display)) -+ Sleep(100); -+ - /* ask the foreground window to re-apply the current ClipCursor rect */ - SendMessageW( GetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, 0, 0 ); - -From 985434fc5279470782763af3da1b4afec57d7ce0 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Tue, 21 Aug 2018 14:47:33 -0500 -Subject: [PATCH] HACK: mutter: winex11.drv: Workaround mutter issue #273. - -This would cause fullscreen windows to lose keyboard focus. ---- - dlls/winex11.drv/event.c | 18 ++++++++++++++++++ - dlls/winex11.drv/window.c | 8 ++++++++ - dlls/winex11.drv/x11drv.h | 1 + - 3 files changed, 27 insertions(+) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 77d2990f01e..b59d4105557 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -870,9 +870,27 @@ static void focus_out( Display *display , HWND hwnd ) - Window focus_win; - int revert; - XIC xic; -+ struct x11drv_win_data *data; - - if (ximInComposeMode) return; - -+ data = get_win_data(hwnd); -+ if(data){ -+ ULONGLONG now = GetTickCount64(); -+ if(data->take_focus_back > 0 && -+ now >= data->take_focus_back && -+ now - data->take_focus_back < 1000){ -+ data->take_focus_back = 0; -+ TRACE("workaround mutter bug, taking focus back\n"); -+ XSetInputFocus( data->display, data->whole_window, RevertToParent, CurrentTime); -+ release_win_data(data); -+ /* don't inform win32 client */ -+ return; -+ } -+ data->take_focus_back = 0; -+ release_win_data(data); -+ } -+ - x11drv_thread_data()->last_focus = hwnd; - if ((xic = X11DRV_get_ic( hwnd ))) XUnsetICFocus( xic ); - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 2c3a9c32bc6..45a45a29f1a 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -921,6 +921,14 @@ static void set_mwm_hints( struct x11drv_win_data *data, DWORD style, DWORD ex_s - } - } - -+ if (wm_is_mutter(data->display) && GetFocus() == data->hwnd && -+ !!data->prev_hints.decorations != !!mwm_hints.decorations) -+ { -+ /* workaround for mutter gitlab bug #273 */ -+ TRACE("workaround mutter bug, setting take_focus_back\n"); -+ data->take_focus_back = GetTickCount64(); -+ } -+ - data->prev_hints = mwm_hints; - } - -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 86d44997f43..52990283ce7 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -625,6 +625,7 @@ struct x11drv_win_data - BOOL skip_taskbar : 1; /* does window should be deleted from taskbar */ - BOOL add_taskbar : 1; /* does window should be added to taskbar regardless of style */ - BOOL pending_fullscreen : 1; -+ ULONGLONG take_focus_back; - int wm_state; /* current value of the WM_STATE property */ - DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ - Window embedder; /* window id of embedder */ -From d2c3166e776eb399cd6b9e94b6fc954591bebdc8 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Fri, 25 Sep 2020 12:58:52 +0300 -Subject: [PATCH] HACK: mutter: winex11.drv: Avoid setting empty shape for - window on mutter. - ---- - dlls/winex11.drv/bitblt.c | 17 +++++++++++++++-- - 1 file changed, 15 insertions(+), 2 deletions(-) - -diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c -index fad183b0b01..1254fff14bf 100644 ---- a/dlls/winex11.drv/bitblt.c -+++ b/dlls/winex11.drv/bitblt.c -@@ -1736,8 +1736,21 @@ static void update_surface_region( struct x11drv_window_surface *surface ) - - if ((data = X11DRV_GetRegionData( rgn, 0 ))) - { -- XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0, -- (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded ); -+ if (!data->rdh.nCount && wm_is_mutter(gdi_display)) -+ { -+ XRectangle xrect; -+ -+ xrect.x = xrect.y = -1; -+ xrect.width = 1; -+ xrect.height = 1; -+ XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0, -+ &xrect, 1, ShapeSet, YXBanded ); -+ } -+ else -+ { -+ XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0, -+ (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded ); -+ } - HeapFree( GetProcessHeap(), 0, data ); - } - -From 39000841d68b3d8401bd5602113fdc146fc1ee43 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Tue, 8 Jun 2021 16:01:54 +0300 -Subject: [PATCH] winex11.drv: Send missed KEYUP events on KeymapNotify. - -Full focus lost / focus gained events on the Windows side are not -feasible for X11's FocusIn/FocusOut events generated by keyboard grabs -(see XGrabKeyboard()) that are used for example for Atl+Tab handling. -Using them would degrade user's experience, especially with our full -screen hack, by causing the window to minimize or flash multiple times -depending on a game/window manager combo. - -Because of that the programs may miss on some KEYUP events that happen -during the grab, and since there are no focus changes on the Windows -side the state doesn't get resynced. - -This change attempts to improve user experience by syncing any missed -key release events that happened while the window haven't had focus on -the X11 side. - -There's no syncing of key presses as those are more problematic because -of window manager quirks, e.g. on KDE it may end up syncing the Tab -press portion of Alt+Tab. Luckily missing key events for keys that were -pressed and not released while the WM had the keyboard grab is not -nearly as confusing as stuck keys. - -For Warhammer: Chaosbane, theHunter: Call of the Wild, Far Cry Primal -and many other games that end up with stuck Alt after Alt+Tabbing. - -CW-Bug-ID: #17046 -CW-Bug-ID: #18904 ---- - dlls/winex11.drv/event.c | 2 ++ - dlls/winex11.drv/keyboard.c | 43 +++++++++++++++++++++++++++++++++++-- - dlls/winex11.drv/mouse.c | 2 ++ - dlls/winex11.drv/x11drv.h | 1 + - 4 files changed, 46 insertions(+), 2 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index b59d4105557..271a70940f1 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -821,6 +821,8 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev ) - if (event->detail == NotifyPointer) return FALSE; - if (hwnd == GetDesktopWindow()) return FALSE; - -+ x11drv_thread_data()->keymapnotify_hwnd = hwnd; -+ - /* Focus was just restored but it can be right after super was - * pressed and gnome-shell needs a bit of time to respond and - * toggle the activity view. If we grab the cursor right away -diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c -index d04d1db9102..720b4869544 100644 ---- a/dlls/winex11.drv/keyboard.c -+++ b/dlls/winex11.drv/keyboard.c -@@ -1209,11 +1209,19 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) - int i, j; - BYTE keystate[256]; - WORD vkey; -+ DWORD flags; -+ KeyCode keycode; -+ HWND keymapnotify_hwnd; - BOOL changed = FALSE; - struct { - WORD vkey; -+ WORD scan; - WORD pressed; - } keys[256]; -+ struct x11drv_thread_data *thread_data = x11drv_thread_data(); -+ -+ keymapnotify_hwnd = thread_data->keymapnotify_hwnd; -+ thread_data->keymapnotify_hwnd = NULL; - - if (!get_async_key_state( keystate )) return FALSE; - -@@ -1228,11 +1236,17 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) - { - for (j = 0; j < 8; j++) - { -- vkey = keyc2vkey[(i * 8) + j]; -+ keycode = (i * 8) + j; -+ vkey = keyc2vkey[keycode]; - - /* If multiple keys map to the same vkey, we want to report it as - * pressed iff any of them are pressed. */ -- if (!keys[vkey & 0xff].vkey) keys[vkey & 0xff].vkey = vkey; -+ if (!keys[vkey & 0xff].vkey) -+ { -+ keys[vkey & 0xff].vkey = vkey; -+ keys[vkey & 0xff].scan = keyc2scan[keycode] & 0xff; -+ } -+ - if (event->xkeymap.key_vector[i] & (1<window, event->x, event->y, event->detail ); - -+ x11drv_thread_data()->keymapnotify_hwnd = hwnd; -+ - if (event->detail == NotifyVirtual) return FALSE; - if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE; - -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 52990283ce7..213143014a7 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -369,6 +369,7 @@ struct x11drv_thread_data - XEvent *current_event; /* event currently being processed */ - HWND grab_hwnd; /* window that currently grabs the mouse */ - HWND last_focus; /* last window that had focus */ -+ HWND keymapnotify_hwnd; /* window that should receive modifier release events */ - XIM xim; /* input method */ - HWND last_xic_hwnd; /* last xic window */ - XFontSet font_set; /* international text drawing font set */ -From 695c72575c72161501a2ac508ba1db649e96d1dd Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Fri, 2 Jul 2021 16:01:28 +0300 -Subject: [PATCH] user32: Allow the backends to defer restoring minimized - windows. - -When restoring a minimized window the WM_SYSCOMMAND SC_RESTORE message -should arrive after WM_NCACTIVATE but before WM_ACTIVATE and WM_SETFOCUS. - -Some games depend on that ordering and the related window state. - -For example Project CARS 3 expects window to be both active and in the -foreground (wrt GetActiveWindow() and GetForegroundWindow()) when -receiving those messages. - -Without being active the window doesn't restore properly, see -82c6ec3a32f4 ("winex11.drv: Activate window when restoring from iconic state.") - -But if the activate messages arrive before the window is in the -foreground, the game tries to re-acquire DirectInput DISCL_FOREGROUND -devices too early and fails, which results in non-working keyboards and -controllers. - -CW-Bug-Id: #19011 ---- - dlls/user32/focus.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c -index 34cc3880cc9..2e1362eaff5 100644 ---- a/dlls/user32/focus.c -+++ b/dlls/user32/focus.c -@@ -164,6 +164,12 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) - (LPARAM)previous ); - if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow()) - PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd ); -+ -+ if (GetPropW( hwnd, L"__WINE_RESTORE_WINDOW" )) -+ { -+ SetPropW( hwnd, L"__WINE_RESTORE_WINDOW", NULL ); -+ SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); -+ } - } - - /* now change focus if necessary */ -From ed85dc3dd49a6aae8347dae8a3b4300713fc3f6d Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Fri, 2 Jul 2021 16:01:29 +0300 -Subject: [PATCH] winex11.drv: Use __WINE_RESTORE_PROPERTY so Window is - un-minimized on FocusIn. - -On X11 / XWayland the PropertyNotify for WM_STATE change from -IconicState to NormalState arrives before the WM_TAKE_FOCUS -ClientMessage or the FocusIn event. - -Converting that state change too early to a WM_SYSCOMMAND SC_RESTORE -message results in it (and the ACTIVATE events because of the previous -HAX) arriving without the window being set to foregrounds first. - -This breaks the expectations of Project CARS 3 which tries on window -activation / restoration to re-acquire DirectInput devices with -cooperative level set to DISCL_FOREGROUND, which fails. - -Signed-off-by: Arkadiusz Hiler - -CW-Bug-Id: #19011 ---- - dlls/winex11.drv/event.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 271a70940f1..3a903eebd7e 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -80,6 +80,8 @@ extern BOOL ximInComposeMode; - #define XEMBED_UNREGISTER_ACCELERATOR 13 - #define XEMBED_ACTIVATE_ACCELERATOR 14 - -+static const WCHAR restore_window_propW[] = {'_','_','W','I','N','E','_','R','E','S','T','O','R','E','_','W','I','N','D','O','W',0}; -+ - Bool (*pXGetEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL; - void (*pXFreeEventData)( Display *display, XEvent /*XGenericEventCookie*/ *event ) = NULL; - -@@ -586,7 +588,7 @@ static inline BOOL can_activate_window( HWND hwnd ) - - if (!(style & WS_VISIBLE)) return FALSE; - if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE; -- if (style & WS_MINIMIZE) return FALSE; -+ if ((style & WS_MINIMIZE) && !GetPropW( hwnd, restore_window_propW )) return FALSE; - if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOACTIVATE) return FALSE; - if (hwnd == GetDesktopWindow()) return FALSE; - if (GetWindowRect( hwnd, &rect ) && IsRectEmpty( &rect )) return FALSE; -@@ -1371,9 +1373,10 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat - { - TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window ); - release_win_data( data ); -- if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE)) -- SetActiveWindow( hwnd ); -- SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); -+ if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE) && GetActiveWindow() != hwnd) -+ SetPropW( hwnd, restore_window_propW, (HANDLE) TRUE ); -+ else -+ SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); - return; - } - TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style ); diff --git a/patches/proton/fshack/04-fullscreen-hack.patch b/patches/proton/fshack/04-fullscreen-hack.patch deleted file mode 100644 index 020965711..000000000 --- a/patches/proton/fshack/04-fullscreen-hack.patch +++ /dev/null @@ -1,7060 +0,0 @@ -From f7c3d6caddfa5f34f11a063021444389c697e8e8 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Sat, 11 Dec 2021 13:28:36 +0100 -Subject: [PATCH] winevulkan: Fullscreen hack - -Includes work by Georg Lehmann, Zhiyi Zhang, Brendan Shanks, and Joshua -Ashton. ---- - dlls/winevulkan/make_vulkan | 19 +- - dlls/winevulkan/vulkan.c | 1397 ++++++++++++++++++++++++++++++ - dlls/winevulkan/vulkan_private.h | 38 + - 3 files changed, 1449 insertions(+), 5 deletions(-) - -diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan -index 360b2087eb9..705a4a6e24e 100755 ---- a/dlls/winevulkan/make_vulkan -+++ b/dlls/winevulkan/make_vulkan -@@ -228,11 +228,11 @@ FUNCTION_OVERRIDES = { - - # VK_KHR_swapchain - "vkAcquireNextImageKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, -- "vkAcquireNextImage2KHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, -- "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, -- "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, -- "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, -- "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.PUBLIC}, -+ "vkAcquireNextImage2KHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, -+ "vkCreateSwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, -+ "vkDestroySwapchainKHR" : {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, -+ "vkGetSwapchainImagesKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, -+ "vkQueuePresentKHR": {"dispatch" : True, "driver" : True, "thunk" : ThunkType.NONE}, - - # VK_KHR_external_fence_capabilities - "vkGetPhysicalDeviceExternalFencePropertiesKHR" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, -@@ -1083,6 +1083,8 @@ class VkHandle(object): - def native_handle(self, name): - """ Provide access to the native handle of a wrapped object. """ - -+ if self.name == "VkSwapchainKHR": -+ return "((struct VkSwapchainKHR_T *)(uintptr_t) ({0}))->swapchain".format(name) - if self.name == "VkCommandPool": - return "wine_cmd_pool_from_handle({0})->command_pool".format(name) - if self.name == "VkDebugUtilsMessengerEXT": -@@ -2580,6 +2658,12 @@ class VkGenerator(object): - f.write("\n") - f.write(" /* winevulkan specific functions */\n") - f.write(" VkSurfaceKHR (*p_wine_get_native_surface)(VkSurfaceKHR);\n") -+ f.write("\n /* Optional. Returns TRUE if FS hack is active, otherwise returns FALSE. If\n") -+ f.write(" * it returns TRUE, then real_sz will contain the actual display\n") -+ f.write(" * resolution; user_sz will contain the app's requested mode; and dst_blit\n") -+ f.write(" * will contain the area to blit the user image to in real coordinates.\n") -+ f.write(" * All parameters are optional. */\n") -+ f.write(" VkBool32 (*query_fs_hack)(VkSurfaceKHR surface, VkExtent2D *real_sz, VkExtent2D *user_sz, VkRect2D *dst_blit, VkFilter *filter);\n") - f.write("};\n\n") - - f.write("extern const struct vulkan_funcs * CDECL __wine_get_vulkan_driver(HDC hdc, UINT version);\n\n") -diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c -index 9f12660a407..3c8bd452eca 100644 ---- a/dlls/winevulkan/vulkan.c -+++ b/dlls/winevulkan/vulkan.c -@@ -22,6 +22,7 @@ - #endif - - #include "config.h" -+#include - #include - #include - -@@ -1657,6 +1658,751 @@ NTSTATUS wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(void *args) - return STATUS_SUCCESS; - } - -+VkResult WINAPI wine_vkSetPrivateDataEXT(VkDevice device, VkObjectType object_type, uint64_t object_handle, -+ VkPrivateDataSlotEXT private_data_slot, uint64_t data) -+{ -+ TRACE("%p, %#x, 0x%s, 0x%s, 0x%s\n", device, object_type, wine_dbgstr_longlong(object_handle), -+ wine_dbgstr_longlong(private_data_slot), wine_dbgstr_longlong(data)); -+ -+ object_handle = wine_vk_unwrap_handle(object_type, object_handle); -+ return device->funcs.p_vkSetPrivateDataEXT(device->device, object_type, object_handle, private_data_slot, data); -+} -+ -+void WINAPI wine_vkGetPrivateDataEXT(VkDevice device, VkObjectType object_type, uint64_t object_handle, -+ VkPrivateDataSlotEXT private_data_slot, uint64_t *data) -+{ -+ TRACE("%p, %#x, 0x%s, 0x%s, %p\n", device, object_type, wine_dbgstr_longlong(object_handle), -+ wine_dbgstr_longlong(private_data_slot), data); -+ -+ object_handle = wine_vk_unwrap_handle(object_type, object_handle); -+ device->funcs.p_vkGetPrivateDataEXT(device->device, object_type, object_handle, private_data_slot, data); -+} -+ -+/* -+#version 450 -+ -+layout(binding = 0) uniform sampler2D texSampler; -+layout(binding = 1, rgba8) uniform writeonly image2D outImage; -+layout(push_constant) uniform pushConstants { -+ //both in real image coords -+ vec2 offset; -+ vec2 extents; -+} constants; -+ -+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; -+ -+void main() -+{ -+ vec2 texcoord = (vec2(gl_GlobalInvocationID.xy) - constants.offset) / constants.extents; -+ vec4 c = texture(texSampler, texcoord); -+ imageStore(outImage, ivec2(gl_GlobalInvocationID.xy), c.bgra); -+} -+*/ -+const uint32_t blit_comp_spv[] = { -+ 0x07230203,0x00010000,0x00080006,0x00000037,0x00000000,0x00020011,0x00000001,0x0006000b, -+ 0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,0x0003000e,0x00000000,0x00000001, -+ 0x0006000f,0x00000005,0x00000004,0x6e69616d,0x00000000,0x0000000d,0x00060010,0x00000004, -+ 0x00000011,0x00000008,0x00000008,0x00000001,0x00030003,0x00000002,0x000001c2,0x00040005, -+ 0x00000004,0x6e69616d,0x00000000,0x00050005,0x00000009,0x63786574,0x64726f6f,0x00000000, -+ 0x00080005,0x0000000d,0x475f6c67,0x61626f6c,0x766e496c,0x7461636f,0x496e6f69,0x00000044, -+ 0x00060005,0x00000012,0x68737570,0x736e6f43,0x746e6174,0x00000073,0x00050006,0x00000012, -+ 0x00000000,0x7366666f,0x00007465,0x00050006,0x00000012,0x00000001,0x65747865,0x0073746e, -+ 0x00050005,0x00000014,0x736e6f63,0x746e6174,0x00000073,0x00030005,0x00000021,0x00000063, -+ 0x00050005,0x00000025,0x53786574,0x6c706d61,0x00007265,0x00050005,0x0000002c,0x4974756f, -+ 0x6567616d,0x00000000,0x00040047,0x0000000d,0x0000000b,0x0000001c,0x00050048,0x00000012, -+ 0x00000000,0x00000023,0x00000000,0x00050048,0x00000012,0x00000001,0x00000023,0x00000008, -+ 0x00030047,0x00000012,0x00000002,0x00040047,0x00000025,0x00000022,0x00000000,0x00040047, -+ 0x00000025,0x00000021,0x00000000,0x00040047,0x0000002c,0x00000022,0x00000000,0x00040047, -+ 0x0000002c,0x00000021,0x00000001,0x00030047,0x0000002c,0x00000019,0x00040047,0x00000036, -+ 0x0000000b,0x00000019,0x00020013,0x00000002,0x00030021,0x00000003,0x00000002,0x00030016, -+ 0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000002,0x00040020,0x00000008, -+ 0x00000007,0x00000007,0x00040015,0x0000000a,0x00000020,0x00000000,0x00040017,0x0000000b, -+ 0x0000000a,0x00000003,0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c, -+ 0x0000000d,0x00000001,0x00040017,0x0000000e,0x0000000a,0x00000002,0x0004001e,0x00000012, -+ 0x00000007,0x00000007,0x00040020,0x00000013,0x00000009,0x00000012,0x0004003b,0x00000013, -+ 0x00000014,0x00000009,0x00040015,0x00000015,0x00000020,0x00000001,0x0004002b,0x00000015, -+ 0x00000016,0x00000000,0x00040020,0x00000017,0x00000009,0x00000007,0x0004002b,0x00000015, -+ 0x0000001b,0x00000001,0x00040017,0x0000001f,0x00000006,0x00000004,0x00040020,0x00000020, -+ 0x00000007,0x0000001f,0x00090019,0x00000022,0x00000006,0x00000001,0x00000000,0x00000000, -+ 0x00000000,0x00000001,0x00000000,0x0003001b,0x00000023,0x00000022,0x00040020,0x00000024, -+ 0x00000000,0x00000023,0x0004003b,0x00000024,0x00000025,0x00000000,0x0004002b,0x00000006, -+ 0x00000028,0x00000000,0x00090019,0x0000002a,0x00000006,0x00000001,0x00000000,0x00000000, -+ 0x00000000,0x00000002,0x00000004,0x00040020,0x0000002b,0x00000000,0x0000002a,0x0004003b, -+ 0x0000002b,0x0000002c,0x00000000,0x00040017,0x00000030,0x00000015,0x00000002,0x0004002b, -+ 0x0000000a,0x00000034,0x00000008,0x0004002b,0x0000000a,0x00000035,0x00000001,0x0006002c, -+ 0x0000000b,0x00000036,0x00000034,0x00000034,0x00000035,0x00050036,0x00000002,0x00000004, -+ 0x00000000,0x00000003,0x000200f8,0x00000005,0x0004003b,0x00000008,0x00000009,0x00000007, -+ 0x0004003b,0x00000020,0x00000021,0x00000007,0x0004003d,0x0000000b,0x0000000f,0x0000000d, -+ 0x0007004f,0x0000000e,0x00000010,0x0000000f,0x0000000f,0x00000000,0x00000001,0x00040070, -+ 0x00000007,0x00000011,0x00000010,0x00050041,0x00000017,0x00000018,0x00000014,0x00000016, -+ 0x0004003d,0x00000007,0x00000019,0x00000018,0x00050083,0x00000007,0x0000001a,0x00000011, -+ 0x00000019,0x00050041,0x00000017,0x0000001c,0x00000014,0x0000001b,0x0004003d,0x00000007, -+ 0x0000001d,0x0000001c,0x00050088,0x00000007,0x0000001e,0x0000001a,0x0000001d,0x0003003e, -+ 0x00000009,0x0000001e,0x0004003d,0x00000023,0x00000026,0x00000025,0x0004003d,0x00000007, -+ 0x00000027,0x00000009,0x00070058,0x0000001f,0x00000029,0x00000026,0x00000027,0x00000002, -+ 0x00000028,0x0003003e,0x00000021,0x00000029,0x0004003d,0x0000002a,0x0000002d,0x0000002c, -+ 0x0004003d,0x0000000b,0x0000002e,0x0000000d,0x0007004f,0x0000000e,0x0000002f,0x0000002e, -+ 0x0000002e,0x00000000,0x00000001,0x0004007c,0x00000030,0x00000031,0x0000002f,0x0004003d, -+ 0x0000001f,0x00000032,0x00000021,0x0009004f,0x0000001f,0x00000033,0x00000032,0x00000032, -+ 0x00000002,0x00000001,0x00000000,0x00000003,0x00040063,0x0000002d,0x00000031,0x00000033, -+ 0x000100fd,0x00010038 -+}; -+ -+static VkResult create_pipeline(VkDevice device, struct VkSwapchainKHR_T *swapchain, VkShaderModule shaderModule) -+{ -+ VkResult res; -+#if defined(USE_STRUCT_CONVERSION) -+ VkComputePipelineCreateInfo_host pipelineInfo = {0}; -+#else -+ VkComputePipelineCreateInfo pipelineInfo = {0}; -+#endif -+ -+ pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; -+ pipelineInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; -+ pipelineInfo.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT; -+ pipelineInfo.stage.module = shaderModule; -+ pipelineInfo.stage.pName = "main"; -+ pipelineInfo.layout = swapchain->pipeline_layout; -+ pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; -+ pipelineInfo.basePipelineIndex = -1; -+ -+ res = device->funcs.p_vkCreateComputePipelines(device->device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, &swapchain->pipeline); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreateComputePipelines: %d\n", res); -+ return res; -+ } -+ -+ return VK_SUCCESS; -+} -+ -+static VkResult create_descriptor_set(VkDevice device, struct VkSwapchainKHR_T *swapchain, struct fs_hack_image *hack) -+{ -+ VkResult res; -+#if defined(USE_STRUCT_CONVERSION) -+ VkDescriptorSetAllocateInfo_host descriptorAllocInfo = {0}; -+ VkWriteDescriptorSet_host descriptorWrites[2] = {{0}, {0}}; -+ VkDescriptorImageInfo_host userDescriptorImageInfo = {0}, realDescriptorImageInfo = {0}; -+#else -+ VkDescriptorSetAllocateInfo descriptorAllocInfo = {0}; -+ VkWriteDescriptorSet descriptorWrites[2] = {{0}, {0}}; -+ VkDescriptorImageInfo userDescriptorImageInfo = {0}, realDescriptorImageInfo = {0}; -+#endif -+ -+ descriptorAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; -+ descriptorAllocInfo.descriptorPool = swapchain->descriptor_pool; -+ descriptorAllocInfo.descriptorSetCount = 1; -+ descriptorAllocInfo.pSetLayouts = &swapchain->descriptor_set_layout; -+ -+ res = device->funcs.p_vkAllocateDescriptorSets(device->device, &descriptorAllocInfo, &hack->descriptor_set); -+ if(res != VK_SUCCESS){ -+ ERR("vkAllocateDescriptorSets: %d\n", res); -+ return res; -+ } -+ -+ userDescriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; -+ userDescriptorImageInfo.imageView = hack->user_view; -+ userDescriptorImageInfo.sampler = swapchain->sampler; -+ -+ realDescriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL; -+ realDescriptorImageInfo.imageView = hack->blit_view; -+ -+ descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; -+ descriptorWrites[0].dstSet = hack->descriptor_set; -+ descriptorWrites[0].dstBinding = 0; -+ descriptorWrites[0].dstArrayElement = 0; -+ descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; -+ descriptorWrites[0].descriptorCount = 1; -+ descriptorWrites[0].pImageInfo = &userDescriptorImageInfo; -+ -+ descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; -+ descriptorWrites[1].dstSet = hack->descriptor_set; -+ descriptorWrites[1].dstBinding = 1; -+ descriptorWrites[1].dstArrayElement = 0; -+ descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; -+ descriptorWrites[1].descriptorCount = 1; -+ descriptorWrites[1].pImageInfo = &realDescriptorImageInfo; -+ -+ device->funcs.p_vkUpdateDescriptorSets(device->device, 2, descriptorWrites, 0, NULL); -+ -+ return VK_SUCCESS; -+} -+ -+static VkResult init_blit_images(VkDevice device, struct VkSwapchainKHR_T *swapchain) -+{ -+ VkResult res; -+ VkSamplerCreateInfo samplerInfo = {0}; -+ VkDescriptorPoolSize poolSizes[2] = {{0}, {0}}; -+ VkDescriptorPoolCreateInfo poolInfo = {0}; -+ VkDescriptorSetLayoutBinding layoutBindings[2] = {{0}, {0}}; -+ VkDescriptorSetLayoutCreateInfo descriptorLayoutInfo = {0}; -+ VkPipelineLayoutCreateInfo pipelineLayoutInfo = {0}; -+ VkPushConstantRange pushConstants; -+ VkShaderModuleCreateInfo shaderInfo = {0}; -+ VkShaderModule shaderModule = 0; -+ VkDeviceSize blitMemTotal = 0, offs; -+ VkImageCreateInfo imageInfo = {0}; -+#if defined(USE_STRUCT_CONVERSION) -+ VkMemoryRequirements_host blitMemReq; -+ VkMemoryAllocateInfo_host allocInfo = {0}; -+ VkPhysicalDeviceMemoryProperties_host memProperties; -+ VkImageViewCreateInfo_host viewInfo = {0}; -+#else -+ VkMemoryRequirements blitMemReq; -+ VkMemoryAllocateInfo allocInfo = {0}; -+ VkPhysicalDeviceMemoryProperties memProperties; -+ VkImageViewCreateInfo viewInfo = {0}; -+#endif -+ uint32_t blit_memory_type = -1, i; -+ -+ samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; -+ samplerInfo.magFilter = swapchain->fs_hack_filter; -+ samplerInfo.minFilter = swapchain->fs_hack_filter; -+ samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; -+ samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; -+ samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; -+ samplerInfo.anisotropyEnable = VK_FALSE; -+ samplerInfo.maxAnisotropy = 1; -+ samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; -+ samplerInfo.unnormalizedCoordinates = VK_FALSE; -+ samplerInfo.compareEnable = VK_FALSE; -+ samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; -+ samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; -+ samplerInfo.mipLodBias = 0.0f; -+ samplerInfo.minLod = 0.0f; -+ samplerInfo.maxLod = 0.0f; -+ -+ res = device->funcs.p_vkCreateSampler(device->device, &samplerInfo, NULL, &swapchain->sampler); -+ if(res != VK_SUCCESS) -+ { -+ WARN("vkCreateSampler failed, res=%d\n", res); -+ return res; -+ } -+ -+ poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; -+ poolSizes[0].descriptorCount = swapchain->n_images; -+ poolSizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; -+ poolSizes[1].descriptorCount = swapchain->n_images; -+ -+ poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; -+ poolInfo.poolSizeCount = 2; -+ poolInfo.pPoolSizes = poolSizes; -+ poolInfo.maxSets = swapchain->n_images; -+ -+ res = device->funcs.p_vkCreateDescriptorPool(device->device, &poolInfo, NULL, &swapchain->descriptor_pool); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreateDescriptorPool: %d\n", res); -+ goto fail; -+ } -+ -+ layoutBindings[0].binding = 0; -+ layoutBindings[0].descriptorCount = 1; -+ layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; -+ layoutBindings[0].pImmutableSamplers = NULL; -+ layoutBindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; -+ -+ layoutBindings[1].binding = 1; -+ layoutBindings[1].descriptorCount = 1; -+ layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; -+ layoutBindings[1].pImmutableSamplers = NULL; -+ layoutBindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; -+ -+ descriptorLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; -+ descriptorLayoutInfo.bindingCount = 2; -+ descriptorLayoutInfo.pBindings = layoutBindings; -+ -+ res = device->funcs.p_vkCreateDescriptorSetLayout(device->device, &descriptorLayoutInfo, NULL, &swapchain->descriptor_set_layout); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreateDescriptorSetLayout: %d\n", res); -+ goto fail; -+ } -+ -+ pushConstants.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; -+ pushConstants.offset = 0; -+ pushConstants.size = 4 * sizeof(float); /* 2 * vec2 */ -+ -+ pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; -+ pipelineLayoutInfo.setLayoutCount = 1; -+ pipelineLayoutInfo.pSetLayouts = &swapchain->descriptor_set_layout; -+ pipelineLayoutInfo.pushConstantRangeCount = 1; -+ pipelineLayoutInfo.pPushConstantRanges = &pushConstants; -+ -+ res = device->funcs.p_vkCreatePipelineLayout(device->device, &pipelineLayoutInfo, NULL, &swapchain->pipeline_layout); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreatePipelineLayout: %d\n", res); -+ goto fail; -+ } -+ -+ shaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; -+ shaderInfo.codeSize = sizeof(blit_comp_spv); -+ shaderInfo.pCode = blit_comp_spv; -+ -+ res = device->funcs.p_vkCreateShaderModule(device->device, &shaderInfo, NULL, &shaderModule); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreateShaderModule: %d\n", res); -+ goto fail; -+ } -+ -+ res = create_pipeline(device, swapchain, shaderModule); -+ if(res != VK_SUCCESS) -+ goto fail; -+ -+ device->funcs.p_vkDestroyShaderModule(device->device, shaderModule, NULL); -+ -+ if(!(swapchain->surface_usage & VK_IMAGE_USAGE_STORAGE_BIT)){ -+ TRACE("using intermediate blit images\n"); -+ /* create intermediate blit images */ -+ for(i = 0; i < swapchain->n_images; ++i){ -+ struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; -+ -+ imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; -+ imageInfo.imageType = VK_IMAGE_TYPE_2D; -+ imageInfo.extent.width = swapchain->real_extent.width; -+ imageInfo.extent.height = swapchain->real_extent.height; -+ imageInfo.extent.depth = 1; -+ imageInfo.mipLevels = 1; -+ imageInfo.arrayLayers = 1; -+ imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; -+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; -+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ imageInfo.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; -+ imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; -+ imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; -+ res = device->funcs.p_vkCreateImage(device->device, &imageInfo, NULL, &hack->blit_image); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreateImage failed: %d\n", res); -+ goto fail; -+ } -+ -+ device->funcs.p_vkGetImageMemoryRequirements(device->device, hack->blit_image, &blitMemReq); -+ -+ offs = blitMemTotal % blitMemReq.alignment; -+ if(offs) -+ blitMemTotal += blitMemReq.alignment - offs; -+ -+ blitMemTotal += blitMemReq.size; -+ } -+ -+ /* allocate backing memory */ -+ device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties(device->phys_dev->phys_dev, &memProperties); -+ -+ for(i = 0; i < memProperties.memoryTypeCount; i++){ -+ if((memProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT){ -+ if(blitMemReq.memoryTypeBits & (1 << i)){ -+ blit_memory_type = i; -+ break; -+ } -+ } -+ } -+ -+ if(blit_memory_type == -1){ -+ ERR("unable to find suitable memory type\n"); -+ res = VK_ERROR_OUT_OF_HOST_MEMORY; -+ goto fail; -+ } -+ -+ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; -+ allocInfo.allocationSize = blitMemTotal; -+ allocInfo.memoryTypeIndex = blit_memory_type; -+ -+ res = device->funcs.p_vkAllocateMemory(device->device, &allocInfo, NULL, &swapchain->blit_image_memory); -+ if(res != VK_SUCCESS){ -+ ERR("vkAllocateMemory: %d\n", res); -+ goto fail; -+ } -+ -+ /* bind backing memory and create imageviews */ -+ blitMemTotal = 0; -+ for(i = 0; i < swapchain->n_images; ++i){ -+ struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; -+ -+ device->funcs.p_vkGetImageMemoryRequirements(device->device, hack->blit_image, &blitMemReq); -+ -+ offs = blitMemTotal % blitMemReq.alignment; -+ if(offs) -+ blitMemTotal += blitMemReq.alignment - offs; -+ -+ res = device->funcs.p_vkBindImageMemory(device->device, hack->blit_image, swapchain->blit_image_memory, blitMemTotal); -+ if(res != VK_SUCCESS){ -+ ERR("vkBindImageMemory: %d\n", res); -+ goto fail; -+ } -+ -+ blitMemTotal += blitMemReq.size; -+ } -+ }else -+ TRACE("blitting directly to swapchain images\n"); -+ -+ /* create imageviews */ -+ for(i = 0; i < swapchain->n_images; ++i){ -+ struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; -+ -+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; -+ viewInfo.image = hack->blit_image ? hack->blit_image : hack->swapchain_image; -+ viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; -+ viewInfo.format = VK_FORMAT_R8G8B8A8_UNORM; -+ viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ viewInfo.subresourceRange.baseMipLevel = 0; -+ viewInfo.subresourceRange.levelCount = 1; -+ viewInfo.subresourceRange.baseArrayLayer = 0; -+ viewInfo.subresourceRange.layerCount = 1; -+ -+ res = device->funcs.p_vkCreateImageView(device->device, &viewInfo, NULL, &hack->blit_view); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreateImageView(blit): %d\n", res); -+ goto fail; -+ } -+ -+ res = create_descriptor_set(device, swapchain, hack); -+ if(res != VK_SUCCESS) -+ goto fail; -+ } -+ -+ return VK_SUCCESS; -+ -+fail: -+ for(i = 0; i < swapchain->n_images; ++i){ -+ struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; -+ -+ device->funcs.p_vkDestroyImageView(device->device, hack->blit_view, NULL); -+ hack->blit_view = VK_NULL_HANDLE; -+ -+ device->funcs.p_vkDestroyImage(device->device, hack->blit_image, NULL); -+ hack->blit_image = VK_NULL_HANDLE; -+ } -+ -+ device->funcs.p_vkDestroyShaderModule(device->device, shaderModule, NULL); -+ -+ device->funcs.p_vkDestroyPipeline(device->device, swapchain->pipeline, NULL); -+ swapchain->pipeline = VK_NULL_HANDLE; -+ -+ device->funcs.p_vkDestroyPipelineLayout(device->device, swapchain->pipeline_layout, NULL); -+ swapchain->pipeline_layout = VK_NULL_HANDLE; -+ -+ device->funcs.p_vkDestroyDescriptorSetLayout(device->device, swapchain->descriptor_set_layout, NULL); -+ swapchain->descriptor_set_layout = VK_NULL_HANDLE; -+ -+ device->funcs.p_vkDestroyDescriptorPool(device->device, swapchain->descriptor_pool, NULL); -+ swapchain->descriptor_pool = VK_NULL_HANDLE; -+ -+ device->funcs.p_vkFreeMemory(device->device, swapchain->blit_image_memory, NULL); -+ swapchain->blit_image_memory = VK_NULL_HANDLE; -+ -+ device->funcs.p_vkDestroySampler(device->device, swapchain->sampler, NULL); -+ swapchain->sampler = VK_NULL_HANDLE; -+ -+ return res; -+} -+ -+static void destroy_fs_hack_image(VkDevice device, struct VkSwapchainKHR_T *swapchain, struct fs_hack_image *hack) -+{ -+ device->funcs.p_vkDestroyImageView(device->device, hack->user_view, NULL); -+ device->funcs.p_vkDestroyImageView(device->device, hack->blit_view, NULL); -+ device->funcs.p_vkDestroyImage(device->device, hack->user_image, NULL); -+ device->funcs.p_vkDestroyImage(device->device, hack->blit_image, NULL); -+ if(hack->cmd) -+ device->funcs.p_vkFreeCommandBuffers(device->device, -+ swapchain->cmd_pools[hack->cmd_queue_idx], -+ 1, &hack->cmd); -+ device->funcs.p_vkDestroySemaphore(device->device, hack->blit_finished, NULL); -+} -+ -+#if defined(USE_STRUCT_CONVERSION) -+static VkResult init_fs_hack_images(VkDevice device, struct VkSwapchainKHR_T *swapchain, VkSwapchainCreateInfoKHR_host *createinfo) -+#else -+static VkResult init_fs_hack_images(VkDevice device, struct VkSwapchainKHR_T *swapchain, VkSwapchainCreateInfoKHR *createinfo) -+#endif -+{ -+ VkResult res; -+ VkImage *real_images = NULL; -+ VkDeviceSize userMemTotal = 0, offs; -+ VkImageCreateInfo imageInfo = {0}; -+ VkSemaphoreCreateInfo semaphoreInfo = {0}; -+#if defined(USE_STRUCT_CONVERSION) -+ VkMemoryRequirements_host userMemReq; -+ VkMemoryAllocateInfo_host allocInfo = {0}; -+ VkPhysicalDeviceMemoryProperties_host memProperties; -+ VkImageViewCreateInfo_host viewInfo = {0}; -+#else -+ VkMemoryRequirements userMemReq; -+ VkMemoryAllocateInfo allocInfo = {0}; -+ VkPhysicalDeviceMemoryProperties memProperties; -+ VkImageViewCreateInfo viewInfo = {0}; -+#endif -+ uint32_t count, i = 0, user_memory_type = -1; -+ -+ res = device->funcs.p_vkGetSwapchainImagesKHR(device->device, swapchain->swapchain, &count, NULL); -+ if(res != VK_SUCCESS) -+ { -+ WARN("vkGetSwapchainImagesKHR failed, res=%d\n", res); -+ return res; -+ } -+ -+ real_images = malloc(count * sizeof(VkImage)); -+ swapchain->cmd_pools = calloc(device->queue_count, sizeof(VkCommandPool)); -+ swapchain->fs_hack_images = calloc(count, sizeof(struct fs_hack_image)); -+ if(!real_images || !swapchain->cmd_pools || !swapchain->fs_hack_images) -+ goto fail; -+ -+ res = device->funcs.p_vkGetSwapchainImagesKHR(device->device, swapchain->swapchain, &count, real_images); -+ if(res != VK_SUCCESS) -+ { -+ WARN("vkGetSwapchainImagesKHR failed, res=%d\n", res); -+ goto fail; -+ } -+ -+ /* create user images */ -+ for(i = 0; i < count; ++i){ -+ struct fs_hack_image *hack = &swapchain->fs_hack_images[i]; -+ -+ hack->swapchain_image = real_images[i]; -+ -+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; -+ res = device->funcs.p_vkCreateSemaphore(device->device, &semaphoreInfo, NULL, &hack->blit_finished); -+ if(res != VK_SUCCESS) -+ { -+ WARN("vkCreateSemaphore failed, res=%d\n", res); -+ goto fail; -+ } -+ -+ imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; -+ imageInfo.imageType = VK_IMAGE_TYPE_2D; -+ imageInfo.extent.width = swapchain->user_extent.width; -+ imageInfo.extent.height = swapchain->user_extent.height; -+ imageInfo.extent.depth = 1; -+ imageInfo.mipLevels = 1; -+ imageInfo.arrayLayers = createinfo->imageArrayLayers; -+ imageInfo.format = createinfo->imageFormat; -+ imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; -+ imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ imageInfo.usage = createinfo->imageUsage | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; -+ imageInfo.sharingMode = createinfo->imageSharingMode; -+ imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; -+ imageInfo.queueFamilyIndexCount = createinfo->queueFamilyIndexCount; -+ imageInfo.pQueueFamilyIndices = createinfo->pQueueFamilyIndices; -+ res = device->funcs.p_vkCreateImage(device->device, &imageInfo, NULL, &hack->user_image); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreateImage failed: %d\n", res); -+ goto fail; -+ } -+ -+ device->funcs.p_vkGetImageMemoryRequirements(device->device, hack->user_image, &userMemReq); -+ -+ offs = userMemTotal % userMemReq.alignment; -+ if(offs) -+ userMemTotal += userMemReq.alignment - offs; -+ -+ userMemTotal += userMemReq.size; -+ -+ swapchain->n_images++; -+ } -+ -+ /* allocate backing memory */ -+ device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceMemoryProperties(device->phys_dev->phys_dev, &memProperties); -+ -+ for (i = 0; i < memProperties.memoryTypeCount; i++){ -+ if((memProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT){ -+ if(userMemReq.memoryTypeBits & (1 << i)){ -+ user_memory_type = i; -+ break; -+ } -+ } -+ } -+ -+ if(user_memory_type == -1){ -+ ERR("unable to find suitable memory type\n"); -+ res = VK_ERROR_OUT_OF_HOST_MEMORY; -+ goto fail; -+ } -+ -+ allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; -+ allocInfo.allocationSize = userMemTotal; -+ allocInfo.memoryTypeIndex = user_memory_type; -+ -+ res = device->funcs.p_vkAllocateMemory(device->device, &allocInfo, NULL, &swapchain->user_image_memory); -+ if(res != VK_SUCCESS){ -+ ERR("vkAllocateMemory: %d\n", res); -+ goto fail; -+ } -+ -+ /* bind backing memory and create imageviews */ -+ userMemTotal = 0; -+ for(i = 0; i < count; ++i){ -+ device->funcs.p_vkGetImageMemoryRequirements(device->device, swapchain->fs_hack_images[i].user_image, &userMemReq); -+ -+ offs = userMemTotal % userMemReq.alignment; -+ if(offs) -+ userMemTotal += userMemReq.alignment - offs; -+ -+ res = device->funcs.p_vkBindImageMemory(device->device, swapchain->fs_hack_images[i].user_image, swapchain->user_image_memory, userMemTotal); -+ if(res != VK_SUCCESS){ -+ ERR("vkBindImageMemory: %d\n", res); -+ goto fail; -+ } -+ -+ userMemTotal += userMemReq.size; -+ -+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; -+ viewInfo.image = swapchain->fs_hack_images[i].user_image; -+ viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; -+ viewInfo.format = createinfo->imageFormat; -+ viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ viewInfo.subresourceRange.baseMipLevel = 0; -+ viewInfo.subresourceRange.levelCount = 1; -+ viewInfo.subresourceRange.baseArrayLayer = 0; -+ viewInfo.subresourceRange.layerCount = 1; -+ -+ res = device->funcs.p_vkCreateImageView(device->device, &viewInfo, NULL, &swapchain->fs_hack_images[i].user_view); -+ if(res != VK_SUCCESS){ -+ ERR("vkCreateImageView(user): %d\n", res); -+ goto fail; -+ } -+ } -+ -+ free(real_images); -+ -+ return VK_SUCCESS; -+ -+fail: -+ for(i = 0; i < swapchain->n_images; ++i) -+ destroy_fs_hack_image(device, swapchain, &swapchain->fs_hack_images[i]); -+ free(real_images); -+ free(swapchain->cmd_pools); -+ free(swapchain->fs_hack_images); -+ return res; -+} -+ -+#if defined(USE_STRUCT_CONVERSION) -+static inline void convert_VkSwapchainCreateInfoKHR_win_to_host(const VkSwapchainCreateInfoKHR *in, VkSwapchainCreateInfoKHR_host *out) -+#else -+static inline void convert_VkSwapchainCreateInfoKHR_win_to_host(const VkSwapchainCreateInfoKHR *in, VkSwapchainCreateInfoKHR *out) -+#endif -+{ -+ if (!in) return; -+ -+ out->sType = in->sType; -+ out->pNext = in->pNext; -+ out->flags = in->flags; -+ out->surface = wine_surface_from_handle(in->surface)->driver_surface; -+ out->minImageCount = in->minImageCount; -+ out->imageFormat = in->imageFormat; -+ out->imageColorSpace = in->imageColorSpace; -+ out->imageExtent = in->imageExtent; -+ out->imageArrayLayers = in->imageArrayLayers; -+ out->imageUsage = in->imageUsage; -+ out->imageSharingMode = in->imageSharingMode; -+ out->queueFamilyIndexCount = in->queueFamilyIndexCount; -+ out->pQueueFamilyIndices = in->pQueueFamilyIndices; -+ out->preTransform = in->preTransform; -+ out->compositeAlpha = in->compositeAlpha; -+ out->presentMode = in->presentMode; -+ out->clipped = in->clipped; -+ out->oldSwapchain = in->oldSwapchain; -+} -+ -+NTSTATUS wine_vkCreateSwapchainKHR(void *args) -+{ -+ struct vkCreateSwapchainKHR_params *params = args; -+ VkDevice device = params->device; -+ const VkSwapchainCreateInfoKHR *create_info = params->pCreateInfo; -+ const VkAllocationCallbacks *allocator = params->pAllocator; -+ VkSwapchainKHR *swapchain = params->pSwapchain; -+#if defined(USE_STRUCT_CONVERSION) -+ VkSwapchainCreateInfoKHR_host native_info; -+#else -+ VkSwapchainCreateInfoKHR native_info; -+#endif -+ VkResult result; -+ VkExtent2D user_sz; -+ struct VkSwapchainKHR_T *object; -+ -+ TRACE("%p, %p, %p, %p\n", device, create_info, allocator, swapchain); -+ -+ if (!(object = calloc(1, sizeof(*object)))) -+ { -+ ERR("Failed to allocate memory for swapchain\n"); -+ return VK_ERROR_OUT_OF_HOST_MEMORY; -+ } -+ -+ convert_VkSwapchainCreateInfoKHR_win_to_host(create_info, &native_info); -+ -+ if(native_info.oldSwapchain) -+ native_info.oldSwapchain = ((struct VkSwapchainKHR_T *)(UINT_PTR)native_info.oldSwapchain)->swapchain; -+ -+ if(vk_funcs->query_fs_hack && -+ vk_funcs->query_fs_hack(native_info.surface, &object->real_extent, &user_sz, &object->blit_dst, &object->fs_hack_filter) && -+ native_info.imageExtent.width == user_sz.width && -+ native_info.imageExtent.height == user_sz.height) -+ { -+ uint32_t count; -+ VkSurfaceCapabilitiesKHR caps = {0}; -+ -+ device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(device->phys_dev->phys_dev, &count, NULL); -+ -+ device->queue_props = malloc(sizeof(VkQueueFamilyProperties) * count); -+ -+ device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(device->phys_dev->phys_dev, &count, device->queue_props); -+ -+ result = device->phys_dev->instance->funcs.p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->phys_dev->phys_dev, native_info.surface, &caps); -+ if(result != VK_SUCCESS) -+ { -+ TRACE("vkGetPhysicalDeviceSurfaceCapabilities failed, res=%d\n", result); -+ free(object); -+ return result; -+ } -+ -+ object->surface_usage = caps.supportedUsageFlags; -+ TRACE("surface usage flags: 0x%x\n", object->surface_usage); -+ -+ native_info.imageExtent = object->real_extent; -+ native_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; /* XXX: check if supported by surface */ -+ -+ if(native_info.imageFormat != VK_FORMAT_B8G8R8A8_UNORM && -+ native_info.imageFormat != VK_FORMAT_B8G8R8A8_SRGB){ -+ FIXME("swapchain image format is not BGRA8 UNORM/SRGB. Things may go badly. %d\n", native_info.imageFormat); -+ } -+ -+ object->fs_hack_enabled = TRUE; -+ } -+ -+ result = device->funcs.p_vkCreateSwapchainKHR(device->device, &native_info, NULL, &object->swapchain); -+ if(result != VK_SUCCESS) -+ { -+ TRACE("vkCreateSwapchainKHR failed, res=%d\n", result); -+ free(object); -+ return result; -+ } -+ -+ WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->swapchain); -+ -+ if(object->fs_hack_enabled){ -+ object->user_extent = create_info->imageExtent; -+ -+ result = init_fs_hack_images(device, object, &native_info); -+ if(result != VK_SUCCESS){ -+ ERR("creating fs hack images failed: %d\n", result); -+ device->funcs.p_vkDestroySwapchainKHR(device->device, object->swapchain, NULL); -+ WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, object); -+ free(object); -+ return result; -+ } -+ -+ /* FIXME: would be nice to do this on-demand, but games can use up all -+ * memory so we fail to allocate later */ -+ result = init_blit_images(device, object); -+ if(result != VK_SUCCESS){ -+ ERR("creating blit images failed: %d\n", result); -+ device->funcs.p_vkDestroySwapchainKHR(device->device, object->swapchain, NULL); -+ WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, object); -+ free(object); -+ return result; -+ } -+ } -+ -+ *swapchain = (uint64_t)(UINT_PTR)object; -+ -+ return result; -+} -+ - NTSTATUS wine_vkCreateWin32SurfaceKHR(void *args) - { - struct vkCreateWin32SurfaceKHR_params *params = args; -@@ -1736,6 +2482,7 @@ NTSTATUS wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(void *args) - VkSurfaceKHR surface = params->surface; - VkSurfaceCapabilitiesKHR *capabilities = params->pSurfaceCapabilities; - VkResult res; -+ VkExtent2D user_res; - - TRACE("%p, 0x%s, %p\n", phys_dev, wine_dbgstr_longlong(surface), capabilities); - -@@ -1744,6 +2491,13 @@ NTSTATUS wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(void *args) - if (res == VK_SUCCESS) - adjust_max_image_count(phys_dev, capabilities); - -+ if (res == VK_SUCCESS && vk_funcs->query_fs_hack && -+ vk_funcs->query_fs_hack(wine_surface_from_handle(surface)->driver_surface, NULL, &user_res, NULL, NULL)){ -+ capabilities->currentExtent = user_res; -+ capabilities->minImageExtent = user_res; -+ capabilities->maxImageExtent = user_res; -+ } -+ - return res; - } - -@@ -1754,6 +2508,7 @@ NTSTATUS wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR(void *args) - const VkPhysicalDeviceSurfaceInfo2KHR *surface_info = params->pSurfaceInfo; - VkSurfaceCapabilities2KHR *capabilities = params->pSurfaceCapabilities; - VkResult res; -+ VkExtent2D user_res; - - TRACE("%p, %p, %p\n", phys_dev, surface_info, capabilities); - -@@ -1762,6 +2517,13 @@ NTSTATUS wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR(void *args) - if (res == VK_SUCCESS) - adjust_max_image_count(phys_dev, &capabilities->surfaceCapabilities); - -+ if (res == VK_SUCCESS && vk_funcs->query_fs_hack && -+ vk_funcs->query_fs_hack(wine_surface_from_handle(surface_info->surface)->driver_surface, NULL, &user_res, NULL, NULL)){ -+ capabilities->surfaceCapabilities.currentExtent = user_res; -+ capabilities->surfaceCapabilities.minImageExtent = user_res; -+ capabilities->surfaceCapabilities.maxImageExtent = user_res; -+ } -+ - return res; - } - -@@ -1894,6 +2656,641 @@ NTSTATUS wine_vkDestroyDebugReportCallbackEXT(void *args) - return STATUS_SUCCESS; - } - -+NTSTATUS wine_vkAcquireNextImage2KHR(void *args) -+{ -+ struct vkAcquireNextImage2KHR_params *params = args; -+ VkDevice device = params->device; -+ const VkAcquireNextImageInfoKHR *pAcquireInfo = params->pAcquireInfo; -+ uint32_t *pImageIndex = params->pImageIndex; -+#if defined(USE_STRUCT_CONVERSION) -+ VkAcquireNextImageInfoKHR_host image_info_host = {0}; -+#else -+ VkAcquireNextImageInfoKHR image_info_host = {0}; -+#endif -+ struct VkSwapchainKHR_T *object = (struct VkSwapchainKHR_T *)(UINT_PTR)pAcquireInfo->swapchain; -+ TRACE("%p, %p, %p\n", device, pAcquireInfo, pImageIndex); -+ -+ image_info_host.sType = pAcquireInfo->sType; -+ image_info_host.pNext = pAcquireInfo->pNext; -+ image_info_host.swapchain = object->swapchain; -+ image_info_host.timeout = pAcquireInfo->timeout; -+ image_info_host.semaphore = pAcquireInfo->semaphore; -+ image_info_host.fence = pAcquireInfo->fence; -+ image_info_host.deviceMask = pAcquireInfo->deviceMask; -+ -+ return device->funcs.p_vkAcquireNextImage2KHR(device->device, &image_info_host, pImageIndex); -+} -+ -+NTSTATUS wine_vkDestroySwapchainKHR(void *args) -+{ -+ struct vkDestroySwapchainKHR_params *params = args; -+ VkDevice device = params->device; -+ VkSwapchainKHR swapchain = params->swapchain; -+ const VkAllocationCallbacks *pAllocator = params->pAllocator; -+ struct VkSwapchainKHR_T *object = (struct VkSwapchainKHR_T *)(UINT_PTR)swapchain; -+ uint32_t i; -+ -+ TRACE("%p, 0x%s, %p\n", device, wine_dbgstr_longlong(swapchain), pAllocator); -+ -+ if(!object) -+ return STATUS_SUCCESS; -+ -+ if(object->fs_hack_enabled){ -+ for(i = 0; i < object->n_images; ++i) -+ destroy_fs_hack_image(device, object, &object->fs_hack_images[i]); -+ -+ for(i = 0; i < device->queue_count; ++i) -+ if(object->cmd_pools[i]) -+ device->funcs.p_vkDestroyCommandPool(device->device, object->cmd_pools[i], NULL); -+ -+ device->funcs.p_vkDestroyPipeline(device->device, object->pipeline, NULL); -+ device->funcs.p_vkDestroyPipelineLayout(device->device, object->pipeline_layout, NULL); -+ device->funcs.p_vkDestroyDescriptorSetLayout(device->device, object->descriptor_set_layout, NULL); -+ device->funcs.p_vkDestroyDescriptorPool(device->device, object->descriptor_pool, NULL); -+ device->funcs.p_vkDestroySampler(device->device, object->sampler, NULL); -+ device->funcs.p_vkFreeMemory(device->device, object->user_image_memory, NULL); -+ device->funcs.p_vkFreeMemory(device->device, object->blit_image_memory, NULL); -+ free(object->cmd_pools); -+ free(object->fs_hack_images); -+ } -+ -+ device->funcs.p_vkDestroySwapchainKHR(device->device, object->swapchain, NULL); -+ -+ WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, object); -+ free(object); -+ return STATUS_SUCCESS; -+} -+ -+NTSTATUS wine_vkGetSwapchainImagesKHR(void *args) -+{ -+ struct vkGetSwapchainImagesKHR_params *params = args; -+ VkDevice device = params->device; -+ VkSwapchainKHR swapchain = params->swapchain; -+ uint32_t *pSwapchainImageCount = params->pSwapchainImageCount; -+ VkImage *pSwapchainImages = params->pSwapchainImages; -+ struct VkSwapchainKHR_T *object = (struct VkSwapchainKHR_T *)(UINT_PTR)swapchain; -+ uint32_t i; -+ -+ TRACE("%p, 0x%s, %p, %p\n", device, wine_dbgstr_longlong(swapchain), pSwapchainImageCount, pSwapchainImages); -+ -+ if(pSwapchainImages && object->fs_hack_enabled){ -+ if(*pSwapchainImageCount > object->n_images) -+ *pSwapchainImageCount = object->n_images; -+ for(i = 0; i < *pSwapchainImageCount ; ++i) -+ pSwapchainImages[i] = object->fs_hack_images[i].user_image; -+ return *pSwapchainImageCount == object->n_images ? VK_SUCCESS : VK_INCOMPLETE; -+ } -+ -+ return device->funcs.p_vkGetSwapchainImagesKHR(device->device, object->swapchain, pSwapchainImageCount, pSwapchainImages); -+} -+ -+static VkCommandBuffer create_hack_cmd(VkQueue queue, struct VkSwapchainKHR_T *swapchain, uint32_t queue_idx) -+{ -+#if defined(USE_STRUCT_CONVERSION) -+ VkCommandBufferAllocateInfo_host allocInfo = {0}; -+#else -+ VkCommandBufferAllocateInfo allocInfo = {0}; -+#endif -+ VkCommandBuffer cmd; -+ VkResult result; -+ -+ if(!swapchain->cmd_pools[queue_idx]){ -+ VkCommandPoolCreateInfo poolInfo = {0}; -+ -+ poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; -+ poolInfo.queueFamilyIndex = queue_idx; -+ -+ result = queue->device->funcs.p_vkCreateCommandPool(queue->device->device, &poolInfo, NULL, &swapchain->cmd_pools[queue_idx]); -+ if(result != VK_SUCCESS){ -+ ERR("vkCreateCommandPool failed, res=%d\n", result); -+ return NULL; -+ } -+ } -+ -+ allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; -+ allocInfo.commandPool = swapchain->cmd_pools[queue_idx]; -+ allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; -+ allocInfo.commandBufferCount = 1; -+ -+ result = queue->device->funcs.p_vkAllocateCommandBuffers(queue->device->device, &allocInfo, &cmd); -+ if(result != VK_SUCCESS){ -+ ERR("vkAllocateCommandBuffers failed, res=%d\n", result); -+ return NULL; -+ } -+ -+ return cmd; -+} -+ -+static VkResult record_compute_cmd(VkDevice device, struct VkSwapchainKHR_T *swapchain, struct fs_hack_image *hack) -+{ -+ VkResult result; -+ VkImageCopy region = {0}; -+#if defined(USE_STRUCT_CONVERSION) -+ VkImageMemoryBarrier_host barriers[3] = {{0}}; -+ VkCommandBufferBeginInfo_host beginInfo = {0}; -+#else -+ VkImageMemoryBarrier barriers[3] = {{0}}; -+ VkCommandBufferBeginInfo beginInfo = {0}; -+#endif -+ float constants[4]; -+ -+ TRACE("recording compute command\n"); -+ -+#if 0 -+ /* DOOM runs out of memory when allocating blit images after loading. */ -+ if(!swapchain->blit_image_memory){ -+ result = init_blit_images(device, swapchain); -+ if(result != VK_SUCCESS) -+ return result; -+ } -+#endif -+ -+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; -+ beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; -+ -+ device->funcs.p_vkBeginCommandBuffer(hack->cmd, &beginInfo); -+ -+ /* for the cs we run... */ -+ /* transition user image from PRESENT_SRC to SHADER_READ */ -+ barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[0].oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; -+ barriers[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; -+ barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].image = hack->user_image; -+ barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[0].subresourceRange.baseMipLevel = 0; -+ barriers[0].subresourceRange.levelCount = 1; -+ barriers[0].subresourceRange.baseArrayLayer = 0; -+ barriers[0].subresourceRange.layerCount = 1; -+ barriers[0].srcAccessMask = 0; -+ barriers[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; -+ -+ /* storage image... */ -+ /* transition blit image from whatever to GENERAL */ -+ barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ barriers[1].newLayout = VK_IMAGE_LAYOUT_GENERAL; -+ barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[1].image = hack->blit_image ? hack->blit_image : hack->swapchain_image; -+ barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[1].subresourceRange.baseMipLevel = 0; -+ barriers[1].subresourceRange.levelCount = 1; -+ barriers[1].subresourceRange.baseArrayLayer = 0; -+ barriers[1].subresourceRange.layerCount = 1; -+ barriers[1].srcAccessMask = 0; -+ barriers[1].dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; -+ -+ device->funcs.p_vkCmdPipelineBarrier( -+ hack->cmd, -+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, -+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, -+ 0, -+ 0, NULL, -+ 0, NULL, -+ 2, barriers -+ ); -+ -+ /* perform blit shader */ -+ device->funcs.p_vkCmdBindPipeline(hack->cmd, -+ VK_PIPELINE_BIND_POINT_COMPUTE, swapchain->pipeline); -+ -+ device->funcs.p_vkCmdBindDescriptorSets(hack->cmd, -+ VK_PIPELINE_BIND_POINT_COMPUTE, swapchain->pipeline_layout, -+ 0, 1, &hack->descriptor_set, 0, NULL); -+ -+ /* vec2: blit dst offset in real coords */ -+ constants[0] = swapchain->blit_dst.offset.x; -+ constants[1] = swapchain->blit_dst.offset.y; -+ /* vec2: blit dst extents in real coords */ -+ constants[2] = swapchain->blit_dst.extent.width; -+ constants[3] = swapchain->blit_dst.extent.height; -+ device->funcs.p_vkCmdPushConstants(hack->cmd, -+ swapchain->pipeline_layout, VK_SHADER_STAGE_COMPUTE_BIT, -+ 0, sizeof(constants), constants); -+ -+ /* local sizes in shader are 8 */ -+ device->funcs.p_vkCmdDispatch(hack->cmd, ceil(swapchain->real_extent.width / 8.), -+ ceil(swapchain->real_extent.height / 8.), 1); -+ -+ /* transition user image from SHADER_READ back to PRESENT_SRC */ -+ barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[0].oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; -+ barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; -+ barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].image = hack->user_image; -+ barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[0].subresourceRange.baseMipLevel = 0; -+ barriers[0].subresourceRange.levelCount = 1; -+ barriers[0].subresourceRange.baseArrayLayer = 0; -+ barriers[0].subresourceRange.layerCount = 1; -+ barriers[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; -+ barriers[0].dstAccessMask = 0; -+ -+ device->funcs.p_vkCmdPipelineBarrier( -+ hack->cmd, -+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, -+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, -+ 0, -+ 0, NULL, -+ 0, NULL, -+ 1, barriers -+ ); -+ -+ if(hack->blit_image){ -+ /* for the copy... */ -+ /* no transition, just a barrier for our access masks (w -> r) */ -+ barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[0].oldLayout = VK_IMAGE_LAYOUT_GENERAL; -+ barriers[0].newLayout = VK_IMAGE_LAYOUT_GENERAL; -+ barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].image = hack->blit_image; -+ barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[0].subresourceRange.baseMipLevel = 0; -+ barriers[0].subresourceRange.levelCount = 1; -+ barriers[0].subresourceRange.baseArrayLayer = 0; -+ barriers[0].subresourceRange.layerCount = 1; -+ barriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; -+ barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; -+ -+ /* for the copy... */ -+ /* transition swapchain image from whatever to TRANSFER_DST -+ * we don't care about the contents... */ -+ barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[1].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; -+ barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[1].image = hack->swapchain_image; -+ barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[1].subresourceRange.baseMipLevel = 0; -+ barriers[1].subresourceRange.levelCount = 1; -+ barriers[1].subresourceRange.baseArrayLayer = 0; -+ barriers[1].subresourceRange.layerCount = 1; -+ barriers[1].srcAccessMask = 0; -+ barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; -+ -+ device->funcs.p_vkCmdPipelineBarrier( -+ hack->cmd, -+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, -+ VK_PIPELINE_STAGE_TRANSFER_BIT, -+ 0, -+ 0, NULL, -+ 0, NULL, -+ 2, barriers -+ ); -+ -+ /* copy from blit image to swapchain image */ -+ region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ region.srcSubresource.layerCount = 1; -+ region.srcOffset.x = 0; -+ region.srcOffset.y = 0; -+ region.srcOffset.z = 0; -+ region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ region.dstSubresource.layerCount = 1; -+ region.dstOffset.x = 0; -+ region.dstOffset.y = 0; -+ region.dstOffset.z = 0; -+ region.extent.width = swapchain->real_extent.width; -+ region.extent.height = swapchain->real_extent.height; -+ region.extent.depth = 1; -+ -+ device->funcs.p_vkCmdCopyImage(hack->cmd, -+ hack->blit_image, VK_IMAGE_LAYOUT_GENERAL, -+ hack->swapchain_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, -+ 1, ®ion); -+ -+ /* transition swapchain image from TRANSFER_DST_OPTIMAL to PRESENT_SRC */ -+ barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; -+ barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; -+ barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].image = hack->swapchain_image; -+ barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[0].subresourceRange.baseMipLevel = 0; -+ barriers[0].subresourceRange.levelCount = 1; -+ barriers[0].subresourceRange.baseArrayLayer = 0; -+ barriers[0].subresourceRange.layerCount = 1; -+ barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; -+ barriers[0].dstAccessMask = 0; -+ -+ device->funcs.p_vkCmdPipelineBarrier( -+ hack->cmd, -+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, -+ VK_PIPELINE_STAGE_TRANSFER_BIT, -+ 0, -+ 0, NULL, -+ 0, NULL, -+ 1, barriers -+ ); -+ }else{ -+ /* transition swapchain image from GENERAL to PRESENT_SRC */ -+ barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[0].oldLayout = VK_IMAGE_LAYOUT_GENERAL; -+ barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; -+ barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].image = hack->swapchain_image; -+ barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[0].subresourceRange.baseMipLevel = 0; -+ barriers[0].subresourceRange.levelCount = 1; -+ barriers[0].subresourceRange.baseArrayLayer = 0; -+ barriers[0].subresourceRange.layerCount = 1; -+ barriers[0].srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; -+ barriers[0].dstAccessMask = 0; -+ -+ device->funcs.p_vkCmdPipelineBarrier( -+ hack->cmd, -+ VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, -+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, -+ 0, -+ 0, NULL, -+ 0, NULL, -+ 1, barriers -+ ); -+ } -+ -+ result = device->funcs.p_vkEndCommandBuffer(hack->cmd); -+ if(result != VK_SUCCESS){ -+ ERR("vkEndCommandBuffer: %d\n", result); -+ return result; -+ } -+ -+ return VK_SUCCESS; -+} -+ -+static VkResult record_graphics_cmd(VkDevice device, struct VkSwapchainKHR_T *swapchain, struct fs_hack_image *hack) -+{ -+ VkResult result; -+ VkImageBlit blitregion = {0}; -+ VkImageSubresourceRange range = {0}; -+ VkClearColorValue black = {{0.f, 0.f, 0.f}}; -+#if defined(USE_STRUCT_CONVERSION) -+ VkImageMemoryBarrier_host barriers[2] = {{0}}; -+ VkCommandBufferBeginInfo_host beginInfo = {0}; -+#else -+ VkImageMemoryBarrier barriers[2] = {{0}}; -+ VkCommandBufferBeginInfo beginInfo = {0}; -+#endif -+ -+ TRACE("recording graphics command\n"); -+ -+ beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; -+ beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; -+ -+ device->funcs.p_vkBeginCommandBuffer(hack->cmd, &beginInfo); -+ -+ /* transition real image from whatever to TRANSFER_DST_OPTIMAL */ -+ barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; -+ barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; -+ barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].image = hack->swapchain_image; -+ barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[0].subresourceRange.baseMipLevel = 0; -+ barriers[0].subresourceRange.levelCount = 1; -+ barriers[0].subresourceRange.baseArrayLayer = 0; -+ barriers[0].subresourceRange.layerCount = 1; -+ barriers[0].srcAccessMask = 0; -+ barriers[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; -+ -+ /* transition user image from PRESENT_SRC to TRANSFER_SRC_OPTIMAL */ -+ barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[1].oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; -+ barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; -+ barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[1].image = hack->user_image; -+ barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[1].subresourceRange.baseMipLevel = 0; -+ barriers[1].subresourceRange.levelCount = 1; -+ barriers[1].subresourceRange.baseArrayLayer = 0; -+ barriers[1].subresourceRange.layerCount = 1; -+ barriers[1].srcAccessMask = 0; -+ barriers[1].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; -+ -+ device->funcs.p_vkCmdPipelineBarrier( -+ hack->cmd, -+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, -+ VK_PIPELINE_STAGE_TRANSFER_BIT, -+ 0, -+ 0, NULL, -+ 0, NULL, -+ 2, barriers -+ ); -+ -+ /* clear the image */ -+ range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ range.baseMipLevel = 0; -+ range.levelCount = 1; -+ range.baseArrayLayer = 0; -+ range.layerCount = 1; -+ -+ device->funcs.p_vkCmdClearColorImage( -+ hack->cmd, hack->swapchain_image, -+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, -+ &black, 1, &range); -+ -+ /* perform blit */ -+ blitregion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ blitregion.srcSubresource.layerCount = 1; -+ blitregion.srcOffsets[0].x = 0; -+ blitregion.srcOffsets[0].y = 0; -+ blitregion.srcOffsets[0].z = 0; -+ blitregion.srcOffsets[1].x = swapchain->user_extent.width; -+ blitregion.srcOffsets[1].y = swapchain->user_extent.height; -+ blitregion.srcOffsets[1].z = 1; -+ blitregion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ blitregion.dstSubresource.layerCount = 1; -+ blitregion.dstOffsets[0].x = swapchain->blit_dst.offset.x; -+ blitregion.dstOffsets[0].y = swapchain->blit_dst.offset.y; -+ blitregion.dstOffsets[0].z = 0; -+ blitregion.dstOffsets[1].x = swapchain->blit_dst.offset.x + swapchain->blit_dst.extent.width; -+ blitregion.dstOffsets[1].y = swapchain->blit_dst.offset.y + swapchain->blit_dst.extent.height; -+ blitregion.dstOffsets[1].z = 1; -+ -+ device->funcs.p_vkCmdBlitImage(hack->cmd, -+ hack->user_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, -+ hack->swapchain_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, -+ 1, &blitregion, swapchain->fs_hack_filter); -+ -+ /* transition real image from TRANSFER_DST to PRESENT_SRC */ -+ barriers[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; -+ barriers[0].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; -+ barriers[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[0].image = hack->swapchain_image; -+ barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[0].subresourceRange.baseMipLevel = 0; -+ barriers[0].subresourceRange.levelCount = 1; -+ barriers[0].subresourceRange.baseArrayLayer = 0; -+ barriers[0].subresourceRange.layerCount = 1; -+ barriers[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; -+ barriers[0].dstAccessMask = 0; -+ -+ /* transition user image from TRANSFER_SRC_OPTIMAL to back to PRESENT_SRC */ -+ barriers[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; -+ barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; -+ barriers[1].newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; -+ barriers[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; -+ barriers[1].image = hack->user_image; -+ barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; -+ barriers[1].subresourceRange.baseMipLevel = 0; -+ barriers[1].subresourceRange.levelCount = 1; -+ barriers[1].subresourceRange.baseArrayLayer = 0; -+ barriers[1].subresourceRange.layerCount = 1; -+ barriers[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; -+ barriers[1].dstAccessMask = 0; -+ -+ device->funcs.p_vkCmdPipelineBarrier( -+ hack->cmd, -+ VK_PIPELINE_STAGE_TRANSFER_BIT, -+ VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, -+ 0, -+ 0, NULL, -+ 0, NULL, -+ 2, barriers -+ ); -+ -+ result = device->funcs.p_vkEndCommandBuffer(hack->cmd); -+ if(result != VK_SUCCESS){ -+ ERR("vkEndCommandBuffer: %d\n", result); -+ return result; -+ } -+ -+ return VK_SUCCESS; -+} -+ -+NTSTATUS wine_vkQueuePresentKHR(void *args) -+{ -+ struct vkQueuePresentKHR_params *params = args; -+ VkQueue queue = params->queue; -+ const VkPresentInfoKHR *pPresentInfo = params->pPresentInfo; -+ VkResult res; -+ VkPresentInfoKHR our_presentInfo; -+ VkSwapchainKHR *arr; -+ VkCommandBuffer *blit_cmds = NULL; -+ VkSubmitInfo submitInfo = {0}; -+ VkSemaphore blit_sema; -+ struct VkSwapchainKHR_T *swapchain; -+ uint32_t i, n_hacks = 0; -+ uint32_t queue_idx; -+ -+ TRACE("%p, %p\n", queue, pPresentInfo); -+ -+ our_presentInfo = *pPresentInfo; -+ -+ for(i = 0; i < our_presentInfo.swapchainCount; ++i){ -+ swapchain = (struct VkSwapchainKHR_T *)(UINT_PTR)our_presentInfo.pSwapchains[i]; -+ -+ if(swapchain->fs_hack_enabled){ -+ struct fs_hack_image *hack = &swapchain->fs_hack_images[our_presentInfo.pImageIndices[i]]; -+ -+ if(!blit_cmds){ -+ queue_idx = queue->family_index; -+ blit_cmds = malloc(our_presentInfo.swapchainCount * sizeof(VkCommandBuffer)); -+ blit_sema = hack->blit_finished; -+ } -+ -+ if(!hack->cmd || hack->cmd_queue_idx != queue_idx){ -+ if(hack->cmd) -+ queue->device->funcs.p_vkFreeCommandBuffers(queue->device->device, -+ swapchain->cmd_pools[hack->cmd_queue_idx], -+ 1, &hack->cmd); -+ -+ hack->cmd_queue_idx = queue_idx; -+ hack->cmd = create_hack_cmd(queue, swapchain, queue_idx); -+ -+ if(!hack->cmd){ -+ free(blit_cmds); -+ return VK_ERROR_DEVICE_LOST; -+ } -+ -+ if(queue->device->queue_props[queue_idx].queueFlags & VK_QUEUE_GRAPHICS_BIT) -+ res = record_graphics_cmd(queue->device, swapchain, hack); -+ else if(queue->device->queue_props[queue_idx].queueFlags & VK_QUEUE_COMPUTE_BIT) -+ res = record_compute_cmd(queue->device, swapchain, hack); -+ else{ -+ ERR("Present queue is neither graphics nor compute queue!\n"); -+ res = VK_ERROR_DEVICE_LOST; -+ } -+ -+ if(res != VK_SUCCESS){ -+ queue->device->funcs.p_vkFreeCommandBuffers(queue->device->device, -+ swapchain->cmd_pools[hack->cmd_queue_idx], -+ 1, &hack->cmd); -+ hack->cmd = NULL; -+ free(blit_cmds); -+ return res; -+ } -+ } -+ -+ blit_cmds[n_hacks] = hack->cmd; -+ -+ ++n_hacks; -+ } -+ } -+ -+ if(n_hacks > 0){ -+ VkPipelineStageFlags waitStage, *waitStages, *waitStages_arr = NULL; -+ -+ if(pPresentInfo->waitSemaphoreCount > 1){ -+ waitStages_arr = malloc(sizeof(VkPipelineStageFlags) * pPresentInfo->waitSemaphoreCount); -+ for(i = 0; i < pPresentInfo->waitSemaphoreCount; ++i) -+ waitStages_arr[i] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; -+ waitStages = waitStages_arr; -+ }else{ -+ waitStage = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; -+ waitStages = &waitStage; -+ } -+ -+ /* blit user image to real image */ -+ submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; -+ submitInfo.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount; -+ submitInfo.pWaitSemaphores = pPresentInfo->pWaitSemaphores; -+ submitInfo.pWaitDstStageMask = waitStages; -+ submitInfo.commandBufferCount = n_hacks; -+ submitInfo.pCommandBuffers = blit_cmds; -+ submitInfo.signalSemaphoreCount = 1; -+ submitInfo.pSignalSemaphores = &blit_sema; -+ -+ res = queue->device->funcs.p_vkQueueSubmit(queue->queue, 1, &submitInfo, VK_NULL_HANDLE); -+ if(res != VK_SUCCESS) -+ ERR("vkQueueSubmit: %d\n", res); -+ -+ free(waitStages_arr); -+ free(blit_cmds); -+ -+ our_presentInfo.waitSemaphoreCount = 1; -+ our_presentInfo.pWaitSemaphores = &blit_sema; -+ } -+ -+ arr = malloc(our_presentInfo.swapchainCount * sizeof(VkSwapchainKHR)); -+ if(!arr){ -+ ERR("Failed to allocate memory for swapchain array\n"); -+ return VK_ERROR_OUT_OF_HOST_MEMORY; -+ } -+ -+ for(i = 0; i < our_presentInfo.swapchainCount; ++i) -+ arr[i] = ((struct VkSwapchainKHR_T *)(UINT_PTR)our_presentInfo.pSwapchains[i])->swapchain; -+ -+ our_presentInfo.pSwapchains = arr; -+ -+ res = queue->device->funcs.p_vkQueuePresentKHR(queue->queue, &our_presentInfo); -+ -+ free(arr); -+ -+ return res; -+ -+} -+ - BOOL WINAPI wine_vk_is_available_instance_function(VkInstance instance, const char *name) - { - return !!vk_funcs->p_vkGetInstanceProcAddr(instance->instance, name); -diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h -index 666ef95e1b1..491e4cbe4a7 100644 ---- a/dlls/winevulkan/vulkan_private.h -+++ b/dlls/winevulkan/vulkan_private.h -@@ -63,6 +63,44 @@ struct VkDevice_T - struct VkQueue_T* queues; - uint32_t queue_count; - -+ VkQueueFamilyProperties *queue_props; -+ -+ struct wine_vk_mapping mapping; -+}; -+ -+struct fs_hack_image -+{ -+ uint32_t cmd_queue_idx; -+ VkCommandBuffer cmd; -+ VkImage swapchain_image; -+ VkImage blit_image; -+ VkImage user_image; -+ VkSemaphore blit_finished; -+ VkImageView user_view, blit_view; -+ VkDescriptorSet descriptor_set; -+}; -+ -+struct VkSwapchainKHR_T -+{ -+ VkSwapchainKHR swapchain; /* native swapchain */ -+ -+ /* fs hack data below */ -+ BOOL fs_hack_enabled; -+ VkExtent2D user_extent; -+ VkExtent2D real_extent; -+ VkImageUsageFlags surface_usage; -+ VkRect2D blit_dst; -+ VkCommandPool *cmd_pools; /* VkCommandPool[device->queue_count] */ -+ VkDeviceMemory user_image_memory, blit_image_memory; -+ uint32_t n_images; -+ struct fs_hack_image *fs_hack_images; /* struct fs_hack_image[n_images] */ -+ VkFilter fs_hack_filter; -+ VkSampler sampler; -+ VkDescriptorPool descriptor_pool; -+ VkDescriptorSetLayout descriptor_set_layout; -+ VkPipelineLayout pipeline_layout; -+ VkPipeline pipeline; -+ - struct wine_vk_mapping mapping; - }; - - -From 16dc52e38a40f4feae70ece79e3ad2d715cf0620 Mon Sep 17 00:00:00 2001 -From: Kai Krakow -Date: Sun, 10 Oct 2021 20:48:24 +0200 -Subject: [PATCH] winex11.drv: Bypass compositor in fullscreen mode. - -Bypass the compositor in fullscreen mode. This reduces stutter -introduced by window updates in the background and also allows for maybe -a few more FPS. To not change the visual appearance of the desktop for -windowed games, this hack only enables itself when the game was switched -to fullscreen mode, and returns to default WM setting when the game -leaves fullscreen mode. - -Compositors tend to cause severe stutter if the game is GPU-bound. ---- - dlls/winex11.drv/window.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 45a45a29f1a..c6b23d857af 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1144,6 +1144,7 @@ void update_user_time( Time time ) - void update_net_wm_states( struct x11drv_win_data *data ) - { - DWORD i, style, ex_style, new_state = 0; -+ unsigned long net_wm_bypass_compositor = 0; - - if (!data->managed) return; - if (data->whole_window == root_window) return; -@@ -1156,7 +1157,10 @@ void update_net_wm_states( struct x11drv_win_data *data ) - if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) - new_state |= (1 << NET_WM_STATE_MAXIMIZED); - else if (!(style & WS_MINIMIZE)) -+ { -+ net_wm_bypass_compositor = 1; - new_state |= (1 << NET_WM_STATE_FULLSCREEN); -+ } - } - else if (style & WS_MAXIMIZE) - new_state |= (1 << NET_WM_STATE_MAXIMIZED); -@@ -1218,6 +1222,9 @@ void update_net_wm_states( struct x11drv_win_data *data ) - } - } - data->net_wm_state = new_state; -+ -+ XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_BYPASS_COMPOSITOR), XA_CARDINAL, -+ 32, PropModeReplace, (unsigned char *)&net_wm_bypass_compositor, 1 ); - } - - /*********************************************************************** -From 045bf41a42665b1a0c56d0549a6b34fd330f052b Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Sun, 10 Oct 2021 20:53:45 +0200 -Subject: [PATCH] winex11.drv: Fullscreen hack -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Based on work by Zhiyi Zhang, includes work by Giovanni Mascellani, Rémi -Bernon, Arkadiusz Hiler, Kai Krakow, Joshua Ashton, Zebediah Figura, and -Matteo Bruni. ---- - dlls/winex11.drv/Makefile.in | 1 + - dlls/winex11.drv/desktop.c | 1 + - dlls/winex11.drv/display.c | 93 +++- - dlls/winex11.drv/event.c | 29 +- - dlls/winex11.drv/fs.c | 899 +++++++++++++++++++++++++++++++++ - dlls/winex11.drv/graphics.c | 3 +- - dlls/winex11.drv/mouse.c | 44 +- - dlls/winex11.drv/opengl.c | 525 ++++++++++++++++++- - dlls/winex11.drv/settings.c | 28 +- - dlls/winex11.drv/vulkan.c | 59 +++ - dlls/winex11.drv/window.c | 152 +++++- - dlls/winex11.drv/x11drv.h | 35 ++ - dlls/winex11.drv/x11drv_main.c | 8 +- - dlls/winex11.drv/xrandr.c | 20 + - dlls/winex11.drv/xrender.c | 137 ++++- - dlls/winex11.drv/xvidmode.c | 1 + - 16 files changed, 1967 insertions(+), 68 deletions(-) - create mode 100644 dlls/winex11.drv/fs.c - -diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in -index c64a8464914..d44c9907498 100644 ---- a/dlls/winex11.drv/Makefile.in -+++ b/dlls/winex11.drv/Makefile.in -@@ -13,6 +13,7 @@ C_SRCS = \ - desktop.c \ - display.c \ - event.c \ -+ fs.c \ - graphics.c \ - ime.c \ - init.c \ -diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c -index 15350244610..ece6c2890ff 100644 ---- a/dlls/winex11.drv/desktop.c -+++ b/dlls/winex11.drv/desktop.c -@@ -317,6 +317,7 @@ void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height ) - settings_handler.free_modes = X11DRV_desktop_free_modes; - settings_handler.get_current_mode = X11DRV_desktop_get_current_mode; - settings_handler.set_current_mode = X11DRV_desktop_set_current_mode; -+ settings_handler.convert_coordinates = NULL; - X11DRV_Settings_SetHandler( &settings_handler ); - } - -diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c -index 04380ff660f..cf638ff43a0 100644 ---- a/dlls/winex11.drv/display.c -+++ b/dlls/winex11.drv/display.c -@@ -139,21 +139,33 @@ static BOOL update_screen_cache(void) - - POINT virtual_screen_to_root(INT x, INT y) - { -- RECT virtual = get_virtual_screen_rect(); -+ RECT virtual = fs_hack_get_real_virtual_screen(); - POINT pt; - -- pt.x = x - virtual.left; -- pt.y = y - virtual.top; -+ TRACE("from %d,%d\n", x, y); -+ -+ pt.x = x; -+ pt.y = y; -+ fs_hack_point_user_to_real(&pt); -+ TRACE("to real %d,%d\n", pt.x, pt.y); -+ -+ pt.x -= virtual.left; -+ pt.y -= virtual.top; -+ TRACE("to root %d,%d\n", pt.x, pt.y); - return pt; - } - - POINT root_to_virtual_screen(INT x, INT y) - { -- RECT virtual = get_virtual_screen_rect(); -+ RECT virtual = fs_hack_get_real_virtual_screen(); - POINT pt; - -+ TRACE("from root %d,%d\n", x, y); - pt.x = x + virtual.left; - pt.y = y + virtual.top; -+ TRACE("to real %d,%d\n", pt.x, pt.y); -+ fs_hack_point_real_to_user(&pt); -+ TRACE("to user %d,%d\n", pt.x, pt.y); - return pt; - } - -@@ -283,6 +295,11 @@ void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler - } - } - -+struct x11drv_display_device_handler X11DRV_DisplayDevices_GetHandler(void) -+{ -+ return host_handler; -+} -+ - void X11DRV_DisplayDevices_RegisterEventHandlers(void) - { - struct x11drv_display_device_handler *handler = is_virtual_desktop() ? &desktop_handler : &host_handler; -@@ -295,22 +312,72 @@ static BOOL CALLBACK update_windows_on_display_change(HWND hwnd, LPARAM lparam) - { - struct x11drv_win_data *data; - UINT mask = (UINT)lparam; -+ HMONITOR monitor; - - if (!(data = get_win_data(hwnd))) - return TRUE; - -- /* update the full screen state */ -- update_net_wm_states(data); -+ monitor = fs_hack_monitor_from_hwnd( hwnd ); -+ if (fs_hack_mapping_required( monitor ) && -+ fs_hack_matches_current_mode( monitor, -+ data->whole_rect.right - data->whole_rect.left, -+ data->whole_rect.bottom - data->whole_rect.top)){ -+ if(!data->fs_hack){ -+ RECT real_rect = fs_hack_real_mode( monitor ); -+ MONITORINFO monitor_info; -+ UINT width, height; -+ POINT tl; -+ -+ monitor_info.cbSize = sizeof(monitor_info); -+ GetMonitorInfoW( monitor, &monitor_info ); -+ tl = virtual_screen_to_root( monitor_info.rcMonitor.left, monitor_info.rcMonitor.top ); -+ width = real_rect.right - real_rect.left; -+ height = real_rect.bottom - real_rect.top; -+ -+ TRACE("Enabling fs hack, resizing window %p to (%u,%u)-(%u,%u)\n", hwnd, tl.x, tl.y, width, height); -+ data->fs_hack = TRUE; -+ set_wm_hints( data ); -+ XMoveResizeWindow(data->display, data->whole_window, tl.x, tl.y, width, height); -+ if(data->client_window) -+ XMoveResizeWindow(gdi_display, data->client_window, 0, 0, width, height); -+ sync_gl_drawable(hwnd, FALSE); -+ update_net_wm_states( data ); -+ } -+ } else { -+ /* update the full screen state */ -+ update_net_wm_states(data); - -- if (mask && data->whole_window) -- { -- POINT pos = virtual_screen_to_root(data->whole_rect.left, data->whole_rect.top); -- XWindowChanges changes; -- changes.x = pos.x; -- changes.y = pos.y; -- XReconfigureWMWindow(data->display, data->whole_window, data->vis.screen, mask, &changes); -+ if (data->fs_hack) -+ mask |= CWX | CWY; -+ -+ if (mask && data->whole_window) -+ { -+ POINT pos = virtual_screen_to_root(data->whole_rect.left, data->whole_rect.top); -+ XWindowChanges changes; -+ changes.x = pos.x; -+ changes.y = pos.y; -+ XReconfigureWMWindow(data->display, data->whole_window, data->vis.screen, mask, &changes); -+ } -+ -+ if(data->fs_hack && (!fs_hack_mapping_required(monitor) || -+ !fs_hack_matches_current_mode(monitor, -+ data->whole_rect.right - data->whole_rect.left, -+ data->whole_rect.bottom - data->whole_rect.top))){ -+ TRACE("Disabling fs hack\n"); -+ data->fs_hack = FALSE; -+ if(data->client_window){ -+ XMoveResizeWindow(gdi_display, data->client_window, -+ data->client_rect.left - data->whole_rect.left, -+ data->client_rect.top - data->whole_rect.top, -+ data->client_rect.right - data->client_rect.left, -+ data->client_rect.bottom - data->client_rect.top); -+ } -+ sync_gl_drawable(hwnd, FALSE); -+ } - } - release_win_data(data); -+ if (hwnd == GetForegroundWindow()) -+ clip_fullscreen_window(hwnd, TRUE); - return TRUE; - } - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 3a903eebd7e..d22d34ea1c7 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -1186,8 +1186,19 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) - } - else pos = root_to_virtual_screen( x, y ); - -- X11DRV_X_to_window_rect( data, &rect, pos.x, pos.y, event->width, event->height ); -- if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 ); -+ if(data->fs_hack){ -+ MONITORINFO monitor_info; -+ HMONITOR monitor; -+ -+ monitor = fs_hack_monitor_from_hwnd( hwnd ); -+ monitor_info.cbSize = sizeof(monitor_info); -+ GetMonitorInfoW( monitor, &monitor_info ); -+ rect = monitor_info.rcMonitor; -+ TRACE( "monitor %p rect: %s\n", monitor, wine_dbgstr_rect(&rect) ); -+ }else{ -+ X11DRV_X_to_window_rect( data, &rect, pos.x, pos.y, event->width, event->height ); -+ if (root_coords) MapWindowPoints( 0, parent, (POINT *)&rect, 2 ); -+ } - - TRACE( "win %p/%lx new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n", - hwnd, data->whole_window, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, -@@ -1195,6 +1206,19 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) - - /* Compare what has changed */ - -+ { -+ const char *steamgameid = getenv("SteamGameId"); -+ if(steamgameid && !strcmp(steamgameid, "590380")){ -+ /* Into The Breach is extremely picky about the size of its window. */ -+ if(is_window_rect_full_screen(&data->whole_rect) && -+ is_window_rect_full_screen(&rect)){ -+ TRACE("window is fullscreen and new size is also fullscreen, so preserving window size\n"); -+ rect.right = rect.left + (data->whole_rect.right - data->whole_rect.left); -+ rect.bottom = rect.top + (data->whole_rect.bottom - data->whole_rect.top); -+ } -+ } -+ } -+ - x = rect.left; - y = rect.top; - cx = rect.right - rect.left; -@@ -1596,6 +1620,7 @@ static void EVENT_DropFromOffiX( HWND hWnd, XClientMessageEvent *event ) - Window win, w_aux_root, w_aux_child; - - if (!(data = get_win_data( hWnd ))) return; -+ ERR("TODO: fs hack\n"); - cx = data->whole_rect.right - data->whole_rect.left; - cy = data->whole_rect.bottom - data->whole_rect.top; - win = data->whole_window; -diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c -new file mode 100644 -index 00000000000..641fdd40d45 ---- /dev/null -+++ b/dlls/winex11.drv/fs.c -@@ -0,0 +1,899 @@ -+/* -+ * Fullscreen Hack -+ * -+ * Simulate monitor resolution change -+ * -+ * Copyright 2020 Andrew Eikum for CodeWeavers -+ * Copyright 2020 Zhiyi Zhang for CodeWeavers -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+#include "config.h" -+#include -+#include -+ -+#define NONAMELESSSTRUCT -+#define NONAMELESSUNION -+ -+#include "x11drv.h" -+#include "wine/debug.h" -+#include "wine/list.h" -+#include "wine/heap.h" -+#include "wine/unicode.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(fshack); -+ -+static struct x11drv_display_device_handler real_device_handler; -+static struct x11drv_settings_handler real_settings_handler; -+static struct list fs_monitors = LIST_INIT(fs_monitors); -+ -+/* Access to fs_monitors is protected by fs_section */ -+static CRITICAL_SECTION fs_section; -+static CRITICAL_SECTION_DEBUG critsect_debug = -+{ -+ 0, 0, &fs_section, -+ {&critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList}, -+ 0, 0, {(DWORD_PTR)(__FILE__ ": fs_section")} -+}; -+static CRITICAL_SECTION fs_section = {&critsect_debug, -1, 0, 0, 0, 0}; -+ -+struct fs_monitor_size -+{ -+ DWORD width; -+ DWORD height; -+}; -+ -+/* A table of resolutions some games expect but host system may not report */ -+static struct fs_monitor_size fs_monitor_sizes[] = -+{ -+ {640, 480}, /* 4:3 */ -+ {800, 600}, /* 4:3 */ -+ {1024, 768}, /* 4:3 */ -+ {1600, 1200}, /* 4:3 */ -+ {960, 540}, /* 16:9 */ -+ {1280, 720}, /* 16:9 */ -+ {1600, 900}, /* 16:9 */ -+ {1920, 1080}, /* 16:9 */ -+ {2560, 1440}, /* 16:9 */ -+ {2880, 1620}, /* 16:9 */ -+ {3200, 1800}, /* 16:9 */ -+ {1440, 900}, /* 8:5 */ -+ {1680, 1050}, /* 8:5 */ -+ {1920, 1200}, /* 8:5 */ -+ {2560, 1600}, /* 8:5 */ -+ {1440, 960}, /* 3:2 */ -+ {1920, 1280}, /* 3:2 */ -+ {2560, 1080}, /* 21:9 ultra-wide */ -+ {1920, 800}, /* 12:5 */ -+ {3840, 1600}, /* 12:5 */ -+ {1280, 1024}, /* 5:4 */ -+}; -+ -+/* A fake monitor for the fullscreen hack */ -+struct fs_monitor -+{ -+ struct list entry; -+ -+ DEVMODEW user_mode; /* Mode changed to by users */ -+ DEVMODEW real_mode; /* Mode actually used by the host system */ -+ double user_to_real_scale; /* Scale factor from fake monitor to real monitor */ -+ POINT top_left; /* Top left corner of the fake monitor rectangle in real virtual screen coordinates */ -+ DEVMODEW *modes; /* Supported display modes */ -+ UINT mode_count; /* Display mode count */ -+ UINT unique_resolutions; /* Number of unique resolutions in terms of WxH */ -+}; -+ -+static void add_fs_mode(struct fs_monitor *fs_monitor, DWORD depth, DWORD width, DWORD height, -+ DWORD frequency, DWORD orientation) -+{ -+ int i; -+ DEVMODEW *mode; -+ const char *appid; -+ BOOL is_new_resolution; -+ -+ /* Titan Souls renders incorrectly if we report modes smaller than 800x600 */ -+ if ((appid = getenv("SteamAppId")) && !strcmp(appid, "297130")) -+ { -+ if (orientation == DMDO_DEFAULT || orientation == DMDO_180) -+ { -+ if (height <= 600 && !(height == 600 && width == 800)) -+ return; -+ } -+ else -+ { -+ if (width <= 600 && !(width == 600 && height == 800)) -+ return; -+ } -+ } -+ -+ is_new_resolution = TRUE; -+ -+ for (i = 0; i < fs_monitor->mode_count; ++i) -+ { -+ if (fs_monitor->modes[i].dmPelsWidth == width && -+ fs_monitor->modes[i].dmPelsHeight == height) -+ { -+ is_new_resolution = FALSE; -+ -+ if (fs_monitor->modes[i].dmBitsPerPel == depth && -+ fs_monitor->modes[i].dmDisplayFrequency == frequency && -+ fs_monitor->modes[i].u1.s2.dmDisplayOrientation == orientation) -+ return; /* The exact mode is already added, nothing to do */ -+ } -+ } -+ -+ if (is_new_resolution) { -+ /* Some games crash if we report too many unique resolutions (in terms of HxW) */ -+ if (limit_number_of_resolutions && fs_monitor->unique_resolutions >= limit_number_of_resolutions) -+ return; -+ -+ fs_monitor->unique_resolutions++; -+ } -+ -+ mode = &fs_monitor->modes[fs_monitor->mode_count++]; -+ mode->dmSize = sizeof(*mode); -+ -+ mode->dmDriverExtra = 0; -+ mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | -+ DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY; -+ mode->u1.s2.dmDisplayOrientation = orientation; -+ mode->dmBitsPerPel = depth; -+ mode->dmPelsWidth = width; -+ mode->dmPelsHeight = height; -+ mode->u2.dmDisplayFlags = 0; -+ mode->dmDisplayFrequency = frequency; -+} -+ -+static BOOL fs_monitor_add_modes(struct fs_monitor *fs_monitor) -+{ -+ DEVMODEW *real_modes, *real_mode, current_mode; -+ UINT real_mode_count; -+ DWORD width, height; -+ ULONG_PTR real_id; -+ ULONG offset; -+ UINT i, j; -+ -+ if (!real_settings_handler.get_id(fs_monitor->user_mode.dmDeviceName, &real_id)) -+ return FALSE; -+ -+ if (!real_settings_handler.get_current_mode(real_id, ¤t_mode)) -+ return FALSE; -+ -+ /* Fullscreen hack doesn't support changing display orientations */ -+ if (!real_settings_handler.get_modes(real_id, 0, &real_modes, &real_mode_count)) -+ return FALSE; -+ -+ fs_monitor->mode_count = 0; -+ fs_monitor->unique_resolutions = 0; -+ fs_monitor->modes = heap_calloc(ARRAY_SIZE(fs_monitor_sizes) * DEPTH_COUNT + real_mode_count, -+ sizeof(*fs_monitor->modes)); -+ if (!fs_monitor->modes) -+ { -+ real_settings_handler.free_modes(real_modes); -+ return FALSE; -+ } -+ -+ /* Add the current mode early, in case we have to limit */ -+ add_fs_mode(fs_monitor, current_mode.dmBitsPerPel, current_mode.dmPelsWidth, -+ current_mode.dmPelsHeight, current_mode.dmDisplayFrequency, -+ current_mode.u1.s2.dmDisplayOrientation); -+ -+ /* Linux reports far fewer resolutions than Windows. Add modes that some games may expect. */ -+ for (i = 0; i < ARRAY_SIZE(fs_monitor_sizes); ++i) -+ { -+ if (current_mode.u1.s2.dmDisplayOrientation == DMDO_DEFAULT || -+ current_mode.u1.s2.dmDisplayOrientation == DMDO_180) -+ { -+ width = fs_monitor_sizes[i].width; -+ height = fs_monitor_sizes[i].height; -+ } -+ else -+ { -+ width = fs_monitor_sizes[i].height; -+ height = fs_monitor_sizes[i].width; -+ } -+ -+ /* Don't report modes that are larger than the current mode */ -+ if (width > current_mode.dmPelsWidth || height > current_mode.dmPelsHeight) -+ continue; -+ -+ for (j = 0; j < DEPTH_COUNT; ++j) -+ add_fs_mode(fs_monitor, depths[j], width, height, 60, -+ current_mode.u1.s2.dmDisplayOrientation); -+ } -+ -+ for (i = 0; i < real_mode_count; ++i) -+ { -+ offset = (sizeof(*real_modes) + real_modes[0].dmDriverExtra) * i; -+ real_mode = (DEVMODEW *)((BYTE *)real_modes + offset); -+ -+ /* Don't report real modes that are larger than the current mode */ -+ if (real_mode->dmPelsWidth > current_mode.dmPelsWidth || -+ real_mode->dmPelsHeight > current_mode.dmPelsHeight) -+ continue; -+ -+ add_fs_mode(fs_monitor, real_mode->dmBitsPerPel, real_mode->dmPelsWidth, -+ real_mode->dmPelsHeight, real_mode->dmDisplayFrequency, -+ real_mode->u1.s2.dmDisplayOrientation); -+ } -+ real_settings_handler.free_modes(real_modes); -+ -+ /* Sort display modes so that X11DRV_EnumDisplaySettingsEx gets an already sorted mode list */ -+ qsort(fs_monitor->modes, fs_monitor->mode_count, sizeof(*fs_monitor->modes), mode_compare); -+ return TRUE; -+} -+ -+/* Add a fake monitor to fs_monitors list. -+ * Call this function with fs_section entered */ -+static BOOL fs_add_monitor(const WCHAR *device_name) -+{ -+ struct fs_monitor *fs_monitor; -+ DEVMODEW real_mode; -+ ULONG_PTR real_id; -+ -+ if (!real_settings_handler.get_id(device_name, &real_id)) -+ return FALSE; -+ -+ if (!real_settings_handler.get_current_mode(real_id, &real_mode)) -+ return FALSE; -+ -+ if (!(fs_monitor = heap_alloc(sizeof(*fs_monitor)))) -+ return FALSE; -+ -+ fs_monitor->user_mode = real_mode; -+ fs_monitor->real_mode = real_mode; -+ fs_monitor->user_to_real_scale = 1.0; -+ fs_monitor->top_left.x = real_mode.u1.s2.dmPosition.x; -+ fs_monitor->top_left.y = real_mode.u1.s2.dmPosition.y; -+ lstrcpyW(fs_monitor->user_mode.dmDeviceName, device_name); -+ if (!fs_monitor_add_modes(fs_monitor)) -+ { -+ ERR("Failed to initialize display modes.\n"); -+ heap_free(fs_monitor); -+ return FALSE; -+ } -+ list_add_tail(&fs_monitors, &fs_monitor->entry); -+ return TRUE; -+} -+ -+/* Fullscreen settings handler */ -+ -+/* Convert fullscreen hack settings handler id to GDI device name */ -+static void fs_id_to_device_name(ULONG_PTR id, WCHAR *device_name) -+{ -+ static WCHAR display_fmtW[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','%','d',0}; -+ sprintfW(device_name, display_fmtW, (INT)id); -+} -+ -+static BOOL fs_get_id(const WCHAR *device_name, ULONG_PTR *id) -+{ -+ static const WCHAR displayW[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y'}; -+ long int display_index; -+ WCHAR *end; -+ -+ if (strncmpiW( device_name, displayW, ARRAY_SIZE(displayW) )) -+ return FALSE; -+ -+ display_index = strtolW( device_name + ARRAY_SIZE(displayW), &end, 10 ); -+ if (*end) -+ return FALSE; -+ -+ *id = (ULONG_PTR)display_index; -+ return TRUE; -+} -+ -+/* Find a fs_monitor from a display name. -+ * Call this function with fs_section entered */ -+static struct fs_monitor *fs_get_monitor_by_name(const WCHAR *name) -+{ -+ struct fs_monitor *fs_monitor; -+ -+ TRACE("name %s\n", wine_dbgstr_w(name)); -+ -+ LIST_FOR_EACH_ENTRY(fs_monitor, &fs_monitors, struct fs_monitor, entry) -+ { -+ if (!lstrcmpiW(fs_monitor->user_mode.dmDeviceName, name)) -+ return fs_monitor; -+ } -+ -+ return NULL; -+} -+ -+static BOOL fs_get_modes(ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count) -+{ -+ WCHAR device_name[CCHDEVICENAME]; -+ struct fs_monitor *fs_monitor; -+ -+ fs_id_to_device_name(id, device_name); -+ EnterCriticalSection(&fs_section); -+ if ((fs_monitor = fs_get_monitor_by_name(device_name))) -+ { -+ *new_modes = fs_monitor->modes; -+ *mode_count = fs_monitor->mode_count; -+ LeaveCriticalSection(&fs_section); -+ return TRUE; -+ } -+ -+ LeaveCriticalSection(&fs_section); -+ return FALSE; -+} -+ -+static void fs_free_modes(DEVMODEW *modes){} -+ -+/* Find a fs_monitor from a HMONITOR handle. -+ * Call this function with fs_section entered */ -+static struct fs_monitor *fs_find_monitor_by_handle(HMONITOR monitor) -+{ -+ MONITORINFOEXW monitor_info; -+ -+ TRACE("monitor %p\n", monitor); -+ -+ monitor_info.cbSize = sizeof(monitor_info); -+ if (!GetMonitorInfoW(monitor, (MONITORINFO *)&monitor_info)) -+ return NULL; -+ -+ return fs_get_monitor_by_name(monitor_info.szDevice); -+} -+ -+static BOOL fs_get_current_mode(ULONG_PTR id, DEVMODEW *mode) -+{ -+ WCHAR device_name[CCHDEVICENAME]; -+ struct fs_monitor *fs_monitor; -+ -+ fs_id_to_device_name(id, device_name); -+ -+ EnterCriticalSection(&fs_section); -+ fs_monitor = fs_get_monitor_by_name(device_name); -+ if (fs_monitor) -+ { -+ *mode = fs_monitor->user_mode; -+ LeaveCriticalSection(&fs_section); -+ return TRUE; -+ } -+ LeaveCriticalSection(&fs_section); -+ return FALSE; -+} -+ -+static LONG fs_set_current_mode(ULONG_PTR id, DEVMODEW *user_mode) -+{ -+ WCHAR device_name[CCHDEVICENAME]; -+ struct fs_monitor *fs_monitor; -+ DEVMODEW real_mode; -+ ULONG_PTR real_id; -+ double scale; -+ -+ fs_id_to_device_name(id, device_name); -+ -+ EnterCriticalSection(&fs_section); -+ fs_monitor = fs_get_monitor_by_name(device_name); -+ if (!fs_monitor) -+ { -+ LeaveCriticalSection(&fs_section); -+ return DISP_CHANGE_FAILED; -+ } -+ -+ if (is_detached_mode(&fs_monitor->real_mode) && !is_detached_mode(user_mode)) -+ { -+ FIXME("Attaching adapters is unsupported with fullscreen hack.\n"); -+ return DISP_CHANGE_SUCCESSFUL; -+ } -+ -+ /* Real modes may be changed since initialization */ -+ if (!real_settings_handler.get_id(device_name, &real_id) || -+ !real_settings_handler.get_current_mode(real_id, &real_mode)) -+ { -+ LeaveCriticalSection(&fs_section); -+ return DISP_CHANGE_FAILED; -+ } -+ -+ fs_monitor->user_mode = *user_mode; -+ fs_monitor->real_mode = real_mode; -+ lstrcpyW(fs_monitor->user_mode.dmDeviceName, device_name); -+ -+ if (is_detached_mode(user_mode)) -+ { -+ fs_monitor->user_to_real_scale = 0; -+ fs_monitor->top_left.x = 0; -+ fs_monitor->top_left.y = 0; -+ } -+ /* Integer scaling */ -+ else if (fs_hack_is_integer()) -+ { -+ scale = min(real_mode.dmPelsWidth / user_mode->dmPelsWidth, real_mode.dmPelsHeight / user_mode->dmPelsHeight); -+ fs_monitor->user_to_real_scale = scale; -+ fs_monitor->top_left.x = real_mode.u1.s2.dmPosition.x + (real_mode.dmPelsWidth - user_mode->dmPelsWidth * scale) / 2; -+ fs_monitor->top_left.y = real_mode.u1.s2.dmPosition.y + (real_mode.dmPelsHeight - user_mode->dmPelsHeight * scale) / 2; -+ } -+ /* If real mode is narrower than fake mode, scale to fit width */ -+ else if ((double)real_mode.dmPelsWidth / (double)real_mode.dmPelsHeight -+ < (double)user_mode->dmPelsWidth / (double)user_mode->dmPelsHeight) -+ { -+ scale = (double)real_mode.dmPelsWidth / (double)user_mode->dmPelsWidth; -+ fs_monitor->user_to_real_scale = scale; -+ fs_monitor->top_left.x = real_mode.u1.s2.dmPosition.x; -+ fs_monitor->top_left.y = real_mode.u1.s2.dmPosition.y + (real_mode.dmPelsHeight - user_mode->dmPelsHeight * scale) / 2; -+ } -+ /* Else scale to fit height */ -+ else -+ { -+ scale = (double)real_mode.dmPelsHeight / (double)user_mode->dmPelsHeight; -+ fs_monitor->user_to_real_scale = scale; -+ fs_monitor->top_left.x = real_mode.u1.s2.dmPosition.x + (real_mode.dmPelsWidth - user_mode->dmPelsWidth * scale) / 2; -+ fs_monitor->top_left.y = real_mode.u1.s2.dmPosition.y; -+ } -+ -+ TRACE("real_mode x %d y %d width %d height %d\n", real_mode.u1.s2.dmPosition.x, real_mode.u1.s2.dmPosition.y, -+ real_mode.dmPelsWidth, real_mode.dmPelsHeight); -+ TRACE("user_mode x %d y %d width %d height %d\n", user_mode->u1.s2.dmPosition.x, user_mode->u1.s2.dmPosition.y, -+ user_mode->dmPelsWidth, user_mode->dmPelsHeight); -+ TRACE("user_to_real_scale %lf\n", fs_monitor->user_to_real_scale); -+ TRACE("top left corner:%s\n", wine_dbgstr_point(&fs_monitor->top_left)); -+ -+ LeaveCriticalSection(&fs_section); -+ return DISP_CHANGE_SUCCESSFUL; -+} -+ -+/* Display device handler functions */ -+ -+static BOOL fs_get_monitors(ULONG_PTR adapter_id, struct gdi_monitor **new_monitors, int *count) -+{ -+ struct gdi_monitor *monitor; -+ struct fs_monitor *fs_monitor; -+ RECT rect; -+ INT i; -+ -+ if (!real_device_handler.get_monitors(adapter_id, new_monitors, count)) -+ return FALSE; -+ -+ EnterCriticalSection(&fs_section); -+ for (i = 0; i < *count; ++i) -+ { -+ monitor = &(*new_monitors)[i]; -+ -+ LIST_FOR_EACH_ENTRY(fs_monitor, &fs_monitors, struct fs_monitor, entry) -+ { -+ rect.left = fs_monitor->real_mode.u1.s2.dmPosition.x; -+ rect.top = fs_monitor->real_mode.u1.s2.dmPosition.y; -+ rect.right = rect.left + fs_monitor->real_mode.dmPelsWidth; -+ rect.bottom = rect.top + fs_monitor->real_mode.dmPelsHeight; -+ -+ if (EqualRect(&rect, &monitor->rc_monitor)) -+ { -+ monitor->rc_monitor.left = fs_monitor->user_mode.u1.s2.dmPosition.x; -+ monitor->rc_monitor.top = fs_monitor->user_mode.u1.s2.dmPosition.y; -+ monitor->rc_monitor.right = monitor->rc_monitor.left + fs_monitor->user_mode.dmPelsWidth; -+ monitor->rc_monitor.bottom = monitor->rc_monitor.top + fs_monitor->user_mode.dmPelsHeight; -+ monitor->rc_work = monitor->rc_monitor; -+ monitor->state_flags = DISPLAY_DEVICE_ATTACHED; -+ if (fs_monitor->user_mode.dmPelsWidth && fs_monitor->user_mode.dmPelsHeight) -+ monitor->state_flags |= DISPLAY_DEVICE_ACTIVE; -+ } -+ } -+ } -+ LeaveCriticalSection(&fs_section); -+ return TRUE; -+} -+ -+/* Fullscreen hack helpers */ -+ -+/* Return whether fullscreen hack is enabled on a specific monitor */ -+BOOL fs_hack_enabled(HMONITOR monitor) -+{ -+ struct fs_monitor *fs_monitor; -+ BOOL enabled = FALSE; -+ -+ TRACE("monitor %p\n", monitor); -+ -+ EnterCriticalSection(&fs_section); -+ fs_monitor = fs_find_monitor_by_handle(monitor); -+ if (fs_monitor && (fs_monitor->user_mode.dmPelsWidth != fs_monitor->real_mode.dmPelsWidth || -+ fs_monitor->user_mode.dmPelsHeight != fs_monitor->real_mode.dmPelsHeight)) -+ enabled = TRUE; -+ LeaveCriticalSection(&fs_section); -+ TRACE("enabled: %s\n", enabled ? "TRUE" : "FALSE"); -+ return enabled; -+} -+ -+BOOL fs_hack_mapping_required(HMONITOR monitor) -+{ -+ BOOL required; -+ -+ TRACE("monitor %p\n", monitor); -+ -+ /* steamcompmgr does our mapping for us */ -+ required = !wm_is_steamcompmgr(NULL) && fs_hack_enabled(monitor); -+ TRACE("required: %s\n", required ? "TRUE" : "FALSE"); -+ return required; -+} -+ -+/* Return whether integer scaling is on */ -+BOOL fs_hack_is_integer(void) -+{ -+ static int is_int = -1; -+ if (is_int < 0) -+ { -+ const char *e = getenv("WINE_FULLSCREEN_INTEGER_SCALING"); -+ is_int = e && strcmp(e, "0"); -+ } -+ TRACE("is_interger_scaling: %s\n", is_int ? "TRUE" : "FALSE"); -+ return is_int; -+} -+ -+HMONITOR fs_hack_monitor_from_rect(const RECT *in_rect) -+{ -+ RECT rect = *in_rect; -+ -+ TRACE("rect %s\n", wine_dbgstr_rect(&rect)); -+ rect.right = rect.left + 1; -+ rect.bottom = rect.top + 1; -+ return MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY); -+} -+ -+/* Get the monitor a window is on. MonitorFromWindow() doesn't work here because it finds the -+ * monitor with the maximum overlapped rectangle when a window is spanned over two monitors, whereas -+ * for the fullscreen hack, the monitor where the left top corner of the window is on is the correct -+ * one. For example, a game with a window of 3840x2160 changes the primary monitor to 1280x720, if -+ * there is a secondary monitor of 3840x2160 to the right, MonitorFromWindow() will return the -+ * secondary monitor instead of the primary one. */ -+HMONITOR fs_hack_monitor_from_hwnd(HWND hwnd) -+{ -+ RECT rect = {0}; -+ -+ if (!GetWindowRect(hwnd, &rect)) -+ ERR("Invalid hwnd %p.\n", hwnd); -+ -+ TRACE("hwnd %p rect %s\n", hwnd, wine_dbgstr_rect(&rect)); -+ return fs_hack_monitor_from_rect(&rect); -+} -+ -+/* Return the rectangle of a monitor in current mode in user virtual screen coordinates */ -+RECT fs_hack_current_mode(HMONITOR monitor) -+{ -+ struct fs_monitor *fs_monitor; -+ RECT rect = {0}; -+ -+ TRACE("monitor %p\n", monitor); -+ -+ EnterCriticalSection(&fs_section); -+ fs_monitor = fs_find_monitor_by_handle(monitor); -+ if (!fs_monitor) -+ { -+ LeaveCriticalSection(&fs_section); -+ return rect; -+ } -+ -+ rect.left = fs_monitor->user_mode.u1.s2.dmPosition.x; -+ rect.top = fs_monitor->user_mode.u1.s2.dmPosition.y; -+ rect.right = rect.left + fs_monitor->user_mode.dmPelsWidth; -+ rect.bottom = rect.top + fs_monitor->user_mode.dmPelsHeight; -+ LeaveCriticalSection(&fs_section); -+ TRACE("current mode rect: %s\n", wine_dbgstr_rect(&rect)); -+ return rect; -+} -+ -+/* Return the rectangle of a monitor in real mode in real virtual screen coordinates */ -+RECT fs_hack_real_mode(HMONITOR monitor) -+{ -+ struct fs_monitor *fs_monitor; -+ RECT rect = {0}; -+ -+ TRACE("monitor %p\n", monitor); -+ -+ EnterCriticalSection(&fs_section); -+ fs_monitor = fs_find_monitor_by_handle(monitor); -+ if (!fs_monitor) -+ { -+ LeaveCriticalSection(&fs_section); -+ return rect; -+ } -+ -+ rect.left = fs_monitor->real_mode.u1.s2.dmPosition.x; -+ rect.top = fs_monitor->real_mode.u1.s2.dmPosition.y; -+ rect.right = rect.left + fs_monitor->real_mode.dmPelsWidth; -+ rect.bottom = rect.top + fs_monitor->real_mode.dmPelsHeight; -+ LeaveCriticalSection(&fs_section); -+ TRACE("real mode rect: %s\n", wine_dbgstr_rect(&rect)); -+ return rect; -+} -+ -+/* Return whether width and height are the same as the current mode used by a monitor */ -+BOOL fs_hack_matches_current_mode(HMONITOR monitor, INT width, INT height) -+{ -+ MONITORINFO monitor_info; -+ BOOL matched; -+ -+ TRACE("monitor %p\n", monitor); -+ -+ monitor_info.cbSize = sizeof(monitor_info); -+ if (!GetMonitorInfoW(monitor, &monitor_info)) -+ return FALSE; -+ -+ matched = (width == monitor_info.rcMonitor.right - monitor_info.rcMonitor.left) -+ && (height == monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top); -+ TRACE("matched: %s\n", matched ? "TRUE" : "FALSE"); -+ return matched; -+} -+ -+/* Transform a point in user virtual screen coordinates to real virtual screen coordinates */ -+void fs_hack_point_user_to_real(POINT *pos) -+{ -+ struct fs_monitor *fs_monitor; -+ RECT rect; -+ -+ TRACE("from %d,%d\n", pos->x, pos->y); -+ -+ if (wm_is_steamcompmgr(NULL)) -+ return; -+ -+ EnterCriticalSection(&fs_section); -+ LIST_FOR_EACH_ENTRY(fs_monitor, &fs_monitors, struct fs_monitor, entry) -+ { -+ rect.left = fs_monitor->user_mode.u1.s2.dmPosition.x; -+ rect.top = fs_monitor->user_mode.u1.s2.dmPosition.y; -+ rect.right = rect.left + fs_monitor->user_mode.dmPelsWidth; -+ rect.bottom = rect.top + fs_monitor->user_mode.dmPelsHeight; -+ -+ if (PtInRect(&rect, *pos)) -+ { -+ pos->x -= fs_monitor->user_mode.u1.s2.dmPosition.x; -+ pos->y -= fs_monitor->user_mode.u1.s2.dmPosition.y; -+ pos->x = lround(pos->x * fs_monitor->user_to_real_scale); -+ pos->y = lround(pos->y * fs_monitor->user_to_real_scale); -+ pos->x += fs_monitor->top_left.x; -+ pos->y += fs_monitor->top_left.y; -+ LeaveCriticalSection(&fs_section); -+ TRACE("to %d,%d\n", pos->x, pos->y); -+ return; -+ } -+ } -+ LeaveCriticalSection(&fs_section); -+ WARN("%d,%d not transformed.\n", pos->x, pos->y); -+} -+ -+/* Transform a point in real virtual screen coordinates to user virtual screen coordinates */ -+void fs_hack_point_real_to_user(POINT *pos) -+{ -+ struct fs_monitor *fs_monitor; -+ RECT rect; -+ -+ TRACE("from %d,%d\n", pos->x, pos->y); -+ -+ if (wm_is_steamcompmgr(NULL)) -+ return; -+ -+ EnterCriticalSection(&fs_section); -+ LIST_FOR_EACH_ENTRY(fs_monitor, &fs_monitors, struct fs_monitor, entry) -+ { -+ rect.left = fs_monitor->real_mode.u1.s2.dmPosition.x; -+ rect.top = fs_monitor->real_mode.u1.s2.dmPosition.y; -+ rect.right = rect.left + fs_monitor->real_mode.dmPelsWidth; -+ rect.bottom = rect.top + fs_monitor->real_mode.dmPelsHeight; -+ -+ if (PtInRect(&rect, *pos)) -+ { -+ pos->x -= fs_monitor->top_left.x; -+ pos->y -= fs_monitor->top_left.y; -+ pos->x = lround(pos->x / fs_monitor->user_to_real_scale); -+ pos->y = lround(pos->y / fs_monitor->user_to_real_scale); -+ pos->x += fs_monitor->user_mode.u1.s2.dmPosition.x; -+ pos->y += fs_monitor->user_mode.u1.s2.dmPosition.y; -+ pos->x = max(pos->x, fs_monitor->user_mode.u1.s2.dmPosition.x); -+ pos->y = max(pos->y, fs_monitor->user_mode.u1.s2.dmPosition.y); -+ pos->x = min(pos->x, fs_monitor->user_mode.u1.s2.dmPosition.x + (INT)fs_monitor->user_mode.dmPelsWidth - 1); -+ pos->y = min(pos->y, fs_monitor->user_mode.u1.s2.dmPosition.y + (INT)fs_monitor->user_mode.dmPelsHeight - 1); -+ LeaveCriticalSection(&fs_section); -+ TRACE("to %d,%d\n", pos->x, pos->y); -+ return; -+ } -+ } -+ LeaveCriticalSection(&fs_section); -+ WARN("%d,%d not transformed.\n", pos->x, pos->y); -+} -+ -+/* Transform RGNDATA in user virtual screen coordinates to real virtual screen coordinates. -+ * This is for clipping. Be sure to use Unsorted for Xlib calls after this transformation because -+ * this may break the requirement of using YXBanded. For example, say there are two monitors aligned -+ * horizontally with the primary monitor on the right. Each of monitor is of real resolution -+ * 1920x1080 and the fake primary monitor resolution is 1024x768. Then (0, 10, 1024, 768) should be -+ * transformed to (0, 14, 1920, 1080). While (1024, 10, 2944, 1080) should be transformed to -+ * (1920, 10, 3840, 1080) and this is breaking YXBanded because it requires y in non-decreasing order */ -+void fs_hack_rgndata_user_to_real(RGNDATA *data) -+{ -+ unsigned int i; -+ XRectangle *xrect; -+ RECT rect; -+ -+ if (!data || wm_is_steamcompmgr(NULL)) -+ return; -+ -+ xrect = (XRectangle *)data->Buffer; -+ for (i = 0; i < data->rdh.nCount; i++) -+ { -+ rect.left = xrect[i].x; -+ rect.top = xrect[i].y; -+ rect.right = xrect[i].x + xrect[i].width; -+ rect.bottom = xrect[i].y + xrect[i].height; -+ TRACE("from rect %s\n", wine_dbgstr_rect(&rect)); -+ fs_hack_rect_user_to_real(&rect); -+ TRACE("to rect %s\n", wine_dbgstr_rect(&rect)); -+ xrect[i].x = rect.left; -+ xrect[i].y = rect.top; -+ xrect[i].width = rect.right - rect.left; -+ xrect[i].height = rect.bottom - rect.top; -+ } -+} -+ -+/* Transform a rectangle in user virtual screen coordinates to real virtual screen coordinates. A -+ * difference compared to fs_hack_point_user_to_real() is that fs_hack_point_user_to_real() finds -+ * the wrong monitor if the point is on the right edge of the monitor rectangle. For example, when -+ * there are two monitors of real size 1920x1080, the primary monitor is of user mode 1024x768 and -+ * the secondary monitor is to the right. Rectangle (0, 0, 1024, 768) should transform to -+ * (0, 0, 1920, 1080). If (1024, 768) is passed to fs_hack_point_user_to_real(), -+ * fs_hack_point_user_to_real() will think (1024, 768) is on the secondary monitor, ends up -+ * returning a wrong result to callers. */ -+void fs_hack_rect_user_to_real(RECT *rect) -+{ -+ struct fs_monitor *fs_monitor; -+ HMONITOR monitor; -+ POINT point; -+ -+ TRACE("from %s\n", wine_dbgstr_rect(rect)); -+ -+ if (wm_is_steamcompmgr(NULL)) -+ return; -+ -+ point.x = rect->left; -+ point.y = rect->top; -+ monitor = MonitorFromPoint(point, MONITOR_DEFAULTTONEAREST); -+ EnterCriticalSection(&fs_section); -+ fs_monitor = fs_find_monitor_by_handle(monitor); -+ if (!fs_monitor) -+ { -+ LeaveCriticalSection(&fs_section); -+ WARN("%s not transformed.\n", wine_dbgstr_rect(rect)); -+ return; -+ } -+ -+ OffsetRect(rect, -fs_monitor->user_mode.u1.s2.dmPosition.x, -fs_monitor->user_mode.u1.s2.dmPosition.y); -+ rect->left = lround(rect->left * fs_monitor->user_to_real_scale); -+ rect->right = lround(rect->right * fs_monitor->user_to_real_scale); -+ rect->top = lround(rect->top * fs_monitor->user_to_real_scale); -+ rect->bottom = lround(rect->bottom * fs_monitor->user_to_real_scale); -+ OffsetRect(rect, fs_monitor->top_left.x, fs_monitor->top_left.y); -+ LeaveCriticalSection(&fs_section); -+ TRACE("to %s\n", wine_dbgstr_rect(rect)); -+} -+ -+/* Get the user_to_real_scale value in a monitor */ -+double fs_hack_get_user_to_real_scale(HMONITOR monitor) -+{ -+ struct fs_monitor *fs_monitor; -+ double scale = 1.0; -+ -+ TRACE("monitor %p\n", monitor); -+ -+ if (wm_is_steamcompmgr(NULL)) -+ return scale; -+ -+ EnterCriticalSection(&fs_section); -+ fs_monitor = fs_find_monitor_by_handle(monitor); -+ if (!fs_monitor) -+ { -+ LeaveCriticalSection(&fs_section); -+ return scale; -+ } -+ scale = fs_monitor->user_to_real_scale; -+ -+ LeaveCriticalSection(&fs_section); -+ TRACE("scale %lf\n", scale); -+ return scale; -+} -+ -+/* Get the scaled scree size of a monitor */ -+SIZE fs_hack_get_scaled_screen_size(HMONITOR monitor) -+{ -+ struct fs_monitor *fs_monitor; -+ SIZE size = {0}; -+ -+ TRACE("monitor %p\n", monitor); -+ -+ EnterCriticalSection(&fs_section); -+ fs_monitor = fs_find_monitor_by_handle(monitor); -+ if (!fs_monitor) -+ { -+ LeaveCriticalSection(&fs_section); -+ return size; -+ } -+ -+ if (wm_is_steamcompmgr(NULL)) -+ { -+ LeaveCriticalSection(&fs_section); -+ size.cx = fs_monitor->user_mode.dmPelsWidth; -+ size.cy = fs_monitor->user_mode.dmPelsHeight; -+ TRACE("width %d height %d\n", size.cx, size.cy); -+ return size; -+ } -+ -+ size.cx = lround(fs_monitor->user_mode.dmPelsWidth * fs_monitor->user_to_real_scale); -+ size.cy = lround(fs_monitor->user_mode.dmPelsHeight * fs_monitor->user_to_real_scale); -+ LeaveCriticalSection(&fs_section); -+ TRACE("width %d height %d\n", size.cx, size.cy); -+ return size; -+} -+ -+/* Get the real virtual screen size instead of virtual screen size using fake modes */ -+RECT fs_hack_get_real_virtual_screen(void) -+{ -+ struct fs_monitor *fs_monitor; -+ RECT rect, virtual = {0}; -+ -+ EnterCriticalSection(&fs_section); -+ LIST_FOR_EACH_ENTRY(fs_monitor, &fs_monitors, struct fs_monitor, entry) -+ { -+ rect.left = fs_monitor->real_mode.u1.s2.dmPosition.x; -+ rect.top = fs_monitor->real_mode.u1.s2.dmPosition.y; -+ rect.right = rect.left + fs_monitor->real_mode.dmPelsWidth; -+ rect.bottom = rect.top + fs_monitor->real_mode.dmPelsHeight; -+ -+ UnionRect(&virtual, &virtual, &rect); -+ } -+ LeaveCriticalSection(&fs_section); -+ TRACE("real virtual screen rect:%s\n", wine_dbgstr_rect(&virtual)); -+ return virtual; -+} -+ -+/* Initialize the fullscreen hack, which is a layer on top of real settings handlers and real -+ * display device handlers */ -+void fs_hack_init(void) -+{ -+ static WCHAR display_fmt[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y','%','d',0}; -+ struct x11drv_display_device_handler device_handler; -+ struct x11drv_settings_handler settings_handler; -+ WCHAR device_name[CCHDEVICENAME]; -+ INT i = 0; -+ -+ real_device_handler = X11DRV_DisplayDevices_GetHandler(); -+ real_settings_handler = X11DRV_Settings_GetHandler(); -+ -+ EnterCriticalSection(&fs_section); -+ while (1) -+ { -+ sprintfW(device_name, display_fmt, ++i); -+ if (!fs_add_monitor(device_name)) -+ break; -+ } -+ LeaveCriticalSection(&fs_section); -+ -+ settings_handler.name = "Fullscreen Hack"; -+ settings_handler.priority = 500; -+ settings_handler.get_id = fs_get_id; -+ settings_handler.get_modes = fs_get_modes; -+ settings_handler.free_modes = fs_free_modes; -+ settings_handler.get_current_mode = fs_get_current_mode; -+ settings_handler.set_current_mode = fs_set_current_mode; -+ settings_handler.convert_coordinates = NULL; -+ X11DRV_Settings_SetHandler(&settings_handler); -+ -+ device_handler.name = "Fullscreen Hack"; -+ device_handler.priority = 500; -+ device_handler.get_gpus = real_device_handler.get_gpus; -+ device_handler.get_adapters = real_device_handler.get_adapters; -+ device_handler.get_monitors = fs_get_monitors; -+ device_handler.free_gpus = real_device_handler.free_gpus; -+ device_handler.free_adapters = real_device_handler.free_adapters; -+ device_handler.free_monitors = real_device_handler.free_monitors; -+ device_handler.register_event_handlers = NULL; -+ X11DRV_DisplayDevices_SetHandler(&device_handler); -+} -diff --git a/dlls/winex11.drv/graphics.c b/dlls/winex11.drv/graphics.c -index b3df3cafcb1..a486f78746b 100644 ---- a/dlls/winex11.drv/graphics.c -+++ b/dlls/winex11.drv/graphics.c -@@ -251,8 +251,9 @@ static void update_x11_clipping( X11DRV_PDEVICE *physDev, HRGN rgn ) - } - else if ((data = X11DRV_GetRegionData( rgn, 0 ))) - { -+ fs_hack_rgndata_user_to_real(data); - XSetClipRectangles( gdi_display, physDev->gc, physDev->dc_rect.left, physDev->dc_rect.top, -- (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded ); -+ (XRectangle *)data->Buffer, data->rdh.nCount, Unsorted ); - HeapFree( GetProcessHeap(), 0, data ); - } - } -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 511550a8486..cb4363ae02e 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -433,6 +433,7 @@ static BOOL grab_clipping_window( const RECT *clip ) - Window clip_window; - HWND msg_hwnd = 0; - POINT pos; -+ RECT real_clip; - - if (GetWindowThreadProcessId( GetDesktopWindow(), NULL ) == GetCurrentThreadId()) - return TRUE; /* don't clip in the desktop process */ -@@ -450,9 +451,21 @@ static BOOL grab_clipping_window( const RECT *clip ) - TRACE( "clipping to %s win %lx\n", wine_dbgstr_rect(clip), clip_window ); - - if (!data->clip_hwnd) XUnmapWindow( data->display, clip_window ); -+ -+ TRACE("user clip rect %s\n", wine_dbgstr_rect(clip)); -+ -+ real_clip = *clip; -+ fs_hack_rect_user_to_real(&real_clip); -+ - pos = virtual_screen_to_root( clip->left, clip->top ); -+ -+ TRACE("setting real clip to %d,%d x %d,%d\n", -+ pos.x, pos.y, -+ real_clip.right - real_clip.left, -+ real_clip.bottom - real_clip.top); -+ - XMoveResizeWindow( data->display, clip_window, pos.x, pos.y, -- max( 1, clip->right - clip->left ), max( 1, clip->bottom - clip->top ) ); -+ max( 1, real_clip.right - real_clip.left ), max( 1, real_clip.bottom - real_clip.top ) ); - XMapWindow( data->display, clip_window ); - - /* if the rectangle is shrinking we may get a pointer warp */ -@@ -631,11 +644,17 @@ static void map_event_coords( HWND hwnd, Window window, Window event_root, int x - thread_data = x11drv_thread_data(); - if (!thread_data->clip_hwnd) return; - if (thread_data->clip_window != window) return; -- pt.x += clip_rect.left; -- pt.y += clip_rect.top; -+ pt.x = clip_rect.left; -+ pt.y = clip_rect.top; -+ fs_hack_point_user_to_real(&pt); -+ -+ pt.x += input->u.mi.dx; -+ pt.y += input->u.mi.dy; -+ fs_hack_point_real_to_user(&pt); - } - else if ((data = get_win_data( hwnd ))) - { -+ if (data->fs_hack) fs_hack_point_real_to_user(&pt); - if (window == root_window) pt = root_to_virtual_screen( pt.x, pt.y ); - else if (event_root == root_window) pt = root_to_virtual_screen( x_root, y_root ); - else -@@ -1513,11 +1532,13 @@ BOOL CDECL X11DRV_SetCursorPos( INT x, INT y ) - struct x11drv_thread_data *data = x11drv_init_thread_data(); - POINT pos = virtual_screen_to_root( x, y ); - -+ TRACE("real setting to %u, %u\n", pos.x, pos.y); -+ - XWarpPointer( data->display, root_window, root_window, 0, 0, 0, 0, pos.x, pos.y ); - data->warp_serial = NextRequest( data->display ); - XNoOp( data->display ); - XFlush( data->display ); /* avoids bad mouse lag in games that do their own mouse warping */ -- TRACE( "warped to %d,%d serial %lu\n", x, y, data->warp_serial ); -+ TRACE( "warped to (fake) %d,%d serial %lu\n", x, y, data->warp_serial ); - return TRUE; - } - -@@ -1933,9 +1933,11 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input, RAWINPUT *raw - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - XIValuatorClassInfo *x = &thread_data->x_valuator, *y = &thread_data->y_valuator; - const double *values = event->valuators.values, *raw_values = event->raw_values; -- double x_raw = 0, y_raw = 0, x_value = 0, y_value = 0, x_scale, y_scale; -+ double x_raw = 0, y_raw = 0, x_value = 0, y_value = 0, x_scale, y_scale, user_to_real_scale; - RECT virtual_rect; - int i; -+ POINT pt; -+ HMONITOR monitor; - - if (x->number < 0 || y->number < 0) return FALSE; - if (!event->valuators.mask_len) return FALSE; -@@ -1968,6 +1999,12 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input, RAWINPUT *raw - else - FIXME( "Unsupported relative/absolute X/Y axis mismatch\n." ); - -+ GetCursorPos(&pt); -+ monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL); -+ user_to_real_scale = fs_hack_get_user_to_real_scale(monitor); -+ input->u.mi.dx = lround((double)input->u.mi.dx / user_to_real_scale); -+ input->u.mi.dy = lround((double)input->u.mi.dy / user_to_real_scale); -+ - if (input->u.mi.dwFlags & MOUSEEVENTF_VIRTUALDESK) SetRect( &virtual_rect, 0, 0, 65535, 65535 ); - else virtual_rect = get_virtual_screen_rect(); - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 3f3deae59ba..bf5f9637227 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -40,6 +40,10 @@ - #include "wine/heap.h" - #include "wine/debug.h" - -+#ifndef ARRAY_SIZE -+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) -+#endif -+ - #ifdef SONAME_LIBGL - - WINE_DEFAULT_DEBUG_CHANNEL(wgl); -@@ -203,6 +207,13 @@ struct wgl_context - struct gl_drawable *drawables[2]; - struct gl_drawable *new_drawables[2]; - BOOL refresh_drawables; -+ BOOL fs_hack; -+ BOOL fs_hack_integer; -+ GLuint fs_hack_fbo, fs_hack_resolve_fbo; -+ GLuint fs_hack_color_texture, fs_hack_ds_texture; -+ GLuint fs_hack_color_renderbuffer, fs_hack_color_resolve_renderbuffer, fs_hack_ds_renderbuffer; -+ POINT setup_for; -+ GLuint current_draw_fbo, current_read_fbo; - struct list entry; - }; - -@@ -247,6 +258,10 @@ struct gl_drawable - int swap_interval; - BOOL refresh_swap_interval; - BOOL mutable_pf; -+ BOOL fs_hack; -+ BOOL fs_hack_did_swapbuf; -+ BOOL fs_hack_context_set_up; -+ BOOL has_scissor_indexed; - }; - - enum glx_swap_control_method -@@ -370,6 +385,10 @@ static int (*pglXSwapIntervalSGI)(int); - static void* (*pglXAllocateMemoryNV)(GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); - static void (*pglXFreeMemoryNV)(GLvoid *pointer); - -+static void (*pglScissorIndexed)(GLuint, GLint, GLint, GLsizei, GLsizei); -+static void (*pglScissorIndexedv)(GLuint, const GLint *); -+static void (*pglGetIntegeri_v)(GLenum, GLuint, GLint *); -+ - /* MESA GLX Extensions */ - static void (*pglXCopySubBufferMESA)(Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); - static int (*pglXSwapIntervalMESA)(unsigned int interval); -@@ -393,6 +412,27 @@ static void wglFinish(void); - static void wglFlush(void); - static const GLubyte *wglGetString(GLenum name); - -+/* Fullscreen hack */ -+static void (*pglBindFramebuffer)( GLenum target, GLuint framebuffer ); -+static void (*pglBindFramebufferEXT)( GLenum target, GLuint framebuffer ); -+static void (*pglBindRenderbuffer)( GLenum target, GLuint renderbuffer ); -+static void (*pglBlitFramebuffer)( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ); -+void (*pglDeleteFramebuffers)( GLsizei n, const GLuint *framebuffers ); -+void (*pglDeleteRenderbuffers)( GLsizei n, const GLuint *renderbuffers ); -+static void (*pglDrawBuffer)( GLenum buffer ); -+static void (*pglFramebufferRenderbuffer)( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ); -+static void (*pglFramebufferTexture2D)( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ); -+static void (*pglGenFramebuffers)( GLsizei n, GLuint *ids ); -+static void (*pglGenRenderbuffers)( GLsizei n, GLuint *renderbuffers ); -+static void (*pglReadBuffer)( GLenum src ); -+static void (*pglRenderbufferStorage)( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ); -+static void (*pglRenderbufferStorageMultisample)( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height ); -+ -+static void wglBindFramebuffer( GLenum target, GLuint framebuffer ); -+static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ); -+static void wglDrawBuffer( GLenum buffer ); -+static void wglReadBuffer( GLenum src ); -+ - /* check if the extension is present in the list */ - static BOOL has_extension( const char *list, const char *ext ) - { -@@ -568,9 +608,11 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context ) - /* redirect some standard OpenGL functions */ - #define REDIRECT(func) \ - do { p##func = opengl_funcs.gl.p_##func; opengl_funcs.gl.p_##func = w##func; } while(0) -+ REDIRECT( glDrawBuffer ); - REDIRECT( glFinish ); - REDIRECT( glFlush ); - REDIRECT( glGetString ); -+ REDIRECT( glReadBuffer ); - #undef REDIRECT - - pglXGetProcAddressARB = dlsym(opengl_handle, "glXGetProcAddressARB"); -@@ -579,6 +621,22 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context ) - goto failed; - } - -+ /* Fullscreen hack */ -+#define LOAD_FUNCPTR(func) p##func = (void *)pglXGetProcAddressARB((const unsigned char *)#func); -+ LOAD_FUNCPTR( glBindFramebuffer ); -+ LOAD_FUNCPTR( glBindFramebufferEXT ); -+ LOAD_FUNCPTR( glBindRenderbuffer ); -+ LOAD_FUNCPTR( glBlitFramebuffer ); -+ LOAD_FUNCPTR( glDeleteFramebuffers ); -+ LOAD_FUNCPTR( glDeleteRenderbuffers ); -+ LOAD_FUNCPTR( glFramebufferRenderbuffer ); -+ LOAD_FUNCPTR( glFramebufferTexture2D ); -+ LOAD_FUNCPTR( glGenFramebuffers ); -+ LOAD_FUNCPTR( glGenRenderbuffers ); -+ LOAD_FUNCPTR( glRenderbufferStorage ); -+ LOAD_FUNCPTR( glRenderbufferStorageMultisample ); -+#undef LOAD_FUNCPTR -+ - #define LOAD_FUNCPTR(f) do if((p##f = (void*)pglXGetProcAddressARB((const unsigned char*)#f)) == NULL) \ - { \ - ERR( "%s not found in libGL, disabling OpenGL.\n", #f ); \ -@@ -629,6 +687,10 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context ) - /* NV GLX Extension */ - LOAD_FUNCPTR(glXAllocateMemoryNV); - LOAD_FUNCPTR(glXFreeMemoryNV); -+ -+ LOAD_FUNCPTR(glScissorIndexed); -+ LOAD_FUNCPTR(glScissorIndexedv); -+ LOAD_FUNCPTR(glGetIntegeri_v); - #undef LOAD_FUNCPTR - - if(!X11DRV_WineGL_InitOpenglInfo()) goto failed; -@@ -719,6 +781,13 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context ) - pglXSwapBuffersMscOML = pglXGetProcAddressARB( (const GLubyte *)"glXSwapBuffersMscOML" ); - } - -+ if (has_extension( glExtensions, "GL_ARB_viewport_array")) -+ { -+ opengl_funcs.ext.p_glGetIntegeri_v = pglGetIntegeri_v; -+ opengl_funcs.ext.p_glScissorIndexed = pglScissorIndexed; -+ opengl_funcs.ext.p_glScissorIndexedv = pglScissorIndexedv; -+ } -+ - X11DRV_WineGL_LoadExtensions(); - init_pixel_formats( gdi_display ); - return TRUE; -@@ -1329,10 +1398,17 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel - - if (!known_child && !GetWindow( hwnd, GW_CHILD ) && GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow()) /* childless top-level window */ - { -+ struct x11drv_win_data *data; -+ - gl->type = DC_GL_WINDOW; - gl->window = create_client_window( hwnd, visual ); - if (gl->window) - gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); -+ data = get_win_data( hwnd ); -+ gl->fs_hack = data->fs_hack; -+ if (gl->fs_hack) -+ TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); -+ release_win_data( data ); - TRACE( "%p created client %lx drawable %lx\n", hwnd, gl->window, gl->drawable ); - } - #ifdef SONAME_LIBXCOMPOSITE -@@ -1454,6 +1530,9 @@ static BOOL set_pixel_format(HDC hdc, int format, BOOL allow_change) - void sync_gl_drawable( HWND hwnd, BOOL known_child ) - { - struct gl_drawable *old, *new; -+ struct x11drv_win_data *data; -+ -+ TRACE("%p\n", hwnd); - - if (!(old = get_gl_drawable( hwnd, 0 ))) return; - -@@ -1472,6 +1551,15 @@ void sync_gl_drawable( HWND hwnd, BOOL known_child ) - default: - break; - } -+ -+ if (DC_GL_PIXMAP_WIN != old->type) { -+ data = get_win_data( hwnd ); -+ old->fs_hack = data->fs_hack; -+ if (old->fs_hack) -+ TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); -+ release_win_data( data ); -+ } -+ - release_gl_drawable( old ); - } - -@@ -1779,6 +1867,10 @@ static BOOL WINAPI glxdrv_wglDeleteContext(struct wgl_context *ctx) - static PROC WINAPI glxdrv_wglGetProcAddress(LPCSTR lpszProc) - { - if (!strncmp(lpszProc, "wgl", 3)) return NULL; -+ if (!strcmp(lpszProc, "glBindFramebuffer")) -+ return (PROC)wglBindFramebuffer; -+ if (!strcmp(lpszProc, "glBindFramebufferEXT")) -+ return (PROC)wglBindFramebufferEXT; - return pglXGetProcAddressARB((const GLubyte*)lpszProc); - } - -@@ -1798,12 +1890,248 @@ static void set_context_drawables( struct wgl_context *ctx, struct gl_drawable * - for (i = 0; i < 4; i++) release_gl_drawable( prev[i] ); - } - -+struct fs_hack_fbconfig_attribs -+{ -+ int render_type; -+ int buffer_size; -+ int red_size; -+ int green_size; -+ int blue_size; -+ int alpha_size; -+ int depth_size; -+ int stencil_size; -+ int doublebuffer; -+ int samples; -+ int srgb; -+}; -+ -+struct fs_hack_fbo_attachments_config -+{ -+ GLint color_internalformat; -+ GLenum color_format; -+ GLenum color_type; -+ GLint ds_internalformat; -+ GLenum ds_format; -+ GLenum ds_type; -+ int samples; -+}; -+ -+static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_hack_fbconfig_attribs *attribs, -+ struct fs_hack_fbo_attachments_config *config ) -+{ -+ if (attribs->render_type != GLX_RGBA_BIT) -+ FIXME( "Unsupported GLX_RENDER_TYPE %#x.\n", attribs->render_type ); -+ if (attribs->red_size != 8 || attribs->green_size != 8 || attribs->blue_size != 8) -+ FIXME( "Unsupported RGBA color sizes {%u, %u, %u, %u}.\n", -+ attribs->red_size, attribs->green_size, attribs->blue_size, attribs->alpha_size ); -+ if (attribs->srgb) -+ config->color_internalformat = attribs->alpha_size ? GL_SRGB8_ALPHA8 : GL_SRGB8; -+ else -+ config->color_internalformat = attribs->alpha_size ? GL_RGBA8 : GL_RGB8; -+ config->color_format = GL_BGRA; -+ config->color_type = GL_UNSIGNED_INT_8_8_8_8_REV; -+ if (attribs->depth_size || attribs->stencil_size) -+ { -+ if (attribs->depth_size != 24) -+ FIXME( "Unsupported depth buffer size %u.\n", attribs->depth_size ); -+ if (attribs->stencil_size && attribs->stencil_size != 8) -+ FIXME( "Unsupported stencil buffer size %u.\n", attribs->stencil_size ); -+ config->ds_internalformat = attribs->stencil_size ? GL_DEPTH24_STENCIL8 : GL_DEPTH_COMPONENT24; -+ config->ds_format = attribs->stencil_size ? GL_DEPTH_STENCIL : GL_DEPTH_COMPONENT; -+ config->ds_type = attribs->stencil_size ? GL_UNSIGNED_INT_24_8 : GL_UNSIGNED_INT; -+ } -+ else -+ { -+ config->ds_internalformat = config->ds_format = config->ds_type = 0; -+ } -+ config->samples = attribs->samples; -+} -+ -+static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable *gl ) -+{ -+ GLuint prev_draw_fbo, prev_read_fbo, prev_texture, prev_renderbuffer; -+ float prev_clear_color[4]; -+ unsigned int i; -+ struct fs_hack_fbo_attachments_config config; -+ struct fs_hack_fbconfig_attribs attribs; -+ static const struct fbconfig_attribs_query -+ { -+ int attribute; -+ unsigned int offset; -+ } -+ queries[] = -+ { -+ {GLX_RENDER_TYPE, offsetof(struct fs_hack_fbconfig_attribs, render_type)}, -+ {GLX_BUFFER_SIZE, offsetof(struct fs_hack_fbconfig_attribs, buffer_size)}, -+ {GLX_RED_SIZE, offsetof(struct fs_hack_fbconfig_attribs, red_size)}, -+ {GLX_GREEN_SIZE, offsetof(struct fs_hack_fbconfig_attribs, green_size)}, -+ {GLX_BLUE_SIZE, offsetof(struct fs_hack_fbconfig_attribs, blue_size)}, -+ {GLX_ALPHA_SIZE, offsetof(struct fs_hack_fbconfig_attribs, alpha_size)}, -+ {GLX_DEPTH_SIZE, offsetof(struct fs_hack_fbconfig_attribs, depth_size)}, -+ {GLX_STENCIL_SIZE, offsetof(struct fs_hack_fbconfig_attribs, stencil_size)}, -+ {GLX_DOUBLEBUFFER, offsetof(struct fs_hack_fbconfig_attribs, doublebuffer)}, -+ {GLX_SAMPLES_ARB, offsetof(struct fs_hack_fbconfig_attribs, samples)}, -+ {GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, offsetof(struct fs_hack_fbconfig_attribs, srgb)}, -+ }; -+ BYTE *ptr = (BYTE *)&attribs; -+ -+ if (ctx->fs_hack) -+ { -+ MONITORINFO monitor_info; -+ HMONITOR monitor; -+ int width, height; -+ -+ monitor = fs_hack_monitor_from_hwnd(WindowFromDC(ctx->hdc)); -+ memset(&monitor_info, 0, sizeof(monitor_info)); -+ monitor_info.cbSize = sizeof(monitor_info); -+ GetMonitorInfoW(monitor, &monitor_info); -+ width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left; -+ height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top; -+ -+ TRACE("Render buffer width:%d height:%d\n", width, height); -+ -+ opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_draw_fbo ); -+ opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&prev_read_fbo ); -+ opengl_funcs.gl.p_glGetIntegerv( GL_TEXTURE_BINDING_2D, (GLint *)&prev_texture ); -+ opengl_funcs.gl.p_glGetIntegerv( GL_RENDERBUFFER_BINDING, (GLint *)&prev_renderbuffer ); -+ opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, prev_clear_color ); -+ TRACE( "Previous draw FBO %u, read FBO %u for ctx %p\n", prev_draw_fbo, prev_read_fbo, ctx); -+ -+ if (!ctx->fs_hack_fbo) -+ { -+ pglGenFramebuffers( 1, &ctx->fs_hack_fbo ); -+ pglGenFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); -+ TRACE( "Created FBO %u for fullscreen hack.\n", ctx->fs_hack_fbo ); -+ } -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); -+ -+ for (i = 0; i < ARRAY_SIZE(queries); ++i) -+ pglXGetFBConfigAttrib( gdi_display, gl->format->fbconfig, queries[i].attribute, -+ (int *)&ptr[queries[i].offset] ); -+ fs_hack_get_attachments_config( gl, &attribs, &config ); -+ -+ if (config.samples) -+ { -+ if (!ctx->fs_hack_color_renderbuffer) -+ pglGenRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); -+ pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); -+ pglRenderbufferStorageMultisample( GL_RENDERBUFFER, config.samples, -+ config.color_internalformat, width, height ); -+ pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, -+ GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); -+ TRACE( "Created renderbuffer %u for fullscreen hack.\n", ctx->fs_hack_color_renderbuffer ); -+ pglGenRenderbuffers( 1, &ctx->fs_hack_color_resolve_renderbuffer ); -+ pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_resolve_renderbuffer ); -+ pglRenderbufferStorage( GL_RENDERBUFFER, config.color_internalformat, width, height ); -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); -+ pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, -+ GL_RENDERBUFFER, ctx->fs_hack_color_resolve_renderbuffer ); -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); -+ pglBindRenderbuffer( GL_RENDERBUFFER, prev_renderbuffer ); -+ TRACE( "Also created renderbuffer %u and FBO %u for color resolve.\n", -+ ctx->fs_hack_color_resolve_renderbuffer, ctx->fs_hack_resolve_fbo ); -+ } -+ else -+ { -+ if (!ctx->fs_hack_color_texture) -+ opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_color_texture ); -+ opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_color_texture ); -+ opengl_funcs.gl.p_glTexImage2D( GL_TEXTURE_2D, 0, config.color_internalformat, width, height, -+ 0, config.color_format, config.color_type, NULL); -+ opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); -+ opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, prev_texture ); -+ pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, -+ GL_TEXTURE_2D, ctx->fs_hack_color_texture, 0 ); -+ TRACE( "Created texture %u for fullscreen hack.\n", ctx->fs_hack_color_texture ); -+ } -+ -+ if (config.ds_internalformat) -+ { -+ if (config.samples) -+ { -+ if (!ctx->fs_hack_ds_renderbuffer) -+ pglGenRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); -+ pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_ds_renderbuffer ); -+ pglRenderbufferStorageMultisample( GL_RENDERBUFFER, config.samples, -+ config.ds_internalformat, width, height ); -+ pglBindRenderbuffer( GL_RENDERBUFFER, prev_renderbuffer ); -+ if (attribs.depth_size) -+ pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, -+ GL_RENDERBUFFER, ctx->fs_hack_ds_renderbuffer ); -+ if (attribs.stencil_size) -+ pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, -+ GL_RENDERBUFFER, ctx->fs_hack_ds_renderbuffer ); -+ TRACE( "Created DS renderbuffer %u for fullscreen hack.\n", ctx->fs_hack_ds_renderbuffer ); -+ } -+ else -+ { -+ if (!ctx->fs_hack_ds_texture) -+ opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_ds_texture ); -+ opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_ds_texture ); -+ opengl_funcs.gl.p_glTexImage2D( GL_TEXTURE_2D, 0, config.ds_internalformat, width, height, -+ 0, config.ds_format, config.ds_type, NULL); -+ opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); -+ opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, prev_texture ); -+ if (attribs.depth_size) -+ pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, ctx->fs_hack_ds_texture, 0 ); -+ if (attribs.stencil_size) -+ pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, ctx->fs_hack_ds_texture, 0 ); -+ TRACE( "Created DS texture %u for fullscreen hack.\n", ctx->fs_hack_ds_texture ); -+ } -+ } -+ -+ opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); -+ if(!gl->fs_hack_context_set_up) -+ opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); -+ pglDrawBuffer( GL_BACK ); -+ if(!gl->fs_hack_context_set_up) -+ opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); -+ opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], prev_clear_color[2], prev_clear_color[3] ); -+ wglBindFramebuffer( GL_DRAW_FRAMEBUFFER, prev_draw_fbo ); -+ wglBindFramebuffer( GL_READ_FRAMEBUFFER, prev_read_fbo ); -+ -+ ctx->setup_for.x = width; -+ ctx->setup_for.y = height; -+ gl->has_scissor_indexed = has_extension(glExtensions, "GL_ARB_viewport_array"); -+ ctx->fs_hack_integer = fs_hack_is_integer(); -+ gl->fs_hack_context_set_up = TRUE; -+ } -+ else -+ { -+ TRACE( "Releasing fullscreen hack texture %u and FBO %u\n", ctx->fs_hack_color_texture, ctx->fs_hack_fbo ); -+ if (ctx->current_draw_fbo == ctx->fs_hack_fbo) -+ { -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); -+ ctx->current_draw_fbo = 0; -+ } -+ if (ctx->current_read_fbo == ctx->fs_hack_fbo) -+ { -+ pglBindFramebuffer( GL_READ_FRAMEBUFFER, 0 ); -+ ctx->current_read_fbo = 0; -+ } -+ -+ pglDeleteRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); -+ pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_resolve_renderbuffer ); -+ pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); -+ opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_ds_texture ); -+ opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_color_texture ); -+ ctx->fs_hack_color_renderbuffer = ctx->fs_hack_color_resolve_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; -+ ctx->fs_hack_color_texture = ctx->fs_hack_ds_texture = 0; -+ pglDeleteFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); -+ pglDeleteFramebuffers( 1, &ctx->fs_hack_fbo ); -+ ctx->fs_hack_fbo = 0; -+ -+ gl->fs_hack_context_set_up = FALSE; -+ } -+} -+ - /*********************************************************************** - * glxdrv_wglMakeCurrent - */ - static BOOL WINAPI glxdrv_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) - { -- BOOL ret = FALSE; -+ BOOL ret = FALSE, setup_fs_hack = FALSE; - struct gl_drawable *gl; - - TRACE("(%p,%p)\n", hdc, ctx); -@@ -1832,10 +2160,17 @@ static BOOL WINAPI glxdrv_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) - if (ret) - { - NtCurrentTeb()->glContext = ctx; -- ctx->has_been_current = TRUE; -+ if (ctx->fs_hack != gl->fs_hack || (ctx->fs_hack && ctx->drawables[0] != gl)) -+ setup_fs_hack = TRUE; - ctx->hdc = hdc; - set_context_drawables( ctx, gl, gl ); - ctx->refresh_drawables = FALSE; -+ if (setup_fs_hack) -+ { -+ ctx->fs_hack = gl->fs_hack; -+ fs_hack_setup_context( ctx, gl ); -+ } -+ ctx->has_been_current = TRUE; - LeaveCriticalSection( &context_section ); - goto done; - } -@@ -1854,7 +2189,7 @@ static BOOL WINAPI glxdrv_wglMakeCurrent(HDC hdc, struct wgl_context *ctx) - */ - static BOOL X11DRV_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct wgl_context *ctx ) - { -- BOOL ret = FALSE; -+ BOOL ret = FALSE, setup_fs_hack = FALSE; - struct gl_drawable *draw_gl, *read_gl = NULL; - - TRACE("(%p,%p,%p)\n", draw_hdc, read_hdc, ctx); -@@ -1877,11 +2212,18 @@ static BOOL X11DRV_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, struct - read_gl ? read_gl->drawable : 0, ctx->ctx); - if (ret) - { -- ctx->has_been_current = TRUE; -+ NtCurrentTeb()->glContext = ctx; -+ if (ctx->fs_hack != draw_gl->fs_hack || (ctx->fs_hack && ctx->drawables[0] != draw_gl)) -+ setup_fs_hack = TRUE; - ctx->hdc = draw_hdc; - set_context_drawables( ctx, draw_gl, read_gl ); - ctx->refresh_drawables = FALSE; -- NtCurrentTeb()->glContext = ctx; -+ if (setup_fs_hack) -+ { -+ ctx->fs_hack = draw_gl->fs_hack; -+ fs_hack_setup_context( ctx, draw_gl ); -+ } -+ ctx->has_been_current = TRUE; - LeaveCriticalSection( &context_section ); - goto done; - } -@@ -1940,6 +2282,145 @@ static BOOL WINAPI glxdrv_wglShareLists(struct wgl_context *org, struct wgl_cont - return FALSE; - } - -+static void wglBindFramebuffer( GLenum target, GLuint framebuffer ) -+{ -+ struct wgl_context *ctx = NtCurrentTeb()->glContext; -+ -+ TRACE( "target %#x, framebuffer %u\n", target, framebuffer ); -+ if (ctx->fs_hack && !framebuffer) -+ framebuffer = ctx->fs_hack_fbo; -+ -+ if (target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER) -+ ctx->current_draw_fbo = framebuffer; -+ if (target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER) -+ ctx->current_read_fbo = framebuffer; -+ -+ pglBindFramebuffer( target, framebuffer ); -+} -+ -+static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ) -+{ -+ struct wgl_context *ctx = NtCurrentTeb()->glContext; -+ -+ TRACE( "target %#x, framebuffer %u\n", target, framebuffer ); -+ if (ctx->fs_hack && !framebuffer) -+ framebuffer = ctx->fs_hack_fbo; -+ -+ if (target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER) -+ ctx->current_draw_fbo = framebuffer; -+ if (target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER) -+ ctx->current_read_fbo = framebuffer; -+ -+ pglBindFramebufferEXT( target, framebuffer ); -+} -+ -+static void wglDrawBuffer( GLenum buffer ) -+{ -+ struct wgl_context *ctx = NtCurrentTeb()->glContext; -+ -+ if (ctx->fs_hack && ctx->current_draw_fbo == ctx->fs_hack_fbo) -+ { -+ TRACE("Overriding %#x with GL_COLOR_ATTACHMENT0\n", buffer); -+ buffer = GL_COLOR_ATTACHMENT0; -+ } -+ pglDrawBuffer( buffer ); -+} -+ -+static void wglReadBuffer( GLenum buffer ) -+{ -+ struct wgl_context *ctx = NtCurrentTeb()->glContext; -+ -+ if (ctx->fs_hack && ctx->current_read_fbo == ctx->fs_hack_fbo) -+ { -+ TRACE("Overriding %#x with GL_COLOR_ATTACHMENT0\n", buffer); -+ buffer = GL_COLOR_ATTACHMENT0; -+ } -+ pglReadBuffer( buffer ); -+} -+ -+static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer ) -+{ -+ struct wgl_context *ctx = NtCurrentTeb()->glContext; -+ SIZE scaled, src, real; -+ GLuint prev_draw_fbo, prev_read_fbo; -+ GLint prev_scissor[4]; -+ RECT user_rect, real_rect; -+ POINT scaled_origin; -+ float prev_clear_color[4]; -+ HMONITOR monitor; -+ -+ monitor = fs_hack_monitor_from_hwnd(WindowFromDC(ctx->hdc)); -+ scaled = fs_hack_get_scaled_screen_size(monitor); -+ user_rect = fs_hack_current_mode(monitor); -+ real_rect = fs_hack_real_mode(monitor); -+ src.cx = user_rect.right - user_rect.left; -+ src.cy = user_rect.bottom - user_rect.top; -+ real.cx = real_rect.right - real_rect.left; -+ real.cy = real_rect.bottom - real_rect.top; -+ scaled_origin.x = user_rect.left; -+ scaled_origin.y = user_rect.top; -+ fs_hack_point_user_to_real(&scaled_origin); -+ scaled_origin.x -= real_rect.left; -+ scaled_origin.y -= real_rect.top; -+ -+ TRACE("scaled:%dx%d src:%dx%d real:%dx%d user_rect:%s real_rect:%s scaled_origin:%s\n", scaled.cx, scaled.cy, -+ src.cx, src.cy, real.cx, real.cy, wine_dbgstr_rect(&user_rect), wine_dbgstr_rect(&real_rect), -+ wine_dbgstr_point(&scaled_origin)); -+ -+ if(ctx->setup_for.x != src.cx || -+ ctx->setup_for.y != src.cy) -+ fs_hack_setup_context( ctx, gl ); -+ -+ TRACE( "Blitting from FBO %u %ux%u to %ux%u\n", ctx->fs_hack_fbo, src.cx, src.cy, scaled.cx, scaled.cy ); -+ -+ opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_draw_fbo ); -+ opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&prev_read_fbo ); -+ TRACE( "Previous draw FBO %u, read FBO %u\n", prev_draw_fbo, prev_read_fbo ); -+ -+ if(gl->has_scissor_indexed){ -+ opengl_funcs.ext.p_glGetIntegeri_v(GL_SCISSOR_BOX, 0, prev_scissor); -+ opengl_funcs.ext.p_glScissorIndexed(0, 0, 0, real.cx, real.cy); -+ }else{ -+ opengl_funcs.gl.p_glGetIntegerv(GL_SCISSOR_BOX, prev_scissor); -+ opengl_funcs.gl.p_glScissor(0, 0, real.cx, real.cy); -+ } -+ -+ pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_fbo ); -+ if (ctx->fs_hack_color_resolve_renderbuffer) -+ { -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); -+ pglBlitFramebuffer( 0, 0, src.cx, src.cy, 0, 0, src.cx, src.cy, GL_COLOR_BUFFER_BIT, GL_NEAREST ); -+ pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); -+ } -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); -+ -+ //HACK -+ //pglDrawBuffer( draw_buffer ); -+ pglDrawBuffer( GL_BACK ); -+ -+ opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, prev_clear_color ); -+ opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); -+ opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); -+ opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], prev_clear_color[2], prev_clear_color[3] ); -+ -+ pglBlitFramebuffer( 0, 0, src.cx, src.cy, -+ scaled_origin.x, scaled_origin.y, scaled_origin.x + scaled.cx, scaled_origin.y + scaled.cy, -+ GL_COLOR_BUFFER_BIT, ctx->fs_hack_integer ? GL_NEAREST : GL_LINEAR ); -+ //HACK -+ if ( draw_buffer == GL_FRONT ) -+ pglXSwapBuffers(gdi_display, gl->drawable); -+ -+ if(gl->has_scissor_indexed){ -+ opengl_funcs.ext.p_glScissorIndexedv(0, prev_scissor); -+ }else{ -+ opengl_funcs.gl.p_glScissor(prev_scissor[0], prev_scissor[1], -+ prev_scissor[2], prev_scissor[3]); -+ } -+ -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, prev_draw_fbo ); -+ pglBindFramebuffer( GL_READ_FRAMEBUFFER, prev_read_fbo ); -+} -+ - static void wglFinish(void) - { - struct x11drv_escape_present_drawable escape; -@@ -1959,6 +2440,18 @@ static void wglFinish(void) - default: break; - } - sync_context(ctx); -+ -+ if (gl->fs_hack) { -+ ctx->fs_hack = gl->fs_hack; -+ if(!gl->fs_hack_context_set_up) -+ fs_hack_setup_context( ctx, gl ); -+ if(!gl->fs_hack_did_swapbuf) -+ fs_hack_blit_framebuffer( gl, GL_FRONT ); -+ }else if(gl->fs_hack_context_set_up){ -+ ctx->fs_hack = FALSE; -+ fs_hack_setup_context(ctx, gl); -+ } -+ - release_gl_drawable( gl ); - } - -@@ -1985,6 +2478,18 @@ static void wglFlush(void) - default: break; - } - sync_context(ctx); -+ -+ if (gl->fs_hack) { -+ ctx->fs_hack = gl->fs_hack; -+ if(!gl->fs_hack_context_set_up) -+ fs_hack_setup_context( ctx, gl ); -+ if(!gl->fs_hack_did_swapbuf) -+ fs_hack_blit_framebuffer( gl, GL_FRONT ); -+ }else if(gl->fs_hack_context_set_up){ -+ ctx->fs_hack = FALSE; -+ fs_hack_setup_context(ctx, gl); -+ } -+ - release_gl_drawable( gl ); - } - -@@ -3363,6 +3868,16 @@ static BOOL WINAPI glxdrv_wglSwapBuffers( HDC hdc ) - target_sbc = pglXSwapBuffersMscOML( gdi_display, gl->drawable, 0, 0, 0 ); - break; - } -+ if (gl->fs_hack){ -+ ctx->fs_hack = gl->fs_hack; -+ if(!gl->fs_hack_context_set_up) -+ fs_hack_setup_context( ctx, gl ); -+ fs_hack_blit_framebuffer( gl, GL_BACK ); -+ gl->fs_hack_did_swapbuf = TRUE; -+ }else if(gl->fs_hack_context_set_up){ -+ ctx->fs_hack = FALSE; -+ fs_hack_setup_context(ctx, gl); -+ } - pglXSwapBuffers(gdi_display, gl->drawable); - break; - } -diff --git a/dlls/winex11.drv/settings.c b/dlls/winex11.drv/settings.c -index cea7ebbc6b7..5af96dfb5be 100644 ---- a/dlls/winex11.drv/settings.c -+++ b/dlls/winex11.drv/settings.c -@@ -36,15 +36,6 @@ - - WINE_DEFAULT_DEBUG_CHANNEL(x11settings); - --struct x11drv_display_setting --{ -- ULONG_PTR id; -- BOOL placed; -- RECT new_rect; -- RECT desired_rect; -- DEVMODEW desired_mode; --}; -- - struct x11drv_display_depth - { - struct list entry; -@@ -88,6 +79,11 @@ void X11DRV_Settings_SetHandler(const struct x11drv_settings_handler *new_handle - } - } - -+struct x11drv_settings_handler X11DRV_Settings_GetHandler(void) -+{ -+ return handler; -+} -+ - /*********************************************************************** - * Default handlers if resolution switching is not enabled - * -@@ -170,7 +166,6 @@ static LONG nores_set_current_mode(ULONG_PTR id, DEVMODEW *mode) - return DISP_CHANGE_SUCCESSFUL; - } - --/* default handler only gets the current X desktop resolution */ - void X11DRV_Settings_Init(void) - { - struct x11drv_settings_handler nores_handler; -@@ -184,6 +179,7 @@ void X11DRV_Settings_Init(void) - nores_handler.free_modes = nores_free_modes; - nores_handler.get_current_mode = nores_get_current_mode; - nores_handler.set_current_mode = nores_set_current_mode; -+ nores_handler.convert_coordinates = NULL; - X11DRV_Settings_SetHandler(&nores_handler); - } - -@@ -367,7 +363,7 @@ BOOL get_primary_adapter(WCHAR *name) - return FALSE; - } - --static int mode_compare(const void *p1, const void *p2) -+int mode_compare(const void *p1, const void *p2) - { - DWORD a_width, a_height, b_width, b_height; - const DEVMODEW *a = p1, *b = p2; -@@ -832,7 +828,6 @@ static POINT get_placement_offset(const struct x11drv_display_setting *displays, - - static void place_all_displays(struct x11drv_display_setting *displays, INT display_count) - { -- INT left_most = INT_MAX, top_most = INT_MAX; - INT placing_idx, display_idx; - POINT min_offset, offset; - -@@ -867,15 +862,6 @@ static void place_all_displays(struct x11drv_display_setting *displays, INT disp - { - displays[display_idx].desired_mode.u1.s2.dmPosition.x = displays[display_idx].new_rect.left; - displays[display_idx].desired_mode.u1.s2.dmPosition.y = displays[display_idx].new_rect.top; -- left_most = min(left_most, displays[display_idx].new_rect.left); -- top_most = min(top_most, displays[display_idx].new_rect.top); -- } -- -- /* Convert virtual screen coordinates to root coordinates */ -- for (display_idx = 0; display_idx < display_count; ++display_idx) -- { -- displays[display_idx].desired_mode.u1.s2.dmPosition.x -= left_most; -- displays[display_idx].desired_mode.u1.s2.dmPosition.y -= top_most; - } - } - -diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c -index 1a077d9323e..6bfbb9dc7bc 100644 ---- a/dlls/winex11.drv/vulkan.c -+++ b/dlls/winex11.drv/vulkan.c -@@ -610,6 +610,64 @@ static VkSurfaceKHR X11DRV_wine_get_native_surface(VkSurfaceKHR surface) - return x11_surface->surface; - } - -+static VkBool32 X11DRV_query_fs_hack(VkSurfaceKHR surface, VkExtent2D *real_sz, VkExtent2D *user_sz, -+ VkRect2D *dst_blit, VkFilter *filter) -+{ -+ struct wine_vk_surface *x11_surface = surface_from_handle(surface); -+ HMONITOR monitor; -+ HWND hwnd; -+ -+ if (wm_is_steamcompmgr(gdi_display)) -+ return VK_FALSE; -+ -+ if (XFindContext(gdi_display, x11_surface->window, winContext, (char **)&hwnd) != 0) -+ { -+ ERR("Failed to find hwnd context\n"); -+ return VK_FALSE; -+ } -+ -+ monitor = fs_hack_monitor_from_hwnd(hwnd); -+ if(fs_hack_enabled(monitor)){ -+ RECT real_rect = fs_hack_real_mode(monitor); -+ RECT user_rect = fs_hack_current_mode(monitor); -+ SIZE scaled = fs_hack_get_scaled_screen_size(monitor); -+ POINT scaled_origin; -+ -+ scaled_origin.x = user_rect.left; -+ scaled_origin.y = user_rect.top; -+ fs_hack_point_user_to_real(&scaled_origin); -+ scaled_origin.x -= real_rect.left; -+ scaled_origin.y -= real_rect.top; -+ -+ TRACE("real_rect:%s user_rect:%s scaled:%dx%d scaled_origin:%s\n", wine_dbgstr_rect(&real_rect), -+ wine_dbgstr_rect(&user_rect), scaled.cx, scaled.cy, wine_dbgstr_point(&scaled_origin)); -+ -+ if(real_sz){ -+ real_sz->width = real_rect.right - real_rect.left; -+ real_sz->height = real_rect.bottom - real_rect.top; -+ } -+ -+ if(user_sz){ -+ user_sz->width = user_rect.right - user_rect.left; -+ user_sz->height = user_rect.bottom - user_rect.top; -+ } -+ -+ if(dst_blit){ -+ dst_blit->offset.x = scaled_origin.x; -+ dst_blit->offset.y = scaled_origin.y; -+ dst_blit->extent.width = scaled.cx; -+ dst_blit->extent.height = scaled.cy; -+ } -+ -+ if(filter) -+ *filter = fs_hack_is_integer() ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; -+ -+ return VK_TRUE; -+ } -+ -+ return VK_FALSE; -+} -+ - static const struct vulkan_funcs vulkan_funcs = - { - X11DRV_vkCreateInstance, -@@ -634,6 +692,7 @@ static const struct vulkan_funcs vulkan_funcs = - X11DRV_vkQueuePresentKHR, - - X11DRV_wine_get_native_surface, -+ X11DRV_query_fs_hack, - }; - - static void *X11DRV_get_vk_device_proc_addr(const char *name) -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index c6b23d857af..a60001aec6d 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -475,6 +475,11 @@ static void sync_window_region( struct x11drv_win_data *data, HRGN win_region ) - HRGN hrgn = win_region; - - if (!data->whole_window) return; -+ -+ if(data->fs_hack){ -+ ERR("shaped windows with fs hack not supported, things may go badly\n"); -+ } -+ - data->shaped = FALSE; - - if (IsRectEmpty( &data->window_rect )) /* set an empty shape */ -@@ -1144,6 +1149,7 @@ void update_user_time( Time time ) - void update_net_wm_states( struct x11drv_win_data *data ) - { - DWORD i, style, ex_style, new_state = 0; -+ HMONITOR monitor; - unsigned long net_wm_bypass_compositor = 0; - - if (!data->managed) return; -@@ -1152,21 +1158,38 @@ void update_net_wm_states( struct x11drv_win_data *data ) - style = GetWindowLongW( data->hwnd, GWL_STYLE ); - if (style & WS_MINIMIZE) - new_state |= data->net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED)); -- if (is_window_rect_full_screen( &data->whole_rect )) -+ monitor = fs_hack_monitor_from_hwnd( data->hwnd ); -+ if ((!data->fs_hack || fs_hack_enabled( monitor )) && is_window_rect_full_screen( &data->whole_rect )) - { - if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) - new_state |= (1 << NET_WM_STATE_MAXIMIZED); - else if (!(style & WS_MINIMIZE)) - { -- net_wm_bypass_compositor = 1; -- new_state |= (1 << NET_WM_STATE_FULLSCREEN); -+ if (!wm_is_steamcompmgr(data->display) || !fs_hack_enabled(monitor)) -+ { -+ /* when fs hack is enabled, we don't want steamcompmgr to resize the window to be fullscreened */ -+ net_wm_bypass_compositor = 1; -+ new_state |= (1 << NET_WM_STATE_FULLSCREEN); -+ } - } - } - else if (style & WS_MAXIMIZE) - new_state |= (1 << NET_WM_STATE_MAXIMIZED); - - ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE ); -- if (ex_style & WS_EX_TOPMOST) -+ if ((ex_style & WS_EX_TOPMOST) && -+ /* mutter < 3.31 has a bug where a FULLSCREEN and ABOVE window when -+ * minimized will incorrectly show a black window. this workaround -+ * should be removed when the fix is widely distributed. see -+ * mutter issue #306. */ -+ !(wm_is_mutter(data->display) && (new_state & (1 << NET_WM_STATE_FULLSCREEN))) && -+ -+ /* KDE refuses to allow alt-tabbing out of fullscreen+above -+ * windows. Other WMs (XFCE) don't make fullscreen (without above) -+ * windows appear above their panels. KDE still does the right -+ * thing with fullscreen-only windows, so let's comprimise by not -+ * setting above on KDE. */ -+ !wm_is_kde(data->display)) - new_state |= (1 << NET_WM_STATE_ABOVE); - if (!data->add_taskbar) - { -@@ -1213,6 +1236,12 @@ void update_net_wm_states( struct x11drv_win_data *data ) - i, data->hwnd, data->whole_window, - (new_state & (1 << i)) != 0, (data->net_wm_state & (1 << i)) != 0 ); - -+ if(i == NET_WM_STATE_FULLSCREEN) -+ { -+ data->pending_fullscreen = (new_state & (1 << i)) != 0; -+ TRACE("set pending_fullscreen to: %u\n", data->pending_fullscreen); -+ } -+ - xev.xclient.data.l[0] = (new_state & (1 << i)) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; - xev.xclient.data.l[1] = X11DRV_Atoms[net_wm_state_atoms[i] - FIRST_XATOM]; - xev.xclient.data.l[2] = ((net_wm_state_atoms[i] == XATOM__NET_WM_STATE_MAXIMIZED_VERT) ? -@@ -1458,8 +1487,19 @@ static void sync_window_position( struct x11drv_win_data *data, - /* resizing a managed maximized window is not allowed */ - if (!(style & WS_MAXIMIZE) || !data->managed) - { -- changes.width = data->whole_rect.right - data->whole_rect.left; -- changes.height = data->whole_rect.bottom - data->whole_rect.top; -+ if(data->fs_hack){ -+ HMONITOR monitor; -+ RECT rect; -+ -+ monitor = fs_hack_monitor_from_hwnd(data->hwnd); -+ rect = fs_hack_real_mode(monitor); -+ changes.width = rect.right - rect.left; -+ changes.height = rect.bottom - rect.top; -+ TRACE("change width:%d height:%d\n", changes.width, changes.height); -+ }else{ -+ changes.width = data->whole_rect.right - data->whole_rect.left; -+ changes.height = data->whole_rect.bottom - data->whole_rect.top; -+ } - /* if window rect is empty force size to 1x1 */ - if (changes.width <= 0 || changes.height <= 0) changes.width = changes.height = 1; - if (changes.width > 65535) changes.width = 65535; -@@ -1542,6 +1582,20 @@ static void sync_client_position( struct x11drv_win_data *data, - if (changes.width != old_client_rect->right - old_client_rect->left) mask |= CWWidth; - if (changes.height != old_client_rect->bottom - old_client_rect->top) mask |= CWHeight; - -+ if(data->fs_hack){ -+ HMONITOR monitor; -+ RECT rect; -+ -+ monitor = fs_hack_monitor_from_hwnd(data->hwnd); -+ rect = fs_hack_real_mode(monitor); -+ changes.x = 0; -+ changes.y = 0; -+ changes.width = rect.right - rect.left; -+ changes.height = rect.bottom - rect.top; -+ mask = CWX | CWY | CWWidth | CWHeight; -+ TRACE( "x:%d y:%d width:%d height:%d\n", changes.x, changes.y, changes.width, changes.height ); -+ } -+ - if (mask) - { - TRACE( "setting client win %lx pos %d,%d,%dx%d changes=%x\n", -@@ -1713,6 +1767,16 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) - cx = min( max( 1, data->client_rect.right - data->client_rect.left ), 65535 ); - cy = min( max( 1, data->client_rect.bottom - data->client_rect.top ), 65535 ); - -+ if(data->fs_hack){ -+ HMONITOR monitor = fs_hack_monitor_from_hwnd(hwnd); -+ RECT rect = fs_hack_real_mode(monitor); -+ cx = rect.right - rect.left; -+ cy = rect.bottom - rect.top; -+ -+ TRACE("width:%d height:%d\n", cx, cy); -+ } -+ -+ TRACE("setting client rect: %u, %u x %ux%u\n", x, y, cx, cy); - ret = data->client_window = XCreateWindow( gdi_display, - data->whole_window ? data->whole_window : dummy_parent, - x, y, cx, cy, 0, default_visual.depth, InputOutput, -@@ -1721,6 +1785,8 @@ Window create_client_window( HWND hwnd, const XVisualInfo *visual ) - if (data->client_window) - { - XSaveContext( data->display, data->client_window, winContext, (char *)data->hwnd ); -+ /* Save to gdi_display as well for fullscreen hack, needed in X11DRV_query_fs_hack() */ -+ XSaveContext( gdi_display, data->client_window, winContext, (char *)data->hwnd ); - XMapWindow( gdi_display, data->client_window ); - XSync( gdi_display, False ); - if (data->whole_window) XSelectInput( data->display, data->client_window, ExposureMask ); -@@ -1765,11 +1831,25 @@ static void create_whole_window( struct x11drv_win_data *data ) - - mask = get_window_attributes( data, &attr ); - -+ attr.background_pixel = XBlackPixel(data->display, data->vis.screen); -+ mask |= CWBackPixel; -+ - if (!(cx = data->whole_rect.right - data->whole_rect.left)) cx = 1; - else if (cx > 65535) cx = 65535; - if (!(cy = data->whole_rect.bottom - data->whole_rect.top)) cy = 1; - else if (cy > 65535) cy = 65535; - -+ if(data->fs_hack){ -+ RECT rect = {0, 0, 0, 0}; -+ HMONITOR monitor; -+ -+ monitor = fs_hack_monitor_from_hwnd(data->hwnd); -+ rect = fs_hack_real_mode(monitor); -+ cx = rect.right - rect.left; -+ cy = rect.bottom - rect.top; -+ TRACE("width:%d height:%d\n", cx, cy); -+ } -+ - pos = virtual_screen_to_root( data->whole_rect.left, data->whole_rect.top ); - data->whole_window = XCreateWindow( data->display, root_window, pos.x, pos.y, - cx, cy, 0, data->vis.depth, InputOutput, -@@ -2540,9 +2620,45 @@ BOOL CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag - DWORD flags; - COLORREF key; - BOOL layered = GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED; -+ HMONITOR monitor; - - if (!data && !(data = X11DRV_create_win_data( hwnd, window_rect, client_rect ))) return TRUE; - -+ monitor = fs_hack_monitor_from_rect(window_rect); -+ if(!wm_is_steamcompmgr(data->display) && !data->fs_hack && fs_hack_enabled(monitor) && -+ fs_hack_matches_current_mode(monitor, -+ window_rect->right - window_rect->left, -+ window_rect->bottom - window_rect->top)){ -+ RECT real_rect = fs_hack_real_mode(monitor); -+ RECT user_rect = fs_hack_current_mode(monitor); -+ POINT tl = virtual_screen_to_root(user_rect.left, user_rect.top); -+ -+ TRACE("Enabling fs hack for %p, resizing the window to (%u,%u)-(%u,%u)\n", hwnd, tl.x, tl.y, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top); -+ data->fs_hack = TRUE; -+ if(data->whole_window) -+ XMoveResizeWindow(data->display, data->whole_window, tl.x, tl.y, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top); -+ if(data->client_window) -+ XMoveResizeWindow(data->display, data->client_window, 0, 0, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top); -+ }else if(data->fs_hack && (!fs_hack_enabled(monitor) || -+ !fs_hack_matches_current_mode(monitor, -+ window_rect->right - window_rect->left, -+ window_rect->bottom - window_rect->top))){ -+ TRACE("Disabling fs hack for %p\n", hwnd); -+ data->fs_hack = FALSE; -+ if(data->whole_window) -+ XMoveResizeWindow(data->display, data->whole_window, -+ window_rect->left, window_rect->top, -+ window_rect->right - window_rect->left, -+ window_rect->bottom - window_rect->top); -+ if(data->client_window){ -+ XMoveResizeWindow(data->display, data->client_window, -+ data->client_rect.left - data->whole_rect.left, -+ data->client_rect.top - data->whole_rect.top, -+ data->client_rect.right - data->client_rect.left, -+ data->client_rect.bottom - data->client_rect.top); -+ } -+ } -+ - /* check if we need to switch the window to managed */ - if (!data->managed && data->whole_window && is_window_managed( hwnd, swp_flags, window_rect )) - { -@@ -2678,6 +2794,9 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags - return; - } - -+ if (data->fs_hack) -+ sync_gl_drawable( hwnd, FALSE ); -+ - /* check if we are currently processing an event relevant to this window */ - event_type = 0; - if (thread_data && -@@ -2772,6 +2891,7 @@ UINT CDECL X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) - DWORD style = GetWindowLongW( hwnd, GWL_STYLE ); - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - struct x11drv_win_data *data = get_win_data( hwnd ); -+ HMONITOR monitor; - - if (!data || !data->whole_window) goto done; - if (style & WS_MINIMIZE) -@@ -2801,7 +2921,25 @@ UINT CDECL X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) - &root, &x, &y, &width, &height, &border, &depth ); - XTranslateCoordinates( thread_data->display, data->whole_window, root, 0, 0, &x, &y, &top ); - pos = root_to_virtual_screen( x, y ); -- X11DRV_X_to_window_rect( data, rect, pos.x, pos.y, width, height ); -+ monitor = fs_hack_monitor_from_hwnd(hwnd); -+ if (data->fs_hack || -+ (fs_hack_enabled(monitor) && -+ fs_hack_matches_current_mode(monitor, -+ rect->right - rect->left, -+ rect->bottom - rect->top))) -+ { -+ MONITORINFO monitor_info; -+ -+ monitor_info.cbSize = sizeof(monitor_info); -+ GetMonitorInfoW( monitor, &monitor_info ); -+ X11DRV_X_to_window_rect( data, rect, monitor_info.rcMonitor.left, monitor_info.rcMonitor.top, -+ monitor_info.rcMonitor.right - monitor_info.rcMonitor.left, -+ monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top ); -+ } -+ else -+ { -+ X11DRV_X_to_window_rect( data, rect, pos.x, pos.y, width, height ); -+ } - swp &= ~(SWP_NOMOVE | SWP_NOCLIENTMOVE | SWP_NOSIZE | SWP_NOCLIENTSIZE); - - done: -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 213143014a7..26843c830eb 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -443,6 +443,7 @@ extern BOOL private_color_map DECLSPEC_HIDDEN; - extern int primary_monitor DECLSPEC_HIDDEN; - extern int copy_default_colors DECLSPEC_HIDDEN; - extern int alloc_system_colors DECLSPEC_HIDDEN; -+extern int limit_number_of_resolutions DECLSPEC_HIDDEN; - extern int xrender_error_base DECLSPEC_HIDDEN; - extern int xfixes_event_base DECLSPEC_HIDDEN; - extern HMODULE x11drv_module DECLSPEC_HIDDEN; -@@ -626,6 +627,7 @@ struct x11drv_win_data - BOOL skip_taskbar : 1; /* does window should be deleted from taskbar */ - BOOL add_taskbar : 1; /* does window should be added to taskbar regardless of style */ - BOOL pending_fullscreen : 1; -+ BOOL fs_hack : 1; - ULONGLONG take_focus_back; - int wm_state; /* current value of the WM_STATE property */ - DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ -@@ -670,6 +672,23 @@ extern BOOL wm_is_mutter(Display *) DECLSPEC_HIDDEN; - extern BOOL wm_is_steamcompmgr(Display *) DECLSPEC_HIDDEN; - - extern void set_wm_hints( struct x11drv_win_data *data ) DECLSPEC_HIDDEN; -+extern BOOL fs_hack_enabled(HMONITOR monitor) DECLSPEC_HIDDEN; -+extern BOOL fs_hack_mapping_required(HMONITOR monitor) DECLSPEC_HIDDEN; -+extern BOOL fs_hack_is_integer(void) DECLSPEC_HIDDEN; -+extern HMONITOR fs_hack_monitor_from_hwnd(HWND hwnd) DECLSPEC_HIDDEN; -+extern HMONITOR fs_hack_monitor_from_rect(const RECT *rect) DECLSPEC_HIDDEN; -+extern BOOL fs_hack_matches_current_mode(HMONITOR monitor, INT width, INT height) DECLSPEC_HIDDEN; -+extern RECT fs_hack_current_mode(HMONITOR monitor) DECLSPEC_HIDDEN; -+extern RECT fs_hack_real_mode(HMONITOR monitor) DECLSPEC_HIDDEN; -+extern void fs_hack_point_user_to_real(POINT *pos) DECLSPEC_HIDDEN; -+extern void fs_hack_point_real_to_user(POINT *pos) DECLSPEC_HIDDEN; -+extern void fs_hack_rect_user_to_real(RECT *rect) DECLSPEC_HIDDEN; -+extern void fs_hack_rgndata_user_to_real(RGNDATA *data) DECLSPEC_HIDDEN; -+extern double fs_hack_get_user_to_real_scale(HMONITOR) DECLSPEC_HIDDEN; -+extern SIZE fs_hack_get_scaled_screen_size(HMONITOR monitor) DECLSPEC_HIDDEN; -+extern RECT fs_hack_get_real_virtual_screen(void) DECLSPEC_HIDDEN; -+extern void fs_hack_init(void) DECLSPEC_HIDDEN; -+extern int mode_compare(const void *p1, const void *p2) DECLSPEC_HIDDEN; - - static inline void mirror_rect( const RECT *window_rect, RECT *rect ) - { -@@ -718,6 +737,16 @@ extern void xinerama_init( unsigned int width, unsigned int height ) DECLSPEC_HI - #define DEPTH_COUNT 3 - extern const unsigned int *depths DECLSPEC_HIDDEN; - -+struct x11drv_display_setting -+{ -+ ULONG_PTR id; -+ BOOL placed; -+ RECT new_rect; -+ RECT old_rect; -+ RECT desired_rect; -+ DEVMODEW desired_mode; -+}; -+ - /* Required functions for changing and enumerating display settings */ - struct x11drv_settings_handler - { -@@ -761,9 +790,14 @@ struct x11drv_settings_handler - * - * Return DISP_CHANGE_*, same as ChangeDisplaySettingsExW() return values */ - LONG (*set_current_mode)(ULONG_PTR id, DEVMODEW *mode); -+ -+ /* convert_coordinates() will be called to convert virtual screen coordinates to driver specific coordinates. -+ * This function is optional and can be NULL if driver don't need to convert coordinates */ -+ void (*convert_coordinates)(struct x11drv_display_setting *displays, UINT display_count); - }; - - extern void X11DRV_Settings_SetHandler(const struct x11drv_settings_handler *handler) DECLSPEC_HIDDEN; -+extern struct x11drv_settings_handler X11DRV_Settings_GetHandler(void) DECLSPEC_HIDDEN; - - extern void X11DRV_init_desktop( Window win, unsigned int width, unsigned int height ) DECLSPEC_HIDDEN; - extern void X11DRV_resize_desktop(BOOL) DECLSPEC_HIDDEN; -@@ -825,6 +859,7 @@ extern HANDLE get_display_device_init_mutex(void) DECLSPEC_HIDDEN; - extern BOOL get_host_primary_gpu(struct gdi_gpu *gpu) DECLSPEC_HIDDEN; - extern void release_display_device_init_mutex(HANDLE) DECLSPEC_HIDDEN; - extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN; -+extern struct x11drv_display_device_handler X11DRV_DisplayDevices_GetHandler(void) DECLSPEC_HIDDEN; - extern void X11DRV_DisplayDevices_Init(BOOL force) DECLSPEC_HIDDEN; - extern void X11DRV_DisplayDevices_RegisterEventHandlers(void) DECLSPEC_HIDDEN; - extern void X11DRV_DisplayDevices_Update(BOOL) DECLSPEC_HIDDEN; -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 1e7c140641f..c9ca46364cd 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -63,7 +63,7 @@ Colormap default_colormap = None; - XPixmapFormatValues **pixmap_formats; - unsigned int screen_bpp; - Window root_window; --BOOL usexvidmode = TRUE; -+BOOL usexvidmode = FALSE; - BOOL usexrandr = TRUE; - BOOL usexcomposite = TRUE; - BOOL use_xfixes = FALSE; -@@ -83,6 +83,7 @@ BOOL client_side_with_render = TRUE; - BOOL shape_layered_windows = TRUE; - int copy_default_colors = 128; - int alloc_system_colors = 256; -+int limit_number_of_resolutions = 0; - DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES; - int xrender_error_base = 0; - int xfixes_event_base = 0; -@@ -456,6 +457,9 @@ static void setup_options(void) - if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) )) - alloc_system_colors = atoi(buffer); - -+ if (!get_config_key( hkey, appkey, "LimitNumberOfResolutions", buffer, sizeof(buffer) )) -+ limit_number_of_resolutions = atoi(buffer); -+ - get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) ); - - if (appkey) RegCloseKey( appkey ); -@@ -706,6 +710,8 @@ static BOOL process_attach(void) - X11DRV_InitMouse( gdi_display ); - if (use_xim) use_xim = X11DRV_InitXIM( input_style ); - -+ fs_hack_init(); -+ - init_user_driver(); - X11DRV_DisplayDevices_Init(FALSE); - return TRUE; -diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c -index fb7a4405a1e..0a080ea6be8 100644 ---- a/dlls/winex11.drv/xrandr.c -+++ b/dlls/winex11.drv/xrandr.c -@@ -1647,6 +1647,24 @@ static LONG xrandr14_set_current_mode( ULONG_PTR id, DEVMODEW *mode ) - - #endif - -+static void xrandr14_convert_coordinates( struct x11drv_display_setting *displays, UINT display_count ) -+{ -+ INT left_most = INT_MAX, top_most = INT_MAX; -+ UINT display_idx; -+ -+ for (display_idx = 0; display_idx < display_count; ++display_idx) -+ { -+ left_most = min( left_most, displays[display_idx].desired_mode.u1.s2.dmPosition.x ); -+ top_most = min( top_most, displays[display_idx].desired_mode.u1.s2.dmPosition.y ); -+ } -+ -+ for (display_idx = 0; display_idx < display_count; ++display_idx) -+ { -+ displays[display_idx].desired_mode.u1.s2.dmPosition.x -= left_most; -+ displays[display_idx].desired_mode.u1.s2.dmPosition.y -= top_most; -+ } -+} -+ - void X11DRV_XRandR_Init(void) - { - struct x11drv_display_device_handler display_handler; -@@ -1675,6 +1693,7 @@ void X11DRV_XRandR_Init(void) - settings_handler.free_modes = xrandr10_free_modes; - settings_handler.get_current_mode = xrandr10_get_current_mode; - settings_handler.set_current_mode = xrandr10_set_current_mode; -+ settings_handler.convert_coordinates = NULL; - X11DRV_Settings_SetHandler( &settings_handler ); - - #ifdef HAVE_XRRGETPROVIDERRESOURCES -@@ -1733,6 +1752,7 @@ void X11DRV_XRandR_Init(void) - settings_handler.free_modes = xrandr14_free_modes; - settings_handler.get_current_mode = xrandr14_get_current_mode; - settings_handler.set_current_mode = xrandr14_set_current_mode; -+ settings_handler.convert_coordinates = xrandr14_convert_coordinates; - X11DRV_Settings_SetHandler( &settings_handler ); - } - #endif -diff --git a/dlls/winex11.drv/xrender.c b/dlls/winex11.drv/xrender.c -index 92dc35fa9e1..d43d67c02cf 100644 ---- a/dlls/winex11.drv/xrender.c -+++ b/dlls/winex11.drv/xrender.c -@@ -475,6 +475,7 @@ static void update_xrender_clipping( struct xrender_physdev *dev, HRGN rgn ) - } - else if ((data = X11DRV_GetRegionData( rgn, 0 ))) - { -+ fs_hack_rgndata_user_to_real(data); - pXRenderSetPictureClipRectangles( gdi_display, dev->pict, - dev->x11dev->dc_rect.left, dev->x11dev->dc_rect.top, - (XRectangle *)data->Buffer, data->rdh.nCount ); -@@ -1461,13 +1462,77 @@ static void multiply_alpha( Picture pict, XRenderPictFormat *format, int alpha, - XFreePixmap( gdi_display, mask_pixmap ); - } - -+/* if we are letterboxing, draw black bars */ -+static void fs_hack_draw_black_bars( HMONITOR monitor, Picture dst_pict ) -+{ -+ static const XRenderColor black = { 0, 0, 0, 0xffff }; -+ POINT tl, br; /* top-left / bottom-right */ -+ RECT user_rect = fs_hack_current_mode(monitor); -+ RECT real_rect = fs_hack_real_mode(monitor); -+ SIZE scaled_screen = fs_hack_get_scaled_screen_size(monitor); -+ XRenderPictureAttributes pa; -+ -+ /* first unclip the picture, so that we can actually draw them */ -+ pa.clip_mask = None; -+ pXRenderChangePicture( gdi_display, dst_pict, CPClipMask, &pa ); -+ -+ tl.x = user_rect.left; -+ tl.y = user_rect.top; -+ fs_hack_point_user_to_real(&tl); -+ tl.x = tl.x - real_rect.left; -+ tl.y = tl.y - real_rect.top; -+ br.x = tl.x + scaled_screen.cx; -+ br.y = tl.y + scaled_screen.cy; -+ -+ if (tl.x > 0) -+ { -+ /* black bars left & right */ -+ pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &black, -+ 0, 0, /* x, y */ -+ tl.x, real_rect.bottom - real_rect.top); /* w, h */ -+ pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &black, -+ br.x, 0, -+ real_rect.right - real_rect.left - br.x, real_rect.bottom - real_rect.top); -+ } -+ else if (tl.y > 0) -+ { -+ /* black bars top & bottom */ -+ pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &black, -+ 0, 0, -+ real_rect.right - real_rect.left, tl.y); -+ pXRenderFillRectangle(gdi_display, PictOpSrc, dst_pict, &black, -+ 0, br.y, -+ real_rect.right - real_rect.left, real_rect.bottom - real_rect.top - br.y); -+ } -+} -+ - /* Helper function for (stretched) blitting using xrender */ --static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture dst_pict, -+static void xrender_blit( struct xrender_physdev *physdev, -+ int op, Picture src_pict, Picture mask_pict, Picture dst_pict, - int x_src, int y_src, int width_src, int height_src, - int x_dst, int y_dst, int width_dst, int height_dst, - double xscale, double yscale ) - { - int x_offset, y_offset; -+ HMONITOR monitor; -+ -+ monitor = fs_hack_monitor_from_hwnd(WindowFromDC(physdev->dev.hdc)); -+ if (fs_hack_mapping_required(monitor)) -+ { -+ double user_to_real_scale; -+ POINT p; -+ p.x = x_dst; -+ p.y = y_dst; -+ fs_hack_point_user_to_real(&p); -+ x_dst = p.x; -+ y_dst = p.y; -+ -+ user_to_real_scale = fs_hack_get_user_to_real_scale(monitor); -+ width_dst *= user_to_real_scale; -+ height_dst *= user_to_real_scale; -+ xscale /= user_to_real_scale; -+ yscale /= user_to_real_scale; -+ } - - if (width_src < 0) - { -@@ -1508,6 +1573,9 @@ static void xrender_blit( int op, Picture src_pict, Picture mask_pict, Picture d - } - pXRenderComposite( gdi_display, op, src_pict, mask_pict, dst_pict, - x_offset, y_offset, 0, 0, x_dst, y_dst, width_dst, height_dst ); -+ -+ if (fs_hack_mapping_required( monitor )) -+ fs_hack_draw_black_bars( monitor, dst_pict ); - } - - /* Helper function for (stretched) mono->color blitting using xrender */ -@@ -1664,7 +1732,7 @@ static void xrender_stretch_blit( struct xrender_physdev *physdev_src, struct xr - if (physdev_dst->pict_format->depth == 32 && physdev_src->pict_format->depth < 32) - mask_pict = get_no_alpha_mask(); - -- xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, -+ xrender_blit( physdev_dst, PictOpSrc, src_pict, mask_pict, dst_pict, - physdev_src->x11dev->dc_rect.left + src->x, - physdev_src->x11dev->dc_rect.top + src->y, - src->width, src->height, x_dst, y_dst, dst->width, dst->height, xscale, yscale ); -@@ -1688,6 +1756,7 @@ static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask - RGNDATA *clip_data = NULL; - - if (clip) clip_data = X11DRV_GetRegionData( clip, 0 ); -+ fs_hack_rgndata_user_to_real(clip_data); - x_dst = dst->x; - y_dst = dst->y; - dst_pict = pXRenderCreatePicture( gdi_display, drawable, dst_format, 0, NULL ); -@@ -1710,7 +1779,7 @@ static void xrender_put_image( Pixmap src_pixmap, Picture src_pict, Picture mask - } - else xscale = yscale = 1; /* no scaling needed with a repeating source */ - -- xrender_blit( PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height, -+ xrender_blit( physdev, PictOpSrc, src_pict, mask_pict, dst_pict, src->x, src->y, src->width, src->height, - x_dst, y_dst, dst->width, dst->height, xscale, yscale ); - - if (drawable) pXRenderFreePicture( gdi_display, dst_pict ); -@@ -1726,6 +1795,11 @@ static BOOL CDECL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords * - struct xrender_physdev *physdev_dst = get_xrender_dev( dst_dev ); - struct xrender_physdev *physdev_src = get_xrender_dev( src_dev ); - BOOL stretch = (src->width != dst->width) || (src->height != dst->height); -+ HMONITOR monitor; -+ -+ TRACE("src %d,%d %dx%d vis=%s dst %d,%d %dx%d vis=%s rop=%06x\n", -+ src->x, src->y, src->width, src->height, wine_dbgstr_rect(&src->visrect), -+ dst->x, dst->y, dst->width, dst->height, wine_dbgstr_rect(&dst->visrect), rop ); - - if (src_dev->funcs != dst_dev->funcs) - { -@@ -1737,6 +1811,10 @@ static BOOL CDECL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords * - if (physdev_dst->format == WXR_FORMAT_MONO && physdev_src->format != WXR_FORMAT_MONO) - goto x11drv_fallback; - -+ monitor = fs_hack_monitor_from_hwnd(WindowFromDC(dst_dev->hdc)); -+ if (fs_hack_mapping_required(monitor)) -+ stretch = TRUE; -+ - /* if not stretching, we only need to handle format conversion */ - if (!stretch && physdev_dst->format == physdev_src->format) goto x11drv_fallback; - -@@ -1755,8 +1833,20 @@ static BOOL CDECL xrenderdrv_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords * - tmpGC = XCreateGC( gdi_display, physdev_dst->x11dev->drawable, 0, NULL ); - XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors ); - XSetGraphicsExposures( gdi_display, tmpGC, False ); -- tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left, -- tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth ); -+ -+ if (fs_hack_mapping_required( monitor )) -+ { -+ double user_to_real_scale; -+ SIZE size; -+ -+ user_to_real_scale = fs_hack_get_user_to_real_scale( monitor ); -+ size.cx = (tmp.visrect.right - tmp.visrect.left) * user_to_real_scale; -+ size.cy = (tmp.visrect.bottom - tmp.visrect.top) * user_to_real_scale; -+ tmp_pixmap = XCreatePixmap( gdi_display, root_window, size.cx, size.cy, physdev_dst->pict_format->depth ); -+ } -+ else -+ tmp_pixmap = XCreatePixmap( gdi_display, root_window, tmp.visrect.right - tmp.visrect.left, -+ tmp.visrect.bottom - tmp.visrect.top, physdev_dst->pict_format->depth ); - - xrender_stretch_blit( physdev_src, physdev_dst, tmp_pixmap, src, &tmp ); - execute_rop( physdev_dst->x11dev, tmp_pixmap, tmpGC, &dst->visrect, rop ); -@@ -1791,6 +1881,10 @@ static DWORD CDECL xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info - Picture src_pict, mask_pict = 0; - BOOL use_repeat; - -+ TRACE("src %d,%d %dx%d vis=%s dst %d,%d %dx%d vis=%s rop=%06x\n", -+ src->x, src->y, src->width, src->height, wine_dbgstr_rect(&src->visrect), -+ dst->x, dst->y, dst->width, dst->height, wine_dbgstr_rect(&dst->visrect), rop ); -+ - dst_format = physdev->format; - src_format = get_xrender_format_from_bitmapinfo( info ); - if (!(pict_format = pict_formats[src_format])) goto update_format; -@@ -1815,6 +1909,7 @@ static DWORD CDECL xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info - if (rop != SRCCOPY) - { - BOOL restore_region = add_extra_clipping_region( physdev->x11dev, clip ); -+ HMONITOR monitor; - - /* make coordinates relative to tmp pixmap */ - tmp = *dst; -@@ -1825,13 +1920,29 @@ static DWORD CDECL xrenderdrv_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info - gc = XCreateGC( gdi_display, physdev->x11dev->drawable, 0, NULL ); - XSetSubwindowMode( gdi_display, gc, IncludeInferiors ); - XSetGraphicsExposures( gdi_display, gc, False ); -- tmp_pixmap = XCreatePixmap( gdi_display, root_window, -- tmp.visrect.right - tmp.visrect.left, -- tmp.visrect.bottom - tmp.visrect.top, -- physdev->pict_format->depth ); -+ -+ monitor = fs_hack_monitor_from_hwnd( WindowFromDC( dev->hdc ) ); -+ if (fs_hack_mapping_required( monitor )) -+ { -+ double user_to_real_scale; -+ SIZE size; -+ -+ user_to_real_scale = fs_hack_get_user_to_real_scale( monitor ); -+ size.cx = (tmp.visrect.right - tmp.visrect.left) * user_to_real_scale; -+ size.cy = (tmp.visrect.bottom - tmp.visrect.top) * user_to_real_scale; -+ tmp_pixmap = XCreatePixmap( gdi_display, root_window, size.cx, size.cy, -+ physdev->pict_format->depth ); -+ } -+ else -+ { -+ tmp_pixmap = XCreatePixmap( gdi_display, root_window, -+ tmp.visrect.right - tmp.visrect.left, -+ tmp.visrect.bottom - tmp.visrect.top, -+ physdev->pict_format->depth ); -+ } - - xrender_put_image( src_pixmap, src_pict, mask_pict, NULL, physdev->pict_format, -- NULL, tmp_pixmap, src, &tmp, use_repeat ); -+ physdev, tmp_pixmap, src, &tmp, use_repeat ); - execute_rop( physdev->x11dev, tmp_pixmap, gc, &dst->visrect, rop ); - - XFreePixmap( gdi_display, tmp_pixmap ); -@@ -1908,7 +2019,7 @@ static DWORD CDECL xrenderdrv_BlendImage( PHYSDEV dev, BITMAPINFO *info, const s - EnterCriticalSection( &xrender_cs ); - mask_pict = get_mask_pict( func.SourceConstantAlpha * 257 ); - -- xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, -+ xrender_blit( physdev, PictOpOver, src_pict, mask_pict, dst_pict, - src->x, src->y, src->width, src->height, - physdev->x11dev->dc_rect.left + dst->x, - physdev->x11dev->dc_rect.top + dst->y, -@@ -1997,7 +2108,7 @@ static BOOL CDECL xrenderdrv_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords * - EnterCriticalSection( &xrender_cs ); - mask_pict = get_mask_pict( blendfn.SourceConstantAlpha * 257 ); - -- xrender_blit( PictOpOver, src_pict, mask_pict, dst_pict, -+ xrender_blit( physdev_dst, PictOpOver, src_pict, mask_pict, dst_pict, - physdev_src->x11dev->dc_rect.left + src->x, - physdev_src->x11dev->dc_rect.top + src->y, - src->width, src->height, -@@ -2100,7 +2211,7 @@ static BOOL CDECL xrenderdrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, U - dst_pict = get_xrender_picture( physdev, 0, NULL ); - - src_pict = pXRenderCreateLinearGradient( gdi_display, &gradient, stops, colors, 2 ); -- xrender_blit( PictOpSrc, src_pict, 0, dst_pict, -+ xrender_blit( physdev, PictOpSrc, src_pict, 0, dst_pict, - 0, 0, rc.right - rc.left, rc.bottom - rc.top, - physdev->x11dev->dc_rect.left + rc.left, - physdev->x11dev->dc_rect.top + rc.top, -diff --git a/dlls/winex11.drv/xvidmode.c b/dlls/winex11.drv/xvidmode.c -index d0be58342a5..123e5d036a9 100644 ---- a/dlls/winex11.drv/xvidmode.c -+++ b/dlls/winex11.drv/xvidmode.c -@@ -313,6 +313,7 @@ void X11DRV_XF86VM_Init(void) - xf86vm_handler.free_modes = xf86vm_free_modes; - xf86vm_handler.get_current_mode = xf86vm_get_current_mode; - xf86vm_handler.set_current_mode = xf86vm_set_current_mode; -+ xf86vm_handler.convert_coordinates = NULL; - X11DRV_Settings_SetHandler(&xf86vm_handler); - return; - -From b2f26fe9bab670740b6298e99a99f34509dcd6b4 Mon Sep 17 00:00:00 2001 -From: Matteo Bruni -Date: Tue, 16 Feb 2021 13:30:51 -0600 -Subject: [PATCH] winex11: Clear fs hack depth / stencil attachment. - ---- - dlls/winex11.drv/opengl.c | 19 +++++++++++++++---- - 1 file changed, 15 insertions(+), 4 deletions(-) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index bf5f9637227..53ac19dfe50 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -1950,7 +1950,8 @@ static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_ha - static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable *gl ) - { - GLuint prev_draw_fbo, prev_read_fbo, prev_texture, prev_renderbuffer; -- float prev_clear_color[4]; -+ float prev_clear_color[4], prev_clear_depth; -+ int prev_clear_stencil; - unsigned int i; - struct fs_hack_fbo_attachments_config config; - struct fs_hack_fbconfig_attribs attribs; -@@ -1995,6 +1996,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - opengl_funcs.gl.p_glGetIntegerv( GL_TEXTURE_BINDING_2D, (GLint *)&prev_texture ); - opengl_funcs.gl.p_glGetIntegerv( GL_RENDERBUFFER_BINDING, (GLint *)&prev_renderbuffer ); - opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, prev_clear_color ); -+ opengl_funcs.gl.p_glGetFloatv( GL_DEPTH_CLEAR_VALUE, &prev_clear_depth ); -+ opengl_funcs.gl.p_glGetIntegerv( GL_STENCIL_CLEAR_VALUE, &prev_clear_stencil ); - TRACE( "Previous draw FBO %u, read FBO %u for ctx %p\n", prev_draw_fbo, prev_read_fbo, ctx); - - if (!ctx->fs_hack_fbo) -@@ -2080,14 +2083,22 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - } - } - -- opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - if(!gl->fs_hack_context_set_up) -- opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); -+ { -+ opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); -+ opengl_funcs.gl.p_glClearDepth( 1.0 ); -+ opengl_funcs.gl.p_glClearStencil( 0 ); -+ opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); -+ } - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); - pglDrawBuffer( GL_BACK ); - if(!gl->fs_hack_context_set_up) -+ { - opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); -- opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], prev_clear_color[2], prev_clear_color[3] ); -+ opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], prev_clear_color[2], prev_clear_color[3] ); -+ opengl_funcs.gl.p_glClearDepth( prev_clear_depth ); -+ opengl_funcs.gl.p_glClearStencil( prev_clear_stencil ); -+ } - wglBindFramebuffer( GL_DRAW_FRAMEBUFFER, prev_draw_fbo ); - wglBindFramebuffer( GL_READ_FRAMEBUFFER, prev_read_fbo ); - -From ba4e9dc41c7fb272c4354669b032b781d96e2e59 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 19 Dec 2019 09:12:17 -0600 -Subject: [PATCH] winex11.drv: Remove nvidia hack workaround - -This breaks things for users who legitimately have only one resolution. ---- - dlls/winex11.drv/xrandr.c | 13 ------------- - 1 file changed, 13 deletions(-) - -diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c -index 0a080ea6be8..667013df5ac 100644 ---- a/dlls/winex11.drv/xrandr.c -+++ b/dlls/winex11.drv/xrandr.c -@@ -28,9 +28,6 @@ - #include "wine/debug.h" - - WINE_DEFAULT_DEBUG_CHANNEL(xrandr); --#ifdef HAVE_XRRGETPROVIDERRESOURCES --WINE_DECLARE_DEBUG_CHANNEL(winediag); --#endif - - #ifdef SONAME_LIBXRANDR - -@@ -378,7 +375,6 @@ static BOOL is_broken_driver(void) - XRRScreenResources *screen_resources; - XRROutputInfo *output_info; - XRRModeInfo *first_mode; -- INT major, event, error; - INT output_idx, i, j; - BOOL only_one_mode; - -@@ -429,15 +425,6 @@ static BOOL is_broken_driver(void) - - if (!only_one_mode) - continue; -- -- /* Check if it is NVIDIA proprietary driver */ -- if (XQueryExtension( gdi_display, "NV-CONTROL", &major, &event, &error )) -- { -- ERR_(winediag)("Broken NVIDIA RandR detected, falling back to RandR 1.0. " -- "Please consider using the Nouveau driver instead.\n"); -- pXRRFreeScreenResources( screen_resources ); -- return TRUE; -- } - } - pXRRFreeScreenResources( screen_resources ); - return FALSE; -From efc3bf9dd9f195641604d0fe392f542bdde2c5f8 Mon Sep 17 00:00:00 2001 -From: Zhiyi Zhang -Date: Mon, 6 Apr 2020 15:30:40 +0800 -Subject: [PATCH] winex11.drv: Bypass compositor only when a window is full - virtual screen. - -Bypass compositor only when a window is full virtual screen. Otherwise, it might cause flicking on -other monitors. - -Signed-off-by: Zhiyi Zhang ---- - dlls/winex11.drv/window.c | 10 +++++++++- - dlls/winex11.drv/x11drv.h | 1 + - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index a60001aec6d..ac7c0005a14 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -386,6 +386,13 @@ BOOL is_window_rect_full_screen( const RECT *rect ) - return info.full_screen; - } - -+BOOL is_window_rect_full_virtual_screen( const RECT *rect ) -+{ -+ RECT virtual_rect = get_virtual_screen_rect(); -+ return (rect->left <= virtual_rect.left && rect->right >= virtual_rect.right && -+ rect->top <= virtual_rect.top && rect->bottom >= virtual_rect.bottom); -+} -+ - /*********************************************************************** - * get_mwm_decorations - */ -@@ -1168,7 +1175,8 @@ void update_net_wm_states( struct x11drv_win_data *data ) - if (!wm_is_steamcompmgr(data->display) || !fs_hack_enabled(monitor)) - { - /* when fs hack is enabled, we don't want steamcompmgr to resize the window to be fullscreened */ -- net_wm_bypass_compositor = 1; -+ if (is_window_rect_full_virtual_screen( &data->whole_rect )) -+ net_wm_bypass_compositor = 1; - new_state |= (1 << NET_WM_STATE_FULLSCREEN); - } - } -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 26843c830eb..55875edc788 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -726,6 +726,7 @@ extern void X11DRV_expect_error( Display *display, x11drv_error_callback callbac - extern int X11DRV_check_error(void) DECLSPEC_HIDDEN; - extern void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect, int x, int y, int cx, int cy ) DECLSPEC_HIDDEN; - extern BOOL is_window_rect_full_screen( const RECT *rect ) DECLSPEC_HIDDEN; -+extern BOOL is_window_rect_full_virtual_screen( const RECT *rect ) DECLSPEC_HIDDEN; - extern POINT virtual_screen_to_root( INT x, INT y ) DECLSPEC_HIDDEN; - extern POINT root_to_virtual_screen( INT x, INT y ) DECLSPEC_HIDDEN; - extern RECT get_virtual_screen_rect(void) DECLSPEC_HIDDEN; -From 37b625a90d44c24f3bdc8c5a61f0dd5b0d37a924 Mon Sep 17 00:00:00 2001 -From: Zhiyi Zhang -Date: Sun, 17 May 2020 23:27:59 +0800 -Subject: [PATCH] user32/tests: Test moving full screen windows. - -Signed-off-by: Zhiyi Zhang ---- - dlls/user32/tests/win.c | 79 +++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 76 insertions(+), 3 deletions(-) - -diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c -index 0156987f529..83969bf89f6 100644 ---- a/dlls/user32/tests/win.c -+++ b/dlls/user32/tests/win.c -@@ -92,8 +92,8 @@ static void dump_minmax_info( const MINMAXINFO *minmax ) - static void flush_events( BOOL remove_messages ) - { - MSG msg; -- int diff = 200; -- int min_timeout = 100; -+ int diff = 500; -+ int min_timeout = 200; - DWORD time = GetTickCount() + diff; - - while (diff > 0) -@@ -102,7 +102,6 @@ static void flush_events( BOOL remove_messages ) - if (remove_messages) - while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); - diff = time - GetTickCount(); -- min_timeout = 50; - } - } - -@@ -8587,6 +8586,29 @@ static LRESULT CALLBACK fullscreen_wnd_proc(HWND hwnd, UINT msg, WPARAM wp, LPAR - return DefWindowProcA(hwnd, msg, wp, lp); - } - -+struct monitor_info -+{ -+ RECT first_monitor; -+ RECT second_monitor; -+}; -+ -+static BOOL CALLBACK enum_monitor_cb(HMONITOR monitor, HDC hdc, RECT *monitor_rect, LPARAM lparam) -+{ -+ struct monitor_info *info = (struct monitor_info *)lparam; -+ -+ if (IsRectEmpty(&info->first_monitor)) -+ { -+ info->first_monitor = *monitor_rect; -+ } -+ else -+ { -+ info->second_monitor = *monitor_rect; -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ - static void test_fullscreen(void) - { - static const DWORD t_style[] = { -@@ -8595,6 +8617,7 @@ static void test_fullscreen(void) - static const DWORD t_ex_style[] = { - 0, WS_EX_APPWINDOW, WS_EX_TOOLWINDOW - }; -+ struct monitor_info monitor_info; - WNDCLASSA cls; - int timeout; - HWND hwnd; -@@ -8747,6 +8770,56 @@ static void test_fullscreen(void) - DestroyWindow(hwnd); - - UnregisterClassA("fullscreen_class", GetModuleHandleA(NULL)); -+ -+ /* Test moving a full screen window to another monitor */ -+ memset(&monitor_info, 0, sizeof(monitor_info)); -+ EnumDisplayMonitors(NULL, NULL, enum_monitor_cb, (LPARAM)&monitor_info); -+ if (!IsRectEmpty(&monitor_info.first_monitor) && !IsRectEmpty(&monitor_info.second_monitor)) -+ { -+ hwnd = CreateWindowA("static", "static1", WS_POPUP | WS_VISIBLE, -+ monitor_info.first_monitor.left, monitor_info.first_monitor.top, -+ monitor_info.first_monitor.right - monitor_info.first_monitor.left, -+ monitor_info.first_monitor.bottom - monitor_info.first_monitor.top, NULL, NULL, -+ GetModuleHandleA(NULL), NULL); -+ ok(!!hwnd, "CreateWindow failed, error %#x.\n", GetLastError()); -+ flush_events(TRUE); -+ -+ GetWindowRect(hwnd, &rc); -+ ok(EqualRect(&rc, &monitor_info.first_monitor), "Expected window rect %s, got %s.\n", -+ wine_dbgstr_rect(&monitor_info.first_monitor), wine_dbgstr_rect(&rc)); -+ -+ SetWindowPos(hwnd, 0, monitor_info.second_monitor.left, monitor_info.second_monitor.top, -+ monitor_info.second_monitor.right - monitor_info.second_monitor.left, -+ monitor_info.second_monitor.bottom - monitor_info.second_monitor.top, SWP_NOZORDER); -+ flush_events(TRUE); -+ GetWindowRect(hwnd, &rc); -+ /* todo_wine on KWin */ -+ todo_wine_if(!EqualRect(&rc, &monitor_info.second_monitor)) -+ ok(EqualRect(&rc, &monitor_info.second_monitor), "Expected window rect %s, got %s.\n", -+ wine_dbgstr_rect(&monitor_info.second_monitor), wine_dbgstr_rect(&rc)); -+ DestroyWindow(hwnd); -+ -+ hwnd = CreateWindowA("static", "static2", WS_POPUP | WS_VISIBLE, -+ monitor_info.second_monitor.left, monitor_info.second_monitor.top, -+ 100, 100, NULL, NULL, NULL, NULL); -+ ok(!!hwnd, "CreateWindow failed, error %#x.\n", GetLastError()); -+ flush_events(TRUE); -+ -+ SetWindowPos(hwnd, 0, monitor_info.first_monitor.left, monitor_info.first_monitor.top, -+ monitor_info.first_monitor.right - monitor_info.first_monitor.left, -+ monitor_info.first_monitor.bottom - monitor_info.first_monitor.top, SWP_NOZORDER); -+ flush_events(TRUE); -+ GetWindowRect(hwnd, &rc); -+ /* todo_wine on KWin */ -+ todo_wine_if(!EqualRect(&rc, &monitor_info.first_monitor)) -+ ok(EqualRect(&rc, &monitor_info.first_monitor), "Expected window rect %s, got %s.\n", -+ wine_dbgstr_rect(&monitor_info.first_monitor), wine_dbgstr_rect(&rc)); -+ DestroyWindow(hwnd); -+ } -+ else -+ { -+ skip("This test requires two monitors present.\n"); -+ } - } - - static BOOL test_thick_child_got_minmax; -From 533d833c1ae99a2b51bf8389b3bfd55ed6dbb3b5 Mon Sep 17 00:00:00 2001 -From: Zhiyi Zhang -Date: Mon, 11 Oct 2021 11:03:06 +0200 -Subject: [PATCH] gdi32/tests: Test GetDeviceCaps() for DCs on multiple monitor - systems. - -Signed-off-by: Zhiyi Zhang ---- - dlls/gdi32/tests/dc.c | 217 ++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 217 insertions(+) - -diff --git a/dlls/gdi32/tests/dc.c b/dlls/gdi32/tests/dc.c -index 2e005f23f3c..1cc6c4cc81f 100644 ---- a/dlls/gdi32/tests/dc.c -+++ b/dlls/gdi32/tests/dc.c -@@ -1698,6 +1698,222 @@ static void test_SetPixel(void) - ok(c == ~0, "SetPixel returned: %x\n", c); - } - -+static void test_multi_monitor_dc(void) -+{ -+ INT value, count, old_count; -+ DWORD device_idx, mode_idx; -+ DEVMODEA dm, dm2, dm3; -+ DISPLAY_DEVICEA dd; -+ BOOL ret; -+ LONG res; -+ HDC hdc; -+ -+ /* Test DCs covering the entire virtual screen */ -+ hdc = CreateDCA("DISPLAY", NULL, NULL, NULL); -+ ok(!!hdc, "CreateDCA failed.\n"); -+ -+ memset(&dm, 0, sizeof(dm)); -+ dm.dmSize = sizeof(dm); -+ ret = EnumDisplaySettingsA(NULL, ENUM_CURRENT_SETTINGS, &dm); -+ ok(ret, "EnumDisplaySettingsA failed.\n"); -+ -+ value = GetDeviceCaps(hdc, HORZRES); -+ ok(value == dm.dmPelsWidth, "Expected %d, got %d.\n", dm.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, VERTRES); -+ ok(value == dm.dmPelsHeight, "Expected %d, got %d.\n", dm.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPHORZRES); -+ todo_wine_if(dm.dmPelsWidth != GetSystemMetrics(SM_CXVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CXVIRTUALSCREEN)) -+ ok(value == dm.dmPelsWidth, "Expected %d, got %d.\n", dm.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPVERTRES); -+ todo_wine_if(dm.dmPelsHeight != GetSystemMetrics(SM_CYVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CYVIRTUALSCREEN)) -+ ok(value == dm.dmPelsHeight, "Expected %d, got %d.\n", dm.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, VREFRESH); -+ todo_wine_if(value != dm.dmDisplayFrequency && value == 1) -+ ok(value == dm.dmDisplayFrequency, "Expected %d, got %d.\n", dm.dmDisplayFrequency, value); -+ -+ /* Test GetDeviceCaps() values after mode changes */ -+ memset(&dm2, 0, sizeof(dm2)); -+ dm2.dmSize = sizeof(dm2); -+ for (mode_idx = 0; EnumDisplaySettingsA(NULL, mode_idx, &dm2); ++mode_idx) -+ { -+ if (dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight) -+ break; -+ } -+ ok(dm2.dmPelsWidth && dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight, -+ "Failed to find a different resolution.\n"); -+ -+ res = ChangeDisplaySettingsExA(NULL, &dm2, NULL, CDS_RESET, NULL); -+ ok(res == DISP_CHANGE_SUCCESSFUL || broken(res == DISP_CHANGE_FAILED), /* Win8 TestBots */ -+ "ChangeDisplaySettingsExA returned unexpected %d.\n", res); -+ if (res == DISP_CHANGE_SUCCESSFUL) -+ { -+ value = GetDeviceCaps(hdc, HORZRES); -+ ok(value == dm2.dmPelsWidth, "Expected %d, got %d.\n", dm2.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, VERTRES); -+ ok(value == dm2.dmPelsHeight, "Expected %d, got %d.\n", dm2.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPHORZRES); -+ todo_wine_if(dm2.dmPelsWidth != GetSystemMetrics(SM_CXVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CXVIRTUALSCREEN)) -+ ok(value == dm2.dmPelsWidth, "Expected %d, got %d.\n", dm2.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPVERTRES); -+ todo_wine_if(dm2.dmPelsHeight != GetSystemMetrics(SM_CYVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CYVIRTUALSCREEN)) -+ ok(value == dm2.dmPelsHeight, "Expected %d, got %d.\n", dm2.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, VREFRESH); -+ todo_wine_if(value != dm2.dmDisplayFrequency && value == 1) -+ ok(value == dm2.dmDisplayFrequency, "Expected %d, got %d.\n", dm2.dmDisplayFrequency, value); -+ -+ res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); -+ ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA returned unexpected %d.\n", res); -+ } -+ -+ DeleteDC(hdc); -+ -+ /* Test DCs covering a specific monitor */ -+ dd.cb = sizeof(dd); -+ for (device_idx = 0; EnumDisplayDevicesA(NULL, device_idx, &dd, 0); ++device_idx) -+ { -+ if (!(dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) -+ continue; -+ -+ memset(&dm, 0, sizeof(dm)); -+ dm.dmSize = sizeof(dm); -+ ret = EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm); -+ ok(ret, "EnumDisplaySettingsA %s failed.\n", dd.DeviceName); -+ -+ hdc = CreateDCA(dd.DeviceName, NULL, NULL, NULL); -+ ok(!!hdc, "CreateDCA %s failed.\n", dd.DeviceName); -+ -+ value = GetDeviceCaps(hdc, HORZRES); -+ todo_wine_if(dm.dmPelsWidth != GetSystemMetrics(SM_CXSCREEN)) -+ ok(value == dm.dmPelsWidth, "Expected %d, got %d.\n", dm.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, VERTRES); -+ todo_wine_if(dm.dmPelsHeight != GetSystemMetrics(SM_CYSCREEN)) -+ ok(value == dm.dmPelsHeight, "Expected %d, got %d.\n", dm.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPHORZRES); -+ todo_wine_if(dm.dmPelsWidth != GetSystemMetrics(SM_CXVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CXVIRTUALSCREEN)) -+ ok(value == dm.dmPelsWidth, "Expected %d, got %d.\n", dm.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPVERTRES); -+ todo_wine_if(dm.dmPelsHeight != GetSystemMetrics(SM_CYVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CYVIRTUALSCREEN)) -+ ok(value == dm.dmPelsHeight, "Expected %d, got %d.\n", dm.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, VREFRESH); -+ todo_wine_if(value != dm.dmDisplayFrequency && value == 1) -+ ok(value == dm.dmDisplayFrequency, "Expected %d, got %d.\n", dm.dmDisplayFrequency, value); -+ -+ /* Test GetDeviceCaps() values after mode changes */ -+ memset(&dm2, 0, sizeof(dm2)); -+ dm2.dmSize = sizeof(dm2); -+ for (mode_idx = 0; EnumDisplaySettingsA(dd.DeviceName, mode_idx, &dm2); ++mode_idx) -+ { -+ if (dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight) -+ break; -+ } -+ ok(dm2.dmPelsWidth && dm2.dmPelsWidth != dm.dmPelsWidth && dm2.dmPelsHeight != dm.dmPelsHeight, -+ "Failed to find a different resolution for %s.\n", dd.DeviceName); -+ -+ res = ChangeDisplaySettingsExA(dd.DeviceName, &dm2, NULL, CDS_RESET, NULL); -+ ok(res == DISP_CHANGE_SUCCESSFUL -+ || broken(res == DISP_CHANGE_FAILED), /* Win8 TestBots */ -+ "ChangeDisplaySettingsExA %s returned unexpected %d.\n", dd.DeviceName, res); -+ if (res != DISP_CHANGE_SUCCESSFUL) -+ { -+ win_skip("Failed to change display mode for %s.\n", dd.DeviceName); -+ DeleteDC(hdc); -+ continue; -+ } -+ -+ value = GetDeviceCaps(hdc, HORZRES); -+ todo_wine_if(dm2.dmPelsWidth != GetSystemMetrics(SM_CXSCREEN)) -+ ok(value == dm2.dmPelsWidth, "Expected %d, got %d.\n", dm2.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, VERTRES); -+ todo_wine_if(dm2.dmPelsHeight != GetSystemMetrics(SM_CYSCREEN)) -+ ok(value == dm2.dmPelsHeight, "Expected %d, got %d.\n", dm2.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPHORZRES); -+ todo_wine_if(dm2.dmPelsWidth != GetSystemMetrics(SM_CXVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CXVIRTUALSCREEN)) -+ ok(value == dm2.dmPelsWidth, "Expected %d, got %d.\n", dm2.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPVERTRES); -+ todo_wine_if(dm2.dmPelsHeight != GetSystemMetrics(SM_CYVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CYVIRTUALSCREEN)) -+ ok(value == dm2.dmPelsHeight, "Expected %d, got %d.\n", dm2.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, VREFRESH); -+ todo_wine_if(value != dm2.dmDisplayFrequency && value == 1) -+ ok(value == dm2.dmDisplayFrequency, "Expected %d, got %d.\n", dm2.dmDisplayFrequency, value); -+ -+ /* Test GetDeviceCaps() values after monitor detach */ -+ if (!(dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) -+ { -+ old_count = GetSystemMetrics(SM_CMONITORS); -+ -+ ret = EnumDisplaySettingsA(dd.DeviceName, ENUM_CURRENT_SETTINGS, &dm3); -+ ok(ret, "EnumDisplaySettingsA %s failed.\n", dd.DeviceName); -+ -+ dm3.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT; -+ dm3.dmPelsWidth = 0; -+ dm3.dmPelsHeight = 0; -+ res = ChangeDisplaySettingsExA(dd.DeviceName, &dm3, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); -+ ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %d.\n", -+ dd.DeviceName, res); -+ res = ChangeDisplaySettingsExA(dd.DeviceName, NULL, NULL, 0, NULL); -+ ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %d.\n", -+ dd.DeviceName, res); -+ -+ count = GetSystemMetrics(SM_CMONITORS); -+ ok(count == old_count - 1, "Expect monitor count %d, got %d.\n", old_count - 1, count); -+ -+ /* Should report the same values before detach */ -+ value = GetDeviceCaps(hdc, HORZRES); -+ todo_wine_if(dm2.dmPelsWidth != GetSystemMetrics(SM_CXSCREEN)) -+ ok(value == dm2.dmPelsWidth, "Expected %d, got %d.\n", dm2.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, VERTRES); -+ todo_wine_if(dm2.dmPelsHeight != GetSystemMetrics(SM_CYSCREEN)) -+ ok(value == dm2.dmPelsHeight, "Expected %d, got %d.\n", dm2.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPHORZRES); -+ todo_wine_if(dm2.dmPelsWidth != GetSystemMetrics(SM_CXVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CXVIRTUALSCREEN)) -+ ok(value == dm2.dmPelsWidth, "Expected %d, got %d.\n", dm2.dmPelsWidth, value); -+ -+ value = GetDeviceCaps(hdc, DESKTOPVERTRES); -+ todo_wine_if(dm2.dmPelsHeight != GetSystemMetrics(SM_CYVIRTUALSCREEN) -+ && value == GetSystemMetrics(SM_CYVIRTUALSCREEN)) -+ ok(value == dm2.dmPelsHeight, "Expected %d, got %d.\n", dm2.dmPelsHeight, value); -+ -+ value = GetDeviceCaps(hdc, VREFRESH); -+ todo_wine_if(value != dm2.dmDisplayFrequency && value == 1) -+ ok(value == dm2.dmDisplayFrequency, "Expected %d, got %d.\n", dm2.dmDisplayFrequency, value); -+ } -+ -+ res = ChangeDisplaySettingsExA(dd.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY | CDS_NORESET, NULL); -+ ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %d.\n", -+ dd.DeviceName, res); -+ res = ChangeDisplaySettingsExA(NULL, NULL, NULL, 0, NULL); -+ ok(res == DISP_CHANGE_SUCCESSFUL, "ChangeDisplaySettingsExA %s returned unexpected %d.\n", -+ dd.DeviceName, res); -+ DeleteDC(hdc); -+ } -+} - - START_TEST(dc) - { -@@ -1716,4 +1932,5 @@ START_TEST(dc) - test_pscript_printer_dc(); - test_clip_box(); - test_SetPixel(); -+ test_multi_monitor_dc(); - } -From 9807dd24837a522537dfc0e84cdf5e29693df837 Mon Sep 17 00:00:00 2001 -From: Zhiyi Zhang -Date: Tue, 26 May 2020 22:36:07 +0800 -Subject: [PATCH] winex11.drv: Do not move window with _NET_WM_STATE_FULLSCREEN - set. - -Signed-off-by: Zhiyi Zhang ---- - dlls/user32/tests/win.c | 4 ---- - dlls/winex11.drv/window.c | 13 +++++++++++++ - 2 files changed, 13 insertions(+), 4 deletions(-) - -diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c -index 83969bf89f6..4722be3fd47 100644 ---- a/dlls/user32/tests/win.c -+++ b/dlls/user32/tests/win.c -@@ -8793,8 +8793,6 @@ static void test_fullscreen(void) - monitor_info.second_monitor.bottom - monitor_info.second_monitor.top, SWP_NOZORDER); - flush_events(TRUE); - GetWindowRect(hwnd, &rc); -- /* todo_wine on KWin */ -- todo_wine_if(!EqualRect(&rc, &monitor_info.second_monitor)) - ok(EqualRect(&rc, &monitor_info.second_monitor), "Expected window rect %s, got %s.\n", - wine_dbgstr_rect(&monitor_info.second_monitor), wine_dbgstr_rect(&rc)); - DestroyWindow(hwnd); -@@ -8810,8 +8808,6 @@ static void test_fullscreen(void) - monitor_info.first_monitor.bottom - monitor_info.first_monitor.top, SWP_NOZORDER); - flush_events(TRUE); - GetWindowRect(hwnd, &rc); -- /* todo_wine on KWin */ -- todo_wine_if(!EqualRect(&rc, &monitor_info.first_monitor)) - ok(EqualRect(&rc, &monitor_info.first_monitor), "Expected window rect %s, got %s.\n", - wine_dbgstr_rect(&monitor_info.first_monitor), wine_dbgstr_rect(&rc)); - DestroyWindow(hwnd); -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index ac7c0005a14..bbe2a1728b5 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1487,6 +1487,7 @@ static void sync_window_position( struct x11drv_win_data *data, - { - DWORD style = GetWindowLongW( data->hwnd, GWL_STYLE ); - DWORD ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE ); -+ RECT original_rect = {0}; - XWindowChanges changes; - unsigned int mask = 0; - -@@ -1541,9 +1542,21 @@ static void sync_window_position( struct x11drv_win_data *data, - - set_size_hints( data, style ); - set_mwm_hints( data, style, ex_style ); -+ /* KWin doesn't allow moving a window with _NET_WM_STATE_FULLSCREEN set. So we need to remove -+ * _NET_WM_STATE_FULLSCREEN before moving the window and restore it later */ -+ if (wm_is_kde( data->display ) && is_window_rect_full_screen( &data->whole_rect )) -+ { -+ original_rect = data->whole_rect; -+ SetRectEmpty( &data->whole_rect ); -+ } - update_net_wm_states( data ); - data->configure_serial = NextRequest( data->display ); - XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); -+ if (!IsRectEmpty( &original_rect )) -+ { -+ data->whole_rect = original_rect; -+ update_net_wm_states( data ); -+ } - #ifdef HAVE_LIBXSHAPE - if (IsRectEmpty( old_window_rect ) != IsRectEmpty( &data->window_rect )) - sync_window_region( data, (HRGN)1 ); -From fa17abadf6856748a1502464dcb0c56fea0d58a8 Mon Sep 17 00:00:00 2001 -From: Andrew Eikum -Date: Thu, 18 Feb 2021 10:05:52 -0600 -Subject: [PATCH] winex11.drv: Support adjusting gamma in the fshack - -CW-Bug-Id: 16421 ---- - dlls/winex11.drv/fs.c | 33 ++ - dlls/winex11.drv/opengl.c | 637 ++++++++++++++++++++++++++++++++---- - dlls/winex11.drv/x11drv.h | 2 + - dlls/winex11.drv/xvidmode.c | 23 +- - 4 files changed, 622 insertions(+), 73 deletions(-) - -diff --git a/dlls/winex11.drv/fs.c b/dlls/winex11.drv/fs.c -index 641fdd40d45..913c37dee68 100644 ---- a/dlls/winex11.drv/fs.c -+++ b/dlls/winex11.drv/fs.c -@@ -39,6 +39,10 @@ static struct x11drv_display_device_handler real_device_handler; - static struct x11drv_settings_handler real_settings_handler; - static struct list fs_monitors = LIST_INIT(fs_monitors); - -+static WORD gamma_ramp_i[GAMMA_RAMP_SIZE * 3]; -+static float gamma_ramp[GAMMA_RAMP_SIZE * 4]; -+static LONG gamma_serial; -+ - /* Access to fs_monitors is protected by fs_section */ - static CRITICAL_SECTION fs_section; - static CRITICAL_SECTION_DEBUG critsect_debug = -@@ -897,3 +901,32 @@ void fs_hack_init(void) - device_handler.register_event_handlers = NULL; - X11DRV_DisplayDevices_SetHandler(&device_handler); - } -+ -+const float *fs_hack_get_gamma_ramp(LONG *serial) -+{ -+ if(gamma_serial == 0) -+ return NULL; -+ if(serial) -+ *serial = gamma_serial; -+ return gamma_ramp; -+} -+ -+void fs_hack_set_gamma_ramp(const WORD *ramp) -+{ -+ int i; -+ if(memcmp(gamma_ramp_i, ramp, sizeof(gamma_ramp_i)) == 0){ -+ /* identical */ -+ return; -+ } -+ for(i = 0; i < GAMMA_RAMP_SIZE; ++i){ -+ gamma_ramp[i * 4 ] = ramp[i ] / 65535.f; -+ gamma_ramp[i * 4 + 1] = ramp[i + GAMMA_RAMP_SIZE] / 65535.f; -+ gamma_ramp[i * 4 + 2] = ramp[i + 2 * GAMMA_RAMP_SIZE] / 65535.f; -+ } -+ memcpy(gamma_ramp_i, ramp, sizeof(gamma_ramp_i)); -+ InterlockedIncrement(&gamma_serial); -+ TRACE("new gamma serial: %u\n", gamma_serial); -+ if(gamma_serial == 0){ -+ InterlockedIncrement(&gamma_serial); -+ } -+} -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 53ac19dfe50..fab13d5b1df 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -209,9 +209,11 @@ struct wgl_context - BOOL refresh_drawables; - BOOL fs_hack; - BOOL fs_hack_integer; -+ BOOL is_core; - GLuint fs_hack_fbo, fs_hack_resolve_fbo; - GLuint fs_hack_color_texture, fs_hack_ds_texture; -- GLuint fs_hack_color_renderbuffer, fs_hack_color_resolve_renderbuffer, fs_hack_ds_renderbuffer; -+ GLuint fs_hack_color_renderbuffer, fs_hack_ds_renderbuffer; -+ GLuint fs_hack_gamma_pgm, ramp_ubo; - POINT setup_for; - GLuint current_draw_fbo, current_read_fbo; - struct list entry; -@@ -262,6 +264,11 @@ struct gl_drawable - BOOL fs_hack_did_swapbuf; - BOOL fs_hack_context_set_up; - BOOL has_scissor_indexed; -+ BOOL has_clip_control; -+ BOOL has_ati_frag_shader; -+ BOOL has_fragment_program; -+ BOOL has_vertex_program; -+ LONG last_gamma_serial; - }; - - enum glx_swap_control_method -@@ -385,10 +392,6 @@ static int (*pglXSwapIntervalSGI)(int); - static void* (*pglXAllocateMemoryNV)(GLsizei size, GLfloat readfreq, GLfloat writefreq, GLfloat priority); - static void (*pglXFreeMemoryNV)(GLvoid *pointer); - --static void (*pglScissorIndexed)(GLuint, GLint, GLint, GLsizei, GLsizei); --static void (*pglScissorIndexedv)(GLuint, const GLint *); --static void (*pglGetIntegeri_v)(GLenum, GLuint, GLint *); -- - /* MESA GLX Extensions */ - static void (*pglXCopySubBufferMESA)(Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); - static int (*pglXSwapIntervalMESA)(unsigned int interval); -@@ -413,21 +416,57 @@ static void wglFlush(void); - static const GLubyte *wglGetString(GLenum name); - - /* Fullscreen hack */ -+static void (*pglActiveTexture)( GLenum texture ); -+static void (*pglAttachShader)( GLuint program, GLuint shader ); -+static void (*pglBindBuffer)( GLenum target, GLuint buffer ); -+static void (*pglBindBufferBase)( GLenum target, GLuint index, GLuint buffer ); -+static void (*pglBindBufferRange)( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size ); - static void (*pglBindFramebuffer)( GLenum target, GLuint framebuffer ); - static void (*pglBindFramebufferEXT)( GLenum target, GLuint framebuffer ); - static void (*pglBindRenderbuffer)( GLenum target, GLuint renderbuffer ); -+static void (*pglBindSampler)( GLuint target, GLuint sampler ); - static void (*pglBlitFramebuffer)( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ); --void (*pglDeleteFramebuffers)( GLsizei n, const GLuint *framebuffers ); --void (*pglDeleteRenderbuffers)( GLsizei n, const GLuint *renderbuffers ); -+static void (*pglBufferData)( GLenum target, GLsizeiptr size, const void *data, GLenum usage ); -+static void (*pglClipControl)( GLenum origin, GLenum depth ); -+static void (*pglColorMaski)( GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a ); -+static void (*pglCompileShader)( GLuint shader ); -+static GLuint (*pglCreateProgram)( void ); -+static GLuint (*pglCreateShader)( GLenum type ); -+static void (*pglDeleteBuffers)( GLsizei n, GLuint *buffers ); -+static void (*pglDeleteFramebuffers)( GLsizei n, const GLuint *framebuffers ); -+static void (*pglDeleteProgram)( GLuint program ); -+static void (*pglDeleteRenderbuffers)( GLsizei n, const GLuint *renderbuffers ); -+static void (*pglDeleteShader)( GLuint shader ); -+static void (*pglDrawArrays)( GLenum mode, GLint first, GLsizei count ); - static void (*pglDrawBuffer)( GLenum buffer ); - static void (*pglFramebufferRenderbuffer)( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer ); - static void (*pglFramebufferTexture2D)( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level ); -+static void (*pglGenBuffers)( GLsizei n, GLuint *buffers ); - static void (*pglGenFramebuffers)( GLsizei n, GLuint *ids ); -+static void (*pglGetBooleani_v )(GLenum target, GLuint index, GLboolean *data); -+static void (*pglGetInteger64i_v)(GLenum target, GLuint index, GLint64 *data); -+static void (*pglGetIntegeri_v)(GLenum, GLuint, GLint *); -+static void (*pglGetFloati_v)(GLenum, GLuint, GLfloat *); - static void (*pglGenRenderbuffers)( GLsizei n, GLuint *renderbuffers ); -+static void (*pglGetProgramiv)( GLuint program, GLenum pname, GLint *params ); -+static void (*pglGetProgramInfoLog)( GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog ); -+static void (*pglGetShaderiv)( GLuint shader, GLenum pname, GLint *params ); -+static void (*pglGetShaderInfoLog)( GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog ); -+static GLuint (*pglGetUniformBlockIndex)( GLuint program, const GLchar *uniformBlockName ); -+static GLint (*pglGetUniformLocation)( GLuint program, const GLchar *name ); -+static void (*pglLinkProgram)( GLuint program ); - static void (*pglReadBuffer)( GLenum src ); - static void (*pglRenderbufferStorage)( GLenum target, GLenum internalformat, GLsizei width, GLsizei height ); - static void (*pglRenderbufferStorageMultisample)( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height ); -- -+static void (*pglScissorIndexed)(GLuint, GLint, GLint, GLsizei, GLsizei); -+static void (*pglScissorIndexedv)(GLuint, const GLint *); -+static void (*pglShaderSource)( GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length ); -+static void (*pglUniformBlockBinding)( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding ); -+static void (*pglUniform1i)( GLint location, GLint v0 ); -+static void (*pglUseProgram)( GLuint program ); -+static void (*pglViewportIndexedf)( GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h ); -+static void (*pglViewportIndexedfv)( GLuint index, const GLfloat *v ); -+static void (*pglGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint *params); - static void wglBindFramebuffer( GLenum target, GLuint framebuffer ); - static void wglBindFramebufferEXT( GLenum target, GLuint framebuffer ); - static void wglDrawBuffer( GLenum buffer ); -@@ -623,18 +662,55 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context ) - - /* Fullscreen hack */ - #define LOAD_FUNCPTR(func) p##func = (void *)pglXGetProcAddressARB((const unsigned char *)#func); -+ LOAD_FUNCPTR( glActiveTexture ); -+ LOAD_FUNCPTR( glAttachShader ); -+ LOAD_FUNCPTR( glBindBuffer ); -+ LOAD_FUNCPTR( glBindBufferBase ); -+ LOAD_FUNCPTR( glBindBufferRange ); - LOAD_FUNCPTR( glBindFramebuffer ); - LOAD_FUNCPTR( glBindFramebufferEXT ); - LOAD_FUNCPTR( glBindRenderbuffer ); -+ LOAD_FUNCPTR( glBindSampler ); - LOAD_FUNCPTR( glBlitFramebuffer ); -+ LOAD_FUNCPTR( glBufferData ); -+ LOAD_FUNCPTR( glClipControl ); -+ LOAD_FUNCPTR( glColorMaski ); -+ LOAD_FUNCPTR( glCompileShader ); -+ LOAD_FUNCPTR( glCreateProgram ); -+ LOAD_FUNCPTR( glCreateShader ); -+ LOAD_FUNCPTR( glDeleteBuffers ); - LOAD_FUNCPTR( glDeleteFramebuffers ); -+ LOAD_FUNCPTR( glDeleteProgram ); - LOAD_FUNCPTR( glDeleteRenderbuffers ); -+ LOAD_FUNCPTR( glDeleteShader ); -+ LOAD_FUNCPTR( glDrawArrays ); - LOAD_FUNCPTR( glFramebufferRenderbuffer ); - LOAD_FUNCPTR( glFramebufferTexture2D ); -+ LOAD_FUNCPTR( glGenBuffers ); - LOAD_FUNCPTR( glGenFramebuffers ); -+ LOAD_FUNCPTR( glGetBooleani_v ); -+ LOAD_FUNCPTR( glGetInteger64i_v ); -+ LOAD_FUNCPTR( glGetIntegeri_v ); -+ LOAD_FUNCPTR( glGetFloati_v ); - LOAD_FUNCPTR( glGenRenderbuffers ); -+ LOAD_FUNCPTR( glGetProgramiv ); -+ LOAD_FUNCPTR( glGetProgramInfoLog ); -+ LOAD_FUNCPTR( glGetShaderiv ); -+ LOAD_FUNCPTR( glGetShaderInfoLog ); -+ LOAD_FUNCPTR( glGetUniformBlockIndex ); -+ LOAD_FUNCPTR( glGetUniformLocation ); -+ LOAD_FUNCPTR( glLinkProgram ); - LOAD_FUNCPTR( glRenderbufferStorage ); - LOAD_FUNCPTR( glRenderbufferStorageMultisample ); -+ LOAD_FUNCPTR( glScissorIndexed ); -+ LOAD_FUNCPTR( glScissorIndexedv ); -+ LOAD_FUNCPTR( glShaderSource ); -+ LOAD_FUNCPTR( glUniformBlockBinding ); -+ LOAD_FUNCPTR( glUniform1i ); -+ LOAD_FUNCPTR( glUseProgram ); -+ LOAD_FUNCPTR( glViewportIndexedf ); -+ LOAD_FUNCPTR( glViewportIndexedfv ); -+ LOAD_FUNCPTR( glGetFramebufferAttachmentParameteriv ); - #undef LOAD_FUNCPTR - - #define LOAD_FUNCPTR(f) do if((p##f = (void*)pglXGetProcAddressARB((const unsigned char*)#f)) == NULL) \ -@@ -687,10 +763,6 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context ) - /* NV GLX Extension */ - LOAD_FUNCPTR(glXAllocateMemoryNV); - LOAD_FUNCPTR(glXFreeMemoryNV); -- -- LOAD_FUNCPTR(glScissorIndexed); -- LOAD_FUNCPTR(glScissorIndexedv); -- LOAD_FUNCPTR(glGetIntegeri_v); - #undef LOAD_FUNCPTR - - if(!X11DRV_WineGL_InitOpenglInfo()) goto failed; -@@ -781,13 +853,6 @@ static BOOL WINAPI init_opengl( INIT_ONCE *once, void *param, void **context ) - pglXSwapBuffersMscOML = pglXGetProcAddressARB( (const GLubyte *)"glXSwapBuffersMscOML" ); - } - -- if (has_extension( glExtensions, "GL_ARB_viewport_array")) -- { -- opengl_funcs.ext.p_glGetIntegeri_v = pglGetIntegeri_v; -- opengl_funcs.ext.p_glScissorIndexed = pglScissorIndexed; -- opengl_funcs.ext.p_glScissorIndexedv = pglScissorIndexedv; -- } -- - X11DRV_WineGL_LoadExtensions(); - init_pixel_formats( gdi_display ); - return TRUE; -@@ -1554,7 +1619,7 @@ void sync_gl_drawable( HWND hwnd, BOOL known_child ) - - if (DC_GL_PIXMAP_WIN != old->type) { - data = get_win_data( hwnd ); -- old->fs_hack = data->fs_hack; -+ old->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp(NULL) != NULL; - if (old->fs_hack) - TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); - release_win_data( data ); -@@ -1902,7 +1967,6 @@ struct fs_hack_fbconfig_attribs - int stencil_size; - int doublebuffer; - int samples; -- int srgb; - }; - - struct fs_hack_fbo_attachments_config -@@ -1924,10 +1988,7 @@ static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_ha - if (attribs->red_size != 8 || attribs->green_size != 8 || attribs->blue_size != 8) - FIXME( "Unsupported RGBA color sizes {%u, %u, %u, %u}.\n", - attribs->red_size, attribs->green_size, attribs->blue_size, attribs->alpha_size ); -- if (attribs->srgb) -- config->color_internalformat = attribs->alpha_size ? GL_SRGB8_ALPHA8 : GL_SRGB8; -- else -- config->color_internalformat = attribs->alpha_size ? GL_RGBA8 : GL_RGB8; -+ config->color_internalformat = attribs->alpha_size ? GL_SRGB8_ALPHA8 : GL_SRGB8; - config->color_format = GL_BGRA; - config->color_type = GL_UNSIGNED_INT_8_8_8_8_REV; - if (attribs->depth_size || attribs->stencil_size) -@@ -1947,6 +2008,161 @@ static void fs_hack_get_attachments_config( struct gl_drawable *gl, struct fs_ha - config->samples = attribs->samples; - } - -+static const float *fs_hack_get_default_gamma_ramp(void) -+{ -+ static float default_gamma_ramp[GAMMA_RAMP_SIZE * 4]; -+ static BOOL initialized; -+ unsigned int i; -+ -+ if (!initialized) -+ { -+ for (i = 0; i < GAMMA_RAMP_SIZE; i++) -+ default_gamma_ramp[i * 4 ] = -+ default_gamma_ramp[i * 4 + 1] = -+ default_gamma_ramp[i * 4 + 2] = -+ i / (float)(GAMMA_RAMP_SIZE - 1); -+ initialized = TRUE; -+ } -+ return default_gamma_ramp; -+} -+ -+static const char *fs_hack_gamma_vertex_shader_src = -+"#version 330\n" -+"\n" -+"const vec4 square[4] = vec4[4](\n" -+" vec4(-1.0, -1.0, 0.0, 1.0),\n" -+" vec4(-1.0, 1.0, 0.0, 1.0),\n" -+" vec4(1.0, -1.0, 0.0, 1.0),\n" -+" vec4(1.0, 1.0, 0.0, 1.0)\n" -+");\n" -+"const vec2 texsq[4] = vec2[4](\n" -+" vec2(0.0, 0.0),\n" -+" vec2(0.0, 1.0),\n" -+" vec2(1.0, 0.0),\n" -+" vec2(1.0, 1.0)\n" -+");\n" -+"\n" -+"out vec2 texCoord;\n" -+"\n" -+"void main(void)\n" -+"{\n" -+" gl_Position = square[gl_VertexID];\n" -+" texCoord = texsq[gl_VertexID];\n" -+"}\n" -+; -+ -+static const char *fs_hack_gamma_frag_shader_src = -+"#version 330\n" -+"\n" -+"uniform sampler2D tex;\n" -+"in vec2 texCoord;\n" -+"layout (std140) uniform ramp {\n" -+" vec3 values[256];\n" -+"};\n" -+"\n" -+"layout(location = 0) out vec4 outColor;\n" -+"\n" -+"void main(void)\n" -+"{\n" -+" vec4 lookup = texture(tex, texCoord) * 255.0;\n" -+" outColor.r = values[int(lookup.r)].r;\n" -+" outColor.g = values[int(lookup.g)].g;\n" -+" outColor.b = values[int(lookup.b)].b;\n" -+" outColor.a = 1.0;\n" -+"}\n" -+; -+ -+static void fs_hack_setup_gamma_shader( struct wgl_context *ctx, struct gl_drawable *gl ) -+{ -+ GLint success; -+ GLuint vshader, fshader, program, ramp_index, tex_loc, prev_program; -+ char errstr[512]; -+ const float *default_gamma_ramp = fs_hack_get_default_gamma_ramp(); -+ -+ opengl_funcs.gl.p_glGetIntegerv( GL_CURRENT_PROGRAM, (GLint *)&prev_program ); -+ /* vertex shader */ -+ vshader = pglCreateShader(GL_VERTEX_SHADER); -+ if(vshader == 0){ -+ ERR("Failed to create gamma vertex shader\n"); -+ return; -+ } -+ pglShaderSource(vshader, 1, &fs_hack_gamma_vertex_shader_src, NULL); -+ pglCompileShader(vshader); -+ -+ pglGetShaderiv(vshader, GL_COMPILE_STATUS, &success); -+ if(!success){ -+ pglGetShaderInfoLog(vshader, sizeof(errstr), NULL, errstr); -+ ERR("Compiling gamma vertex shader failed: %s\n", errstr); -+ pglDeleteShader(vshader); -+ return; -+ } -+ -+ -+ /* fragment shader */ -+ fshader = pglCreateShader(GL_FRAGMENT_SHADER); -+ if(fshader == 0){ -+ ERR("Failed to create gamma fragment shader\n"); -+ pglDeleteShader(vshader); -+ return; -+ } -+ pglShaderSource(fshader, 1, &fs_hack_gamma_frag_shader_src, NULL); -+ pglCompileShader(fshader); -+ -+ pglGetShaderiv(fshader, GL_COMPILE_STATUS, &success); -+ if(!success){ -+ pglGetShaderInfoLog(fshader, sizeof(errstr), NULL, errstr); -+ ERR("Compiling gamma fragment shader failed: %s\n", errstr); -+ pglDeleteShader(fshader); -+ pglDeleteShader(vshader); -+ return; -+ } -+ -+ -+ /* gamma program */ -+ program = pglCreateProgram(); -+ if(program == 0){ -+ ERR("Failed to create gamma program\n"); -+ pglDeleteShader(fshader); -+ pglDeleteShader(vshader); -+ return; -+ } -+ -+ pglAttachShader(program, vshader); -+ pglAttachShader(program, fshader); -+ -+ pglLinkProgram(program); -+ -+ pglGetProgramiv(program, GL_LINK_STATUS, &success); -+ if(!success){ -+ pglGetProgramInfoLog(program, sizeof(errstr), NULL, errstr); -+ ERR("Linking gamma shader failed: %s\n", errstr); -+ pglDeleteProgram(program); -+ pglDeleteShader(fshader); -+ pglDeleteShader(vshader); -+ return; -+ } -+ -+ pglDeleteShader(fshader); -+ pglDeleteShader(vshader); -+ -+ pglGenBuffers(1, &ctx->ramp_ubo); -+ pglBindBuffer(GL_UNIFORM_BUFFER, ctx->ramp_ubo); -+ pglBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4 * GAMMA_RAMP_SIZE, default_gamma_ramp, GL_DYNAMIC_DRAW); -+ gl->last_gamma_serial = 0; -+ -+ ramp_index = pglGetUniformBlockIndex(program, "ramp"); -+ pglUniformBlockBinding(program, ramp_index, 0); -+ -+ pglUseProgram( program ); -+ -+ tex_loc = pglGetUniformLocation(program, "tex"); -+ pglUniform1i(tex_loc, 0); -+ -+ ctx->fs_hack_gamma_pgm = program; -+ -+ pglUseProgram( prev_program ); -+} -+ - static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable *gl ) - { - GLuint prev_draw_fbo, prev_read_fbo, prev_texture, prev_renderbuffer; -@@ -1972,7 +2188,6 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - {GLX_STENCIL_SIZE, offsetof(struct fs_hack_fbconfig_attribs, stencil_size)}, - {GLX_DOUBLEBUFFER, offsetof(struct fs_hack_fbconfig_attribs, doublebuffer)}, - {GLX_SAMPLES_ARB, offsetof(struct fs_hack_fbconfig_attribs, samples)}, -- {GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, offsetof(struct fs_hack_fbconfig_attribs, srgb)}, - }; - BYTE *ptr = (BYTE *)&attribs; - -@@ -1981,6 +2196,7 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - MONITORINFO monitor_info; - HMONITOR monitor; - int width, height; -+ GLuint profile; - - monitor = fs_hack_monitor_from_hwnd(WindowFromDC(ctx->hdc)); - memset(&monitor_info, 0, sizeof(monitor_info)); -@@ -1991,6 +2207,9 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - - TRACE("Render buffer width:%d height:%d\n", width, height); - -+ opengl_funcs.gl.p_glGetIntegerv( GL_CONTEXT_PROFILE_MASK, (GLint *)&profile ); -+ ctx->is_core = (profile & GL_CONTEXT_CORE_PROFILE_BIT) != 0; -+ - opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_draw_fbo ); - opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&prev_read_fbo ); - opengl_funcs.gl.p_glGetIntegerv( GL_TEXTURE_BINDING_2D, (GLint *)&prev_texture ); -@@ -2006,13 +2225,27 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - pglGenFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); - TRACE( "Created FBO %u for fullscreen hack.\n", ctx->fs_hack_fbo ); - } -- pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0); - - for (i = 0; i < ARRAY_SIZE(queries); ++i) - pglXGetFBConfigAttrib( gdi_display, gl->format->fbconfig, queries[i].attribute, - (int *)&ptr[queries[i].offset] ); -+ -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); -+ - fs_hack_get_attachments_config( gl, &attribs, &config ); - -+ if (!ctx->fs_hack_color_texture) -+ opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_color_texture ); -+ opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_color_texture ); -+ opengl_funcs.gl.p_glTexImage2D( GL_TEXTURE_2D, 0, config.color_internalformat, width, height, -+ 0, config.color_format, config.color_type, NULL); -+ opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); -+ opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, -+ ctx->fs_hack_integer ? GL_NEAREST : GL_LINEAR); -+ opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, prev_texture ); -+ TRACE( "Created texture %u for fullscreen hack.\n", ctx->fs_hack_color_texture ); -+ - if (config.samples) - { - if (!ctx->fs_hack_color_renderbuffer) -@@ -2022,30 +2255,17 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - config.color_internalformat, width, height ); - pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); -- TRACE( "Created renderbuffer %u for fullscreen hack.\n", ctx->fs_hack_color_renderbuffer ); -- pglGenRenderbuffers( 1, &ctx->fs_hack_color_resolve_renderbuffer ); -- pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_resolve_renderbuffer ); -- pglRenderbufferStorage( GL_RENDERBUFFER, config.color_internalformat, width, height ); -+ TRACE( "Created renderbuffer %u and FBO %u for fullscreen hack.\n", ctx->fs_hack_color_renderbuffer, ctx->fs_hack_resolve_fbo ); - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); -- pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, -- GL_RENDERBUFFER, ctx->fs_hack_color_resolve_renderbuffer ); -+ pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, -+ GL_TEXTURE_2D, ctx->fs_hack_color_texture, 0 ); - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_fbo ); - pglBindRenderbuffer( GL_RENDERBUFFER, prev_renderbuffer ); -- TRACE( "Also created renderbuffer %u and FBO %u for color resolve.\n", -- ctx->fs_hack_color_resolve_renderbuffer, ctx->fs_hack_resolve_fbo ); - } - else - { -- if (!ctx->fs_hack_color_texture) -- opengl_funcs.gl.p_glGenTextures( 1, &ctx->fs_hack_color_texture ); -- opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_color_texture ); -- opengl_funcs.gl.p_glTexImage2D( GL_TEXTURE_2D, 0, config.color_internalformat, width, height, -- 0, config.color_format, config.color_type, NULL); -- opengl_funcs.gl.p_glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); -- opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, prev_texture ); - pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, ctx->fs_hack_color_texture, 0 ); -- TRACE( "Created texture %u for fullscreen hack.\n", ctx->fs_hack_color_texture ); - } - - if (config.ds_internalformat) -@@ -2083,6 +2303,8 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - } - } - -+ fs_hack_setup_gamma_shader(ctx, gl); -+ - if(!gl->fs_hack_context_set_up) - { - opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); -@@ -2105,6 +2327,10 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - ctx->setup_for.x = width; - ctx->setup_for.y = height; - gl->has_scissor_indexed = has_extension(glExtensions, "GL_ARB_viewport_array"); -+ gl->has_clip_control = has_extension(glExtensions, "GL_ARB_clip_control"); -+ gl->has_ati_frag_shader = !ctx->is_core && has_extension(glExtensions, "GL_ATI_fragment_shader"); -+ gl->has_fragment_program = !ctx->is_core && has_extension(glExtensions, "GL_ARB_fragment_program"); -+ gl->has_vertex_program = !ctx->is_core && has_extension(glExtensions, "GL_ARB_vertex_program"); - ctx->fs_hack_integer = fs_hack_is_integer(); - gl->fs_hack_context_set_up = TRUE; - } -@@ -2122,12 +2348,15 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - ctx->current_read_fbo = 0; - } - -+ pglDeleteBuffers(1, &ctx->ramp_ubo); -+ pglDeleteProgram(ctx->fs_hack_gamma_pgm); -+ ctx->fs_hack_gamma_pgm = 0; -+ - pglDeleteRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); -- pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_resolve_renderbuffer ); - pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); - opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_ds_texture ); - opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_color_texture ); -- ctx->fs_hack_color_renderbuffer = ctx->fs_hack_color_resolve_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; -+ ctx->fs_hack_color_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; - ctx->fs_hack_color_texture = ctx->fs_hack_ds_texture = 0; - pglDeleteFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); - pglDeleteFramebuffers( 1, &ctx->fs_hack_fbo ); -@@ -2349,16 +2578,264 @@ static void wglReadBuffer( GLenum buffer ) - pglReadBuffer( buffer ); - } - -+struct fs_hack_gl_state { -+ GLuint draw_fbo; -+ GLuint read_fbo; -+ GLuint program; -+ GLuint bound_texture; -+ GLint active_texture; -+ GLint clip_origin, clip_depth_mode; -+ GLuint ubo; -+ GLint64 ubo_size, ubo_start; -+ GLint viewporti[4]; -+ GLfloat viewportf[4]; -+ float clear_color[4]; -+ GLboolean scissor_test, cull_face, blend, alpha_test, depth_test, stencil_test; -+ GLboolean arb_frag, arb_vert, ati_frag, fb_srgb; -+ GLboolean clip_distance[8]; -+ GLboolean color_mask[4]; -+ GLuint sampler; -+}; -+ -+#define SET 0 -+#define RESET 1 -+ -+static void fs_hack_handle_enable_switch(int mode, GLenum cap, GLboolean *b, BOOL new) -+{ -+ if(mode == SET){ -+ *b = opengl_funcs.gl.p_glIsEnabled(cap); -+ if(new) -+ opengl_funcs.gl.p_glEnable(cap); -+ else -+ opengl_funcs.gl.p_glDisable(cap); -+ }else{ -+ if(*b) -+ opengl_funcs.gl.p_glEnable(cap); -+ else -+ opengl_funcs.gl.p_glDisable(cap); -+ } -+} -+ -+static void fs_hack_handle_fbo_state(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ if(mode == SET){ -+ opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&state->draw_fbo ); -+ opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&state->read_fbo ); -+ TRACE( "Previous draw FBO %u, read FBO %u\n", state->draw_fbo, state->read_fbo ); -+ -+ }else{ -+ pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, state->draw_fbo ); -+ pglBindFramebuffer( GL_READ_FRAMEBUFFER, state->read_fbo ); -+ } -+} -+ -+static void fs_hack_handle_clip_control(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ if(!gl->has_clip_control) -+ return; -+ -+ if(mode == SET){ -+ opengl_funcs.gl.p_glGetIntegerv(GL_CLIP_ORIGIN, (GLint *)&state->clip_origin); -+ opengl_funcs.gl.p_glGetIntegerv(GL_CLIP_DEPTH_MODE, (GLint *)&state->clip_depth_mode); -+ -+ -+ pglClipControl(GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE); -+ -+ }else{ -+ pglClipControl(state->clip_origin, state->clip_depth_mode); -+ } -+} -+ -+static void fs_hack_handle_shaders(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ if (gl->has_fragment_program) -+ fs_hack_handle_enable_switch(mode, GL_FRAGMENT_PROGRAM_ARB, &state->arb_frag, FALSE); -+ if (gl->has_vertex_program) -+ fs_hack_handle_enable_switch(mode, GL_VERTEX_PROGRAM_ARB, &state->arb_vert, FALSE); -+ fs_hack_handle_enable_switch(mode, GL_FRAMEBUFFER_SRGB, &state->fb_srgb, TRUE); -+ -+ if(gl->has_ati_frag_shader) -+ fs_hack_handle_enable_switch(mode, GL_FRAGMENT_SHADER_ATI, &state->ati_frag, FALSE); -+ -+ if(mode == SET){ -+ opengl_funcs.gl.p_glGetIntegerv( GL_CURRENT_PROGRAM, (GLint *)&state->program ); -+ -+ pglGetIntegeri_v( GL_UNIFORM_BUFFER_BINDING, 0, (GLint *)&state->ubo ); -+ pglGetInteger64i_v( GL_UNIFORM_BUFFER_START, 0, &state->ubo_start ); -+ pglGetInteger64i_v( GL_UNIFORM_BUFFER_SIZE, 0, &state->ubo_size ); -+ -+ opengl_funcs.gl.p_glGetIntegerv(GL_ACTIVE_TEXTURE, &state->active_texture); -+ pglActiveTexture(GL_TEXTURE0); -+ opengl_funcs.gl.p_glGetIntegerv( GL_TEXTURE_BINDING_2D, (GLint *)&state->bound_texture ); -+ pglGetIntegeri_v(GL_SAMPLER_BINDING, 0, (GLint *)&state->sampler); -+ -+ pglBindBufferBase(GL_UNIFORM_BUFFER, 0, ctx->ramp_ubo); -+ -+ opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, ctx->fs_hack_color_texture ); -+ pglBindSampler( 0, 0 ); -+ -+ pglUseProgram( ctx->fs_hack_gamma_pgm ); -+ -+ }else{ -+ pglUseProgram( state->program ); -+ -+ pglBindSampler( 0, state->sampler ); -+ -+ opengl_funcs.gl.p_glBindTexture( GL_TEXTURE_2D, state->bound_texture ); -+ pglActiveTexture(state->active_texture); -+ -+ pglBindBufferRange(GL_UNIFORM_BUFFER, 0, state->ubo, state->ubo_start, state->ubo_size); -+ } -+} -+ -+static void fs_hack_handle_viewport(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ if(mode == SET){ -+ if(gl->has_scissor_indexed){ -+ pglGetFloati_v(GL_VIEWPORT, 0, state->viewportf); -+ pglViewportIndexedf(0, scaled_origin->x, scaled_origin->y, scaled->cx, scaled->cy); -+ }else{ -+ opengl_funcs.gl.p_glGetIntegerv(GL_VIEWPORT, state->viewporti); -+ opengl_funcs.gl.p_glViewport(scaled_origin->x, scaled_origin->y, scaled->cx, scaled->cy); -+ } -+ -+ }else{ -+ if(gl->has_scissor_indexed){ -+ pglViewportIndexedfv(0, state->viewportf); -+ }else{ -+ opengl_funcs.gl.p_glViewport(state->viewporti[0], state->viewporti[1], -+ state->viewporti[2], state->viewporti[3]); -+ } -+ } -+} -+ -+static void fs_hack_handle_clear_color(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ if(mode == SET){ -+ opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, state->clear_color ); -+ opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); -+ }else{ -+ opengl_funcs.gl.p_glClearColor( state->clear_color[0], state->clear_color[1], state->clear_color[2], state->clear_color[3] ); -+ } -+} -+ -+static void fs_hack_handle_clip_distance(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ unsigned int i; -+ if(mode == SET){ -+ for(i = 0; i < ARRAY_SIZE(state->clip_distance); ++i){ -+ state->clip_distance[i] = opengl_funcs.gl.p_glIsEnabled(GL_CLIP_DISTANCE0 + i); -+ opengl_funcs.gl.p_glDisable(GL_CLIP_DISTANCE0 + i); -+ } -+ }else{ -+ for(i = 0; i < ARRAY_SIZE(state->clip_distance); ++i){ -+ if(state->clip_distance[i]) -+ opengl_funcs.gl.p_glEnable(GL_CLIP_DISTANCE0 + i); -+ } -+ } -+} -+ -+static void fs_hack_handle_color_mask(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ if(mode == SET){ -+ pglGetBooleani_v(GL_COLOR_WRITEMASK, 0, state->color_mask); -+ -+ pglColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -+ }else{ -+ pglColorMaski(0, state->color_mask[0], -+ state->color_mask[1], state->color_mask[2], -+ state->color_mask[3]); -+ } -+} -+ -+static void fs_hack_handle_scissor(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, -+ const SIZE *real, const SIZE *scaled, const POINT *scaled_origin) -+{ -+ fs_hack_handle_enable_switch(mode, GL_SCISSOR_TEST, &state->scissor_test, FALSE); -+} -+ -+static void fs_hack_handle_cull_face(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ fs_hack_handle_enable_switch(mode, GL_CULL_FACE, &state->cull_face, FALSE); -+} -+ -+static void fs_hack_handle_blend(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ fs_hack_handle_enable_switch(mode, GL_BLEND, &state->blend, FALSE); -+} -+ -+static void fs_hack_handle_alpha_test(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ if(ctx->is_core) -+ return; -+ -+ fs_hack_handle_enable_switch(mode, GL_ALPHA_TEST, &state->alpha_test, FALSE); -+} -+ -+static void fs_hack_handle_ds_test(int mode, struct gl_drawable *gl, -+ struct wgl_context *ctx, struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin) -+{ -+ fs_hack_handle_enable_switch(mode, GL_DEPTH_TEST, &state->depth_test, FALSE); -+ fs_hack_handle_enable_switch(mode, GL_STENCIL_TEST, &state->stencil_test, FALSE); -+} -+ - static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer ) - { -+ static const struct -+ { -+ void (*state_handler)(int mode, struct gl_drawable *gl, struct wgl_context *ctx, -+ struct fs_hack_gl_state *state, const SIZE *real, -+ const SIZE *scaled, const POINT *scaled_origin); -+ } -+ general_state_handlers[] = -+ { -+ {fs_hack_handle_fbo_state}, -+ {fs_hack_handle_scissor}, -+ {fs_hack_handle_clear_color}, -+ }, -+ draw_state_handlers[] = -+ { -+ {fs_hack_handle_clip_control}, -+ {fs_hack_handle_shaders}, -+ {fs_hack_handle_viewport}, -+ {fs_hack_handle_cull_face}, -+ {fs_hack_handle_clip_distance}, -+ {fs_hack_handle_color_mask}, -+ {fs_hack_handle_blend}, -+ {fs_hack_handle_alpha_test}, -+ {fs_hack_handle_ds_test}, -+ }; - struct wgl_context *ctx = NtCurrentTeb()->glContext; - SIZE scaled, src, real; -- GLuint prev_draw_fbo, prev_read_fbo; -- GLint prev_scissor[4]; - RECT user_rect, real_rect; - POINT scaled_origin; -- float prev_clear_color[4]; - HMONITOR monitor; -+ struct fs_hack_gl_state state; -+ const float *gamma_ramp; -+ LONG gamma_serial; -+ unsigned int i; - - monitor = fs_hack_monitor_from_hwnd(WindowFromDC(ctx->hdc)); - scaled = fs_hack_get_scaled_screen_size(monitor); -@@ -2374,6 +2851,8 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer - scaled_origin.x -= real_rect.left; - scaled_origin.y -= real_rect.top; - -+ gamma_ramp = fs_hack_get_gamma_ramp(&gamma_serial); -+ - TRACE("scaled:%dx%d src:%dx%d real:%dx%d user_rect:%s real_rect:%s scaled_origin:%s\n", scaled.cx, scaled.cy, - src.cx, src.cy, real.cx, real.cy, wine_dbgstr_rect(&user_rect), wine_dbgstr_rect(&real_rect), - wine_dbgstr_point(&scaled_origin)); -@@ -2382,54 +2861,68 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer - ctx->setup_for.y != src.cy) - fs_hack_setup_context( ctx, gl ); - -- TRACE( "Blitting from FBO %u %ux%u to %ux%u\n", ctx->fs_hack_fbo, src.cx, src.cy, scaled.cx, scaled.cy ); -+ /* Can't stretch blit with multisampled renderbuffers */ -+ if (ctx->fs_hack_color_renderbuffer && !gamma_ramp){ -+ gamma_ramp = fs_hack_get_default_gamma_ramp(); -+ gamma_serial = 0; -+ } - -- opengl_funcs.gl.p_glGetIntegerv( GL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&prev_draw_fbo ); -- opengl_funcs.gl.p_glGetIntegerv( GL_READ_FRAMEBUFFER_BINDING, (GLint *)&prev_read_fbo ); -- TRACE( "Previous draw FBO %u, read FBO %u\n", prev_draw_fbo, prev_read_fbo ); -+ TRACE( "Stretching from FBO %u %ux%u to %ux%u\n", ctx->fs_hack_fbo, src.cx, src.cy, scaled.cx, scaled.cy ); - -- if(gl->has_scissor_indexed){ -- opengl_funcs.ext.p_glGetIntegeri_v(GL_SCISSOR_BOX, 0, prev_scissor); -- opengl_funcs.ext.p_glScissorIndexed(0, 0, 0, real.cx, real.cy); -- }else{ -- opengl_funcs.gl.p_glGetIntegerv(GL_SCISSOR_BOX, prev_scissor); -- opengl_funcs.gl.p_glScissor(0, 0, real.cx, real.cy); -+ for (i = 0; i < ARRAY_SIZE(general_state_handlers); i++) -+ general_state_handlers[i].state_handler(SET, gl, ctx, &state, &real, &scaled, &scaled_origin); -+ -+ if(gamma_ramp){ -+ for (i = 0; i < ARRAY_SIZE(draw_state_handlers); i++) -+ draw_state_handlers[i].state_handler(SET, gl, ctx, &state, &real, &scaled, &scaled_origin); - } - - pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_fbo ); -- if (ctx->fs_hack_color_resolve_renderbuffer) -+ -+ if (ctx->fs_hack_color_renderbuffer) - { - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); -+ - pglBlitFramebuffer( 0, 0, src.cx, src.cy, 0, 0, src.cx, src.cy, GL_COLOR_BUFFER_BIT, GL_NEAREST ); -+ - pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); - } -+ - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); - - //HACK - //pglDrawBuffer( draw_buffer ); - pglDrawBuffer( GL_BACK ); - -- opengl_funcs.gl.p_glGetFloatv( GL_COLOR_CLEAR_VALUE, prev_clear_color ); -- opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - opengl_funcs.gl.p_glClear( GL_COLOR_BUFFER_BIT ); -- opengl_funcs.gl.p_glClearColor( prev_clear_color[0], prev_clear_color[1], prev_clear_color[2], prev_clear_color[3] ); - -- pglBlitFramebuffer( 0, 0, src.cx, src.cy, -- scaled_origin.x, scaled_origin.y, scaled_origin.x + scaled.cx, scaled_origin.y + scaled.cy, -- GL_COLOR_BUFFER_BIT, ctx->fs_hack_integer ? GL_NEAREST : GL_LINEAR ); -+ if(gamma_ramp){ -+ if(gamma_serial != gl->last_gamma_serial){ -+ TRACE("updating gamma ramp (serial: %u)\n", gamma_serial); -+ -+ pglBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4 * GAMMA_RAMP_SIZE, gamma_ramp, GL_DYNAMIC_DRAW); -+ -+ gl->last_gamma_serial = gamma_serial; -+ } -+ -+ pglDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -+ }else{ -+ pglBlitFramebuffer( 0, 0, src.cx, src.cy, -+ scaled_origin.x, scaled_origin.y, scaled_origin.x + scaled.cx, scaled_origin.y + scaled.cy, -+ GL_COLOR_BUFFER_BIT, ctx->fs_hack_integer ? GL_NEAREST : GL_LINEAR ); -+ } -+ - //HACK - if ( draw_buffer == GL_FRONT ) - pglXSwapBuffers(gdi_display, gl->drawable); - -- if(gl->has_scissor_indexed){ -- opengl_funcs.ext.p_glScissorIndexedv(0, prev_scissor); -- }else{ -- opengl_funcs.gl.p_glScissor(prev_scissor[0], prev_scissor[1], -- prev_scissor[2], prev_scissor[3]); -+ if(gamma_ramp){ -+ for (i = 0; i < ARRAY_SIZE(draw_state_handlers); i++) -+ draw_state_handlers[i].state_handler(RESET, gl, ctx, &state, NULL, NULL, NULL); - } - -- pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, prev_draw_fbo ); -- pglBindFramebuffer( GL_READ_FRAMEBUFFER, prev_read_fbo ); -+ for (i = 0; i < ARRAY_SIZE(general_state_handlers); i++) -+ general_state_handlers[i].state_handler(RESET, gl, ctx, &state, NULL, NULL, NULL); - } - - static void wglFinish(void) -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 55875edc788..3e162382975 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -688,6 +688,8 @@ extern double fs_hack_get_user_to_real_scale(HMONITOR) DECLSPEC_HIDDEN; - extern SIZE fs_hack_get_scaled_screen_size(HMONITOR monitor) DECLSPEC_HIDDEN; - extern RECT fs_hack_get_real_virtual_screen(void) DECLSPEC_HIDDEN; - extern void fs_hack_init(void) DECLSPEC_HIDDEN; -+extern const float *fs_hack_get_gamma_ramp(LONG *serial); -+extern void fs_hack_set_gamma_ramp(const WORD *ramp); - extern int mode_compare(const void *p1, const void *p2) DECLSPEC_HIDDEN; - - static inline void mirror_rect( const RECT *window_rect, RECT *rect ) -diff --git a/dlls/winex11.drv/xvidmode.c b/dlls/winex11.drv/xvidmode.c -index 123e5d036a9..828aeb83d0c 100644 ---- a/dlls/winex11.drv/xvidmode.c -+++ b/dlls/winex11.drv/xvidmode.c -@@ -554,6 +554,25 @@ void X11DRV_XF86VM_Init(void) - - #endif /* SONAME_LIBXXF86VM */ - -+static BOOL CALLBACK gammahack_UpdateWindowGamma(HWND hwnd, LPARAM lparam) -+{ -+ /* XXX: Technically, the ramp should only apply to windows on the given -+ * device, but I can't think of a situation in which that would matter. */ -+ -+ sync_gl_drawable(hwnd, FALSE); -+ -+ return TRUE; -+} -+ -+static BOOL gamma_hack_SetGammaRamp(PHYSDEV dev, const WORD *ramp) -+{ -+ fs_hack_set_gamma_ramp(ramp); -+ -+ EnumWindows(gammahack_UpdateWindowGamma, 0); -+ -+ return TRUE; -+} -+ - /*********************************************************************** - * GetDeviceGammaRamp (X11DRV.@) - * -@@ -580,7 +599,9 @@ BOOL CDECL X11DRV_GetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp) - BOOL CDECL X11DRV_SetDeviceGammaRamp(PHYSDEV dev, LPVOID ramp) - { - #ifdef SONAME_LIBXXF86VM -- return X11DRV_XF86VM_SetGammaRamp(ramp); -+ if(!X11DRV_XF86VM_SetGammaRamp(ramp)) -+ return gamma_hack_SetGammaRamp(dev, ramp); -+ return TRUE; - #else - return FALSE; - #endif -From d342a851179df02705f463d6cac444cbe6607868 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 22 Jun 2021 18:57:49 +0300 -Subject: [PATCH] fshack: Setup gamma shader only once per context. - -Fixes GL objects leak and avoids unneccessary shader recreation -when the fs_hack_setup_context() is called due to switching GL -drawable. - -For Star Wars - Knights of the Old Republic blank screen. - -CW-Bug-Id: #19002 ---- - dlls/winex11.drv/opengl.c | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index fab13d5b1df..db66aabff59 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -2079,6 +2079,11 @@ static void fs_hack_setup_gamma_shader( struct wgl_context *ctx, struct gl_drawa - char errstr[512]; - const float *default_gamma_ramp = fs_hack_get_default_gamma_ramp(); - -+ gl->last_gamma_serial = 0; -+ -+ if (ctx->fs_hack_gamma_pgm) -+ return; -+ - opengl_funcs.gl.p_glGetIntegerv( GL_CURRENT_PROGRAM, (GLint *)&prev_program ); - /* vertex shader */ - vshader = pglCreateShader(GL_VERTEX_SHADER); -@@ -2148,7 +2153,6 @@ static void fs_hack_setup_gamma_shader( struct wgl_context *ctx, struct gl_drawa - pglGenBuffers(1, &ctx->ramp_ubo); - pglBindBuffer(GL_UNIFORM_BUFFER, ctx->ramp_ubo); - pglBufferData(GL_UNIFORM_BUFFER, sizeof(float) * 4 * GAMMA_RAMP_SIZE, default_gamma_ramp, GL_DYNAMIC_DRAW); -- gl->last_gamma_serial = 0; - - ramp_index = pglGetUniformBlockIndex(program, "ramp"); - pglUniformBlockBinding(program, ramp_index, 0); -From b52e6329eb7ff2feec0ef0b4b2bb638abe57e200 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 22 Jun 2021 23:56:20 +0300 -Subject: [PATCH] fshack: Track if multisample resolve is needed in - gl_drawable. - -As that changes per drawable and not per context. ---- - dlls/winex11.drv/opengl.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index db66aabff59..5b4a7456e29 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -263,6 +263,7 @@ struct gl_drawable - BOOL fs_hack; - BOOL fs_hack_did_swapbuf; - BOOL fs_hack_context_set_up; -+ BOOL fs_hack_needs_resolve; - BOOL has_scissor_indexed; - BOOL has_clip_control; - BOOL has_ati_frag_shader; -@@ -2252,11 +2253,13 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - - if (config.samples) - { -+ gl->fs_hack_needs_resolve = TRUE; - if (!ctx->fs_hack_color_renderbuffer) - pglGenRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); - pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); - pglRenderbufferStorageMultisample( GL_RENDERBUFFER, config.samples, - config.color_internalformat, width, height ); -+ - pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); - TRACE( "Created renderbuffer %u and FBO %u for fullscreen hack.\n", ctx->fs_hack_color_renderbuffer, ctx->fs_hack_resolve_fbo ); -@@ -2268,6 +2271,7 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - } - else - { -+ gl->fs_hack_needs_resolve = FALSE; - pglFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, ctx->fs_hack_color_texture, 0 ); - } -@@ -2281,6 +2285,7 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_ds_renderbuffer ); - pglRenderbufferStorageMultisample( GL_RENDERBUFFER, config.samples, - config.ds_internalformat, width, height ); -+ - pglBindRenderbuffer( GL_RENDERBUFFER, prev_renderbuffer ); - if (attribs.depth_size) - pglFramebufferRenderbuffer( GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, -@@ -2866,7 +2871,7 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer - fs_hack_setup_context( ctx, gl ); - - /* Can't stretch blit with multisampled renderbuffers */ -- if (ctx->fs_hack_color_renderbuffer && !gamma_ramp){ -+ if (gl->fs_hack_needs_resolve && !gamma_ramp){ - gamma_ramp = fs_hack_get_default_gamma_ramp(); - gamma_serial = 0; - } -@@ -2883,7 +2888,7 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer - - pglBindFramebuffer( GL_READ_FRAMEBUFFER, ctx->fs_hack_fbo ); - -- if (ctx->fs_hack_color_renderbuffer) -+ if (gl->fs_hack_needs_resolve) - { - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, ctx->fs_hack_resolve_fbo ); - -From d4eb7bd91e076ae6531fe87d83dae2ad07042caa Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 23 Jun 2021 20:26:27 +0300 -Subject: [PATCH] fshack: Destroy fshack GL objects only at GL context destroy. - ---- - dlls/winex11.drv/opengl.c | 59 ++++++++++++++++++++++++++++----------- - 1 file changed, 43 insertions(+), 16 deletions(-) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 5b4a7456e29..ff5c9969aab 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -1899,6 +1899,40 @@ static struct wgl_context * WINAPI glxdrv_wglCreateContext( HDC hdc ) - return ret; - } - -+static void fs_hack_destroy_context( struct wgl_context *ctx ) -+{ -+ GLXContext prev_context; -+ GLXDrawable prev_drawable; -+ -+ if (!ctx->drawables[0]) return; -+ -+ prev_context = pglXGetCurrentContext(); -+ prev_drawable = pglXGetCurrentDrawable(); -+ pglXMakeCurrent(gdi_display, ctx->drawables[0]->drawable, ctx->ctx); -+ -+ pglDeleteBuffers(1, &ctx->ramp_ubo); -+ pglDeleteProgram(ctx->fs_hack_gamma_pgm); -+ ctx->fs_hack_gamma_pgm = 0; -+ -+ if (ctx->fs_hack_ds_renderbuffer) -+ pglDeleteRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); -+ if (ctx->fs_hack_color_renderbuffer) -+ pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); -+ if (ctx->fs_hack_ds_texture) -+ opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_ds_texture ); -+ if (ctx->fs_hack_color_texture) -+ opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_color_texture ); -+ ctx->fs_hack_color_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; -+ ctx->fs_hack_color_texture = ctx->fs_hack_ds_texture = 0; -+ if (ctx->fs_hack_resolve_fbo) -+ pglDeleteFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); -+ if (ctx->fs_hack_fbo) -+ pglDeleteFramebuffers( 1, &ctx->fs_hack_fbo ); -+ ctx->fs_hack_resolve_fbo = ctx->fs_hack_fbo = 0; -+ -+ pglXMakeCurrent(gdi_display, prev_drawable, prev_context); -+} -+ - /*********************************************************************** - * glxdrv_wglDeleteContext - */ -@@ -1908,6 +1942,8 @@ static BOOL WINAPI glxdrv_wglDeleteContext(struct wgl_context *ctx) - - TRACE("(%p)\n", ctx); - -+ fs_hack_destroy_context( ctx ); -+ - EnterCriticalSection( &context_section ); - list_remove( &ctx->entry ); - LIST_FOR_EACH_ENTRY( pb, &pbuffer_list, struct wgl_pbuffer, entry ) -@@ -2227,7 +2263,6 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - if (!ctx->fs_hack_fbo) - { - pglGenFramebuffers( 1, &ctx->fs_hack_fbo ); -- pglGenFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); - TRACE( "Created FBO %u for fullscreen hack.\n", ctx->fs_hack_fbo ); - } - pglBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0); -@@ -2254,6 +2289,13 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - if (config.samples) - { - gl->fs_hack_needs_resolve = TRUE; -+ -+ if (!ctx->fs_hack_resolve_fbo) -+ { -+ pglGenFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); -+ TRACE( "Created resolve FBO %u for fullscreen hack.\n", ctx->fs_hack_resolve_fbo ); -+ } -+ - if (!ctx->fs_hack_color_renderbuffer) - pglGenRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); - pglBindRenderbuffer( GL_RENDERBUFFER, ctx->fs_hack_color_renderbuffer ); -@@ -2356,21 +2398,6 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - pglBindFramebuffer( GL_READ_FRAMEBUFFER, 0 ); - ctx->current_read_fbo = 0; - } -- -- pglDeleteBuffers(1, &ctx->ramp_ubo); -- pglDeleteProgram(ctx->fs_hack_gamma_pgm); -- ctx->fs_hack_gamma_pgm = 0; -- -- pglDeleteRenderbuffers( 1, &ctx->fs_hack_ds_renderbuffer ); -- pglDeleteRenderbuffers( 1, &ctx->fs_hack_color_renderbuffer ); -- opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_ds_texture ); -- opengl_funcs.gl.p_glDeleteTextures( 1, &ctx->fs_hack_color_texture ); -- ctx->fs_hack_color_renderbuffer = ctx->fs_hack_ds_renderbuffer = 0; -- ctx->fs_hack_color_texture = ctx->fs_hack_ds_texture = 0; -- pglDeleteFramebuffers( 1, &ctx->fs_hack_resolve_fbo ); -- pglDeleteFramebuffers( 1, &ctx->fs_hack_fbo ); -- ctx->fs_hack_fbo = 0; -- - gl->fs_hack_context_set_up = FALSE; - } - } -From f4dc9634f2036de04260193c2beca61aa1bf8dd1 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 22 Jun 2021 00:36:17 +0300 -Subject: [PATCH] fshack: Set viewport in fs_hack_setup_context(). - -For Star Wars - Knights of the Old Republic blank screen. - -CW-Bug-Id: #19002 ---- - dlls/winex11.drv/opengl.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index ff5c9969aab..d0089806155 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -2356,6 +2356,9 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - - fs_hack_setup_gamma_shader(ctx, gl); - -+ if (!ctx->has_been_current) -+ opengl_funcs.gl.p_glViewport(0, 0, width, height); -+ - if(!gl->fs_hack_context_set_up) - { - opengl_funcs.gl.p_glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); -@@ -2383,6 +2386,7 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - gl->has_fragment_program = !ctx->is_core && has_extension(glExtensions, "GL_ARB_fragment_program"); - gl->has_vertex_program = !ctx->is_core && has_extension(glExtensions, "GL_ARB_vertex_program"); - ctx->fs_hack_integer = fs_hack_is_integer(); -+ - gl->fs_hack_context_set_up = TRUE; - } - else -From 79f3013b06b7502fa2875aac989335ec0d8576b5 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 22 Jun 2021 19:03:16 +0300 -Subject: [PATCH] fshack: Also enable fshack for drawable due to gamma in - create_gl_drawable(). - -For Star Wars - Knights of the Old Republic blank screen. - -CW-Bug-Id: #19002 ---- - dlls/winex11.drv/opengl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index d0089806155..0a08c0a2261 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -1471,7 +1471,7 @@ static struct gl_drawable *create_gl_drawable( HWND hwnd, const struct wgl_pixel - if (gl->window) - gl->drawable = pglXCreateWindow( gdi_display, gl->format->fbconfig, gl->window, NULL ); - data = get_win_data( hwnd ); -- gl->fs_hack = data->fs_hack; -+ gl->fs_hack = data->fs_hack || fs_hack_get_gamma_ramp(NULL); - if (gl->fs_hack) - TRACE( "Window %p has the fullscreen hack enabled\n", hwnd ); - release_win_data( data ); -From a770d875cd09a714bedcbfeef16062a62a77c169 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 22 Jun 2021 18:54:20 +0300 -Subject: [PATCH] fshack: Use window dimensions in GL if fshack is enabled for - gamma only. - -For Star Wars - Knights of the Old Republic blank screen. - -CW-Bug-Id: #19002 ---- - dlls/winex11.drv/opengl.c | 49 ++++++++++++++++++++++++++++++--------- - 1 file changed, 38 insertions(+), 11 deletions(-) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 0a08c0a2261..175b183dc44 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -2237,14 +2237,27 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - MONITORINFO monitor_info; - HMONITOR monitor; - int width, height; -+ RECT rect = {0}; - GLuint profile; -+ HWND hwnd; - -- monitor = fs_hack_monitor_from_hwnd(WindowFromDC(ctx->hdc)); -- memset(&monitor_info, 0, sizeof(monitor_info)); -- monitor_info.cbSize = sizeof(monitor_info); -- GetMonitorInfoW(monitor, &monitor_info); -- width = monitor_info.rcMonitor.right - monitor_info.rcMonitor.left; -- height = monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top; -+ hwnd = WindowFromDC(ctx->hdc); -+ monitor = fs_hack_monitor_from_hwnd(hwnd); -+ -+ if (fs_hack_enabled(monitor)) -+ { -+ memset(&monitor_info, 0, sizeof(monitor_info)); -+ monitor_info.cbSize = sizeof(monitor_info); -+ GetMonitorInfoW(monitor, &monitor_info); -+ rect = monitor_info.rcMonitor; -+ } -+ else -+ { -+ GetClientRect(hwnd, &rect); -+ } -+ -+ width = rect.right - rect.left; -+ height = rect.bottom - rect.top; - - TRACE("Render buffer width:%d height:%d\n", width, height); - -@@ -2869,18 +2882,32 @@ static void fs_hack_blit_framebuffer( struct gl_drawable *gl, GLenum draw_buffer - }; - struct wgl_context *ctx = NtCurrentTeb()->glContext; - SIZE scaled, src, real; -- RECT user_rect, real_rect; -+ RECT user_rect = {0}, real_rect; - POINT scaled_origin; - HMONITOR monitor; - struct fs_hack_gl_state state; - const float *gamma_ramp; - LONG gamma_serial; - unsigned int i; -+ HWND hwnd; -+ -+ hwnd = WindowFromDC(ctx->hdc); -+ monitor = fs_hack_monitor_from_hwnd(hwnd); -+ -+ if (fs_hack_enabled(monitor)) -+ { -+ user_rect = fs_hack_current_mode(monitor); -+ real_rect = fs_hack_real_mode(monitor); -+ scaled = fs_hack_get_scaled_screen_size(monitor); -+ } -+ else -+ { -+ GetClientRect(hwnd, &user_rect); -+ real_rect = user_rect; -+ scaled.cx = user_rect.right - user_rect.left; -+ scaled.cy = user_rect.bottom - user_rect.top; -+ } - -- monitor = fs_hack_monitor_from_hwnd(WindowFromDC(ctx->hdc)); -- scaled = fs_hack_get_scaled_screen_size(monitor); -- user_rect = fs_hack_current_mode(monitor); -- real_rect = fs_hack_real_mode(monitor); - src.cx = user_rect.right - user_rect.left; - src.cy = user_rect.bottom - user_rect.top; - real.cx = real_rect.right - real_rect.left; -From 2452e8f4855dbd27e2f1a951fad2da7d21ddf711 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 23 Jun 2021 00:01:57 +0300 -Subject: [PATCH] fshack: Use window size for texture and framebuffers in - fs_hack_setup_context(). - -For Star Wars - Knights of the Old Republic blank screen. - -CW-Bug-Id: #19002 ---- - dlls/winex11.drv/opengl.c | 16 +--------------- - 1 file changed, 1 insertion(+), 15 deletions(-) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 175b183dc44..91119e8d393 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -2234,27 +2234,13 @@ static void fs_hack_setup_context( struct wgl_context *ctx, struct gl_drawable * - - if (ctx->fs_hack) - { -- MONITORINFO monitor_info; -- HMONITOR monitor; - int width, height; - RECT rect = {0}; - GLuint profile; - HWND hwnd; - - hwnd = WindowFromDC(ctx->hdc); -- monitor = fs_hack_monitor_from_hwnd(hwnd); -- -- if (fs_hack_enabled(monitor)) -- { -- memset(&monitor_info, 0, sizeof(monitor_info)); -- monitor_info.cbSize = sizeof(monitor_info); -- GetMonitorInfoW(monitor, &monitor_info); -- rect = monitor_info.rcMonitor; -- } -- else -- { -- GetClientRect(hwnd, &rect); -- } -+ GetClientRect(hwnd, &rect); - - width = rect.right - rect.left; - height = rect.bottom - rect.top; -From 3b91dfd727758caf874bbcfaedd8a0f4d4822320 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 23 Feb 2021 11:28:28 +0100 -Subject: [PATCH] HACK: fshack: winex11.drv: Use gdi_display for client_window - requests. - -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/window.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index bbe2a1728b5..e785e0c0563 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -2659,7 +2659,7 @@ BOOL CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag - if(data->whole_window) - XMoveResizeWindow(data->display, data->whole_window, tl.x, tl.y, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top); - if(data->client_window) -- XMoveResizeWindow(data->display, data->client_window, 0, 0, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top); -+ XMoveResizeWindow(gdi_display, data->client_window, 0, 0, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top); - }else if(data->fs_hack && (!fs_hack_enabled(monitor) || - !fs_hack_matches_current_mode(monitor, - window_rect->right - window_rect->left, -@@ -2672,7 +2672,7 @@ BOOL CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag - window_rect->right - window_rect->left, - window_rect->bottom - window_rect->top); - if(data->client_window){ -- XMoveResizeWindow(data->display, data->client_window, -+ XMoveResizeWindow(gdi_display, data->client_window, - data->client_rect.left - data->whole_rect.left, - data->client_rect.top - data->whole_rect.top, - data->client_rect.right - data->client_rect.left, -From 4640b0cc2479c0a78e151bd0459d3ffa160ca73b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 26 Feb 2021 17:34:56 +0100 -Subject: [PATCH] HACK: fshack: winex11.drv: Simply scale offscreen vulkan - surfaces. - -They will be copied manually onto the screen, so we don't need to scale -them to the screen dimensions. - -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/vulkan.c | 34 +++++++++++++++++++++++++++++++++- - 1 file changed, 33 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c -index 6bfbb9dc7bc..1afb62c0b7d 100644 ---- a/dlls/winex11.drv/vulkan.c -+++ b/dlls/winex11.drv/vulkan.c -@@ -854,7 +854,7 @@ static VkBool32 X11DRV_query_fs_hack(VkSurfaceKHR surface, VkExtent2D *real_sz, - } - - monitor = fs_hack_monitor_from_hwnd(hwnd); -- if(fs_hack_enabled(monitor)){ -+ if(fs_hack_enabled(monitor) && !x11_surface->offscreen){ - RECT real_rect = fs_hack_real_mode(monitor); - RECT user_rect = fs_hack_current_mode(monitor); - SIZE scaled = fs_hack_get_scaled_screen_size(monitor); -@@ -886,6 +886,38 @@ static VkBool32 X11DRV_query_fs_hack(VkSurfaceKHR surface, VkExtent2D *real_sz, - dst_blit->extent.height = scaled.cy; - } - -+ if (filter) -+ *filter = fs_hack_is_integer() ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; -+ -+ return VK_TRUE; -+ } -+ else if (fs_hack_enabled(monitor)) -+ { -+ double scale = fs_hack_get_user_to_real_scale( monitor ); -+ RECT client_rect; -+ -+ GetClientRect( hwnd, &client_rect ); -+ -+ if (real_sz) -+ { -+ real_sz->width = (client_rect.right - client_rect.left) * scale; -+ real_sz->height = (client_rect.bottom - client_rect.top) * scale; -+ } -+ -+ if (user_sz) -+ { -+ user_sz->width = client_rect.right - client_rect.left; -+ user_sz->height = client_rect.bottom - client_rect.top; -+ } -+ -+ if (dst_blit) -+ { -+ dst_blit->offset.x = client_rect.left * scale; -+ dst_blit->offset.y = client_rect.top * scale; -+ dst_blit->extent.width = (client_rect.right - client_rect.left) * scale; -+ dst_blit->extent.height = (client_rect.bottom - client_rect.top) * scale; -+ } -+ - if(filter) - *filter = fs_hack_is_integer() ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; - -From 65ee4143317ed95b33ee67a9714b1269de7dc17e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 25 Feb 2021 19:12:10 +0100 -Subject: [PATCH] HACK: fshack: winex11.drv: Resize child window client_windows - too. - -CW-Bug-Id: 16608 ---- - dlls/winex11.drv/display.c | 40 ++++++++++++++++++++++++++++++++++++++ - dlls/winex11.drv/window.c | 2 ++ - dlls/winex11.drv/x11drv.h | 1 + - 3 files changed, 43 insertions(+) - -diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c -index cf638ff43a0..56a0bf35070 100644 ---- a/dlls/winex11.drv/display.c -+++ b/dlls/winex11.drv/display.c -@@ -308,6 +308,44 @@ void X11DRV_DisplayDevices_RegisterEventHandlers(void) - handler->register_event_handlers(); - } - -+BOOL CALLBACK fs_hack_update_child_window_client_surface(HWND hwnd, LPARAM enable_fs_hack) -+{ -+ struct x11drv_win_data *data; -+ RECT client_rect; -+ -+ if (!(data = get_win_data( hwnd ))) -+ return TRUE; -+ -+ if (enable_fs_hack && data->client_window) -+ { -+ client_rect = data->client_rect; -+ ClientToScreen( hwnd, (POINT *)&client_rect.left ); -+ ClientToScreen( hwnd, (POINT *)&client_rect.right ); -+ fs_hack_rect_user_to_real( &client_rect ); -+ -+ FIXME( "Enabling child fshack, resizing window %p to %s.\n", hwnd, wine_dbgstr_rect( &client_rect ) ); -+ XMoveResizeWindow( gdi_display, data->client_window, -+ client_rect.left, client_rect.top, -+ client_rect.right - client_rect.left, -+ client_rect.bottom - client_rect.top ); -+ data->fs_hack = TRUE; -+ } -+ else if (!enable_fs_hack && data->client_window) -+ { -+ FIXME( "Disabling child fshack, restoring window %p.\n", hwnd ); -+ XMoveResizeWindow( gdi_display, data->client_window, -+ data->client_rect.left - data->whole_rect.left, -+ data->client_rect.top - data->whole_rect.top, -+ data->client_rect.right - data->client_rect.left, -+ data->client_rect.bottom - data->client_rect.top ); -+ data->fs_hack = FALSE; -+ } -+ -+ if (data->client_window) sync_gl_drawable( hwnd, TRUE ); -+ release_win_data( data ); -+ return TRUE; -+} -+ - static BOOL CALLBACK update_windows_on_display_change(HWND hwnd, LPARAM lparam) - { - struct x11drv_win_data *data; -@@ -342,6 +380,7 @@ static BOOL CALLBACK update_windows_on_display_change(HWND hwnd, LPARAM lparam) - XMoveResizeWindow(gdi_display, data->client_window, 0, 0, width, height); - sync_gl_drawable(hwnd, FALSE); - update_net_wm_states( data ); -+ EnumChildWindows( hwnd, fs_hack_update_child_window_client_surface, TRUE ); - } - } else { - /* update the full screen state */ -@@ -373,6 +412,7 @@ static BOOL CALLBACK update_windows_on_display_change(HWND hwnd, LPARAM lparam) - data->client_rect.bottom - data->client_rect.top); - } - sync_gl_drawable(hwnd, FALSE); -+ EnumChildWindows( hwnd, fs_hack_update_child_window_client_surface, FALSE ); - } - } - release_win_data(data); -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index e785e0c0563..4cd2324bff2 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -2660,6 +2660,7 @@ BOOL CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag - XMoveResizeWindow(data->display, data->whole_window, tl.x, tl.y, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top); - if(data->client_window) - XMoveResizeWindow(gdi_display, data->client_window, 0, 0, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top); -+ EnumChildWindows( hwnd, fs_hack_update_child_window_client_surface, TRUE ); - }else if(data->fs_hack && (!fs_hack_enabled(monitor) || - !fs_hack_matches_current_mode(monitor, - window_rect->right - window_rect->left, -@@ -2678,6 +2679,7 @@ BOOL CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag - data->client_rect.right - data->client_rect.left, - data->client_rect.bottom - data->client_rect.top); - } -+ EnumChildWindows( hwnd, fs_hack_update_child_window_client_surface, FALSE ); - } - - /* check if we need to switch the window to managed */ -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 3e162382975..4e7d602ee73 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -691,6 +691,7 @@ extern void fs_hack_init(void) DECLSPEC_HIDDEN; - extern const float *fs_hack_get_gamma_ramp(LONG *serial); - extern void fs_hack_set_gamma_ramp(const WORD *ramp); - extern int mode_compare(const void *p1, const void *p2) DECLSPEC_HIDDEN; -+BOOL CALLBACK fs_hack_update_child_window_client_surface(HWND hwnd, LPARAM enable_fs_hack) DECLSPEC_HIDDEN; - - static inline void mirror_rect( const RECT *window_rect, RECT *rect ) - { -From b7eccbd7f418ad20822b5113277963e001368640 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 17 May 2021 10:54:27 +0200 -Subject: [PATCH] HACK: fshack: winex11.drv: Transform X11DRV_FLUSH_VK_DRAWABLE - rects. - -CW-Bug-Id: #16608 ---- - dlls/winex11.drv/init.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c -index 8f152eedc69..095a3778089 100644 ---- a/dlls/winex11.drv/init.c -+++ b/dlls/winex11.drv/init.c -@@ -227,13 +227,15 @@ static INT CDECL X11DRV_ExtEscape( PHYSDEV dev, INT escape, INT in_count, LPCVOI - { - const struct x11drv_escape_present_drawable *data = in_data; - RECT rect = physDev->dc_rect; -+ RECT real_rect = physDev->dc_rect; - -+ fs_hack_rect_user_to_real( &real_rect ); - OffsetRect( &rect, -physDev->dc_rect.left, -physDev->dc_rect.top ); - if (data->flush) XFlush( gdi_display ); - XSetFunction( gdi_display, physDev->gc, GXcopy ); - XCopyArea( gdi_display, data->drawable, physDev->drawable, physDev->gc, -- 0, 0, rect.right, rect.bottom, -- physDev->dc_rect.left, physDev->dc_rect.top ); -+ 0, 0, real_rect.right - real_rect.left, real_rect.bottom - real_rect.top, -+ real_rect.left, real_rect.top ); - add_device_bounds( physDev, &rect ); - return TRUE; - } -From 9e86e5142b754c7265fb505ea1208e3b2d34a23e Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Sat, 11 Dec 2021 12:38:26 +0100 -Subject: [PATCH] HACK: winevulkan: Add vkGetPhysicalDeviceProperties thunks to - fake NVIDIA PCI IDs as AMD - -Needed for RDR2 with NVIDIA cards, otherwise game crashes or gets stuck -trying to load nvapi64.dll ---- - dlls/winevulkan/loader.c | 48 +++++++++++++++++++++++++++++++++ - dlls/winevulkan/make_vulkan | 1 + - dlls/winevulkan/vulkan_loader.h | 3 +++ - 3 files changed, 52 insertions(+) - -diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c -index 0b2c4241f75..d3ac9f57763 100644 ---- a/dlls/winevulkan/loader.c -+++ b/dlls/winevulkan/loader.c -@@ -368,6 +368,30 @@ static void fill_luid_property(VkPhysicalDeviceProperties2 *properties2) - id->deviceNodeMask); - } - -+void WINAPI vkGetPhysicalDeviceProperties(VkPhysicalDevice physical_device, -+ VkPhysicalDeviceProperties *properties) -+{ -+ struct vkGetPhysicalDeviceProperties_params params; -+ -+ TRACE("%p, %p\n", physical_device, properties); -+ -+ params.physicalDevice = physical_device; -+ params.pProperties = properties; -+ vk_unix_call(unix_vkGetPhysicalDeviceProperties, ¶ms); -+ -+ { -+ const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); -+ if (sgi && *sgi != '0') -+ { -+ if (properties->vendorID == 0x10de /* NVIDIA */) -+ { -+ properties->vendorID = 0x1002; /* AMD */ -+ properties->deviceID = 0x67df; /* RX 480 */ -+ } -+ } -+ } -+} -+ - void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev, - VkPhysicalDeviceProperties2 *properties2) - { -@@ -379,6 +403,18 @@ void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev, - params.pProperties = properties2; - vk_unix_call(unix_vkGetPhysicalDeviceProperties2, ¶ms); - fill_luid_property(properties2); -+ -+ { -+ const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); -+ if (sgi && *sgi != '0') -+ { -+ if (properties2->properties.vendorID == 0x10de /* NVIDIA */) -+ { -+ properties2->properties.vendorID = 0x1002; /* AMD */ -+ properties2->properties.deviceID = 0x67df; /* RX 480 */ -+ } -+ } -+ } - } - - void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev, -@@ -392,6 +428,18 @@ void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev, - params.pProperties = properties2; - vk_unix_call(unix_vkGetPhysicalDeviceProperties2KHR, ¶ms); - fill_luid_property(properties2); -+ -+ { -+ const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); -+ if (sgi && *sgi != '0') -+ { -+ if (properties2->properties.vendorID == 0x10de /* NVIDIA */) -+ { -+ properties2->properties.vendorID = 0x1002; /* AMD */ -+ properties2->properties.deviceID = 0x67df; /* RX 480 */ -+ } -+ } -+ } - } - - static BOOL WINAPI call_vulkan_debug_report_callback( struct wine_vk_debug_report_params *params, ULONG size ) -diff --git a/dlls/winevulkan/vulkan_loader.h b/dlls/winevulkan/vulkan_loader.h -index 05913756fbc..275242657e3 100644 ---- a/dlls/winevulkan/vulkan_loader.h -+++ b/dlls/winevulkan/vulkan_loader.h -@@ -20,6 +20,9 @@ - #ifndef __WINE_VULKAN_LOADER_H - #define __WINE_VULKAN_LOADER_H - -+#include -+#include -+ - #include "ntstatus.h" - #define WIN32_NO_STATUS - #include -From b3f1bd23771192f136ed9b4f93a1f4b6087611a0 Mon Sep 17 00:00:00 2001 -From: Thomas Crider -Date: Sat, 19 Feb 2022 01:55:40 -0700 -Subject: [PATCH] revert 656edbb and 587f377 to retain fshack compat patch - compatibility - ---- - dlls/win32u/sysparams.c | 14 ++--- - dlls/winex11.drv/Makefile.in | 2 +- - dlls/winex11.drv/display.c | 109 ++++++++++++++++++++++++++++++++++- - include/ntuser.h | 2 - - 4 files changed, 111 insertions(+), 16 deletions(-) - -diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c -index 58bd22a3adf..7af1e20f008 100644 ---- a/dlls/win32u/sysparams.c -+++ b/dlls/win32u/sysparams.c -@@ -1474,7 +1474,7 @@ RECT get_display_rect( const WCHAR *display ) - return map_dpi_rect( rect, system_dpi, get_thread_dpi() ); - } - --static RECT get_primary_monitor_rect( UINT dpi ) -+static RECT get_primary_monitor_rect(void) - { - struct monitor *monitor; - RECT rect = {0}; -@@ -1489,7 +1489,7 @@ static RECT get_primary_monitor_rect( UINT dpi ) - } - - unlock_display_devices(); -- return map_dpi_rect( rect, system_dpi, dpi ); -+ return map_dpi_rect( rect, system_dpi, get_thread_dpi() ); - } - - /********************************************************************** -@@ -4203,10 +4203,10 @@ int get_system_metrics( int index ) - case SM_MOUSEWHEELPRESENT: - return 1; - case SM_CXSCREEN: -- rect = get_primary_monitor_rect( get_thread_dpi() ); -+ rect = get_primary_monitor_rect(); - return rect.right - rect.left; - case SM_CYSCREEN: -- rect = get_primary_monitor_rect( get_thread_dpi() ); -+ rect = get_primary_monitor_rect(); - return rect.bottom - rect.top; - case SM_XVIRTUALSCREEN: - rect = get_virtual_screen_rect( get_thread_dpi() ); -@@ -4528,18 +4528,12 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) - return get_sys_color( arg ); - case NtUserRealizePalette: - return realize_palette( UlongToHandle(arg) ); -- case NtUserGetPrimaryMonitorRect: -- *(RECT *)arg = get_primary_monitor_rect( 0 ); -- return 1; - case NtUserGetSysColorBrush: - return HandleToUlong( get_sys_color_brush(arg) ); - case NtUserGetSysColorPen: - return HandleToUlong( get_sys_color_pen(arg) ); - case NtUserGetSystemMetrics: - return get_system_metrics( arg ); -- case NtUserGetVirtualScreenRect: -- *(RECT *)arg = get_virtual_screen_rect( 0 ); -- return 1; - case NtUserMessageBeep: - return message_beep( arg ); - /* temporary exports */ -diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in -index 93a975d7f63..64df2075cc4 100644 ---- a/dlls/winex11.drv/Makefile.in -+++ b/dlls/winex11.drv/Makefile.in -@@ -1,6 +1,6 @@ - EXTRADEFS = -DWINE_NO_LONG_TYPES - MODULE = winex11.drv --IMPORTS = uuid user32 gdi32 advapi32 win32u -+IMPORTS = uuid setupapi rpcrt4 user32 gdi32 advapi32 win32u - DELAYIMPORTS = comctl32 ole32 shell32 imm32 - EXTRAINCL = $(X_CFLAGS) - EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS) -diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c -index ab5dcdac23f..04380ff660f 100644 ---- a/dlls/winex11.drv/display.c -+++ b/dlls/winex11.drv/display.c -@@ -19,14 +19,53 @@ - */ - - #include "config.h" --#include "x11drv.h" -+ -+#include -+ -+#include "windef.h" -+#include "winbase.h" -+#include "rpc.h" -+#include "winreg.h" -+#include "cfgmgr32.h" -+#include "initguid.h" -+#include "devguid.h" -+#include "devpkey.h" -+#include "ntddvdeo.h" -+#include "setupapi.h" -+#define WIN32_NO_STATUS -+#include "winternl.h" - #include "wine/debug.h" -+#include "wine/unicode.h" -+#include "x11drv.h" - - WINE_DEFAULT_DEBUG_CHANNEL(x11drv); - -+/* Wine specific properties */ -+DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_MONITOR_RCMONITOR, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 3); -+ -+static const WCHAR displayW[] = {'D','I','S','P','L','A','Y',0}; -+static const WCHAR video_keyW[] = { -+ 'H','A','R','D','W','A','R','E','\\', -+ 'D','E','V','I','C','E','M','A','P','\\', -+ 'V','I','D','E','O',0}; -+ - static struct x11drv_display_device_handler host_handler; - struct x11drv_display_device_handler desktop_handler; - -+/* Cached screen information, protected by screen_section */ -+static HKEY video_key; -+static RECT virtual_screen_rect; -+static RECT primary_monitor_rect; -+static FILETIME last_query_screen_time; -+static CRITICAL_SECTION screen_section; -+static CRITICAL_SECTION_DEBUG screen_critsect_debug = -+{ -+ 0, 0, &screen_section, -+ {&screen_critsect_debug.ProcessLocksList, &screen_critsect_debug.ProcessLocksList}, -+ 0, 0, {(DWORD_PTR)(__FILE__ ": screen_section")} -+}; -+static CRITICAL_SECTION screen_section = {&screen_critsect_debug, -1, 0, 0, 0, 0}; -+ - HANDLE get_display_device_init_mutex(void) - { - static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0}; -@@ -42,6 +81,62 @@ void release_display_device_init_mutex(HANDLE mutex) - CloseHandle(mutex); - } - -+/* Update screen rectangle cache from SetupAPI if it's outdated, return FALSE on failure and TRUE on success */ -+static BOOL update_screen_cache(void) -+{ -+ RECT virtual_rect = {0}, primary_rect = {0}, monitor_rect; -+ SP_DEVINFO_DATA device_data = {sizeof(device_data)}; -+ HDEVINFO devinfo = INVALID_HANDLE_VALUE; -+ FILETIME filetime = {0}; -+ HANDLE mutex = NULL; -+ DWORD i = 0; -+ INT result; -+ DWORD type; -+ BOOL ret = FALSE; -+ -+ EnterCriticalSection(&screen_section); -+ if ((!video_key && RegOpenKeyW(HKEY_LOCAL_MACHINE, video_keyW, &video_key)) -+ || RegQueryInfoKeyW(video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime)) -+ { -+ LeaveCriticalSection(&screen_section); -+ return FALSE; -+ } -+ result = CompareFileTime(&filetime, &last_query_screen_time); -+ LeaveCriticalSection(&screen_section); -+ if (result < 1) -+ return TRUE; -+ -+ mutex = get_display_device_init_mutex(); -+ -+ devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, displayW, NULL, DIGCF_PRESENT); -+ if (devinfo == INVALID_HANDLE_VALUE) -+ goto fail; -+ -+ while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data)) -+ { -+ if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type, -+ (BYTE *)&monitor_rect, sizeof(monitor_rect), NULL, 0)) -+ goto fail; -+ -+ UnionRect(&virtual_rect, &virtual_rect, &monitor_rect); -+ if (i == 1) -+ primary_rect = monitor_rect; -+ } -+ -+ EnterCriticalSection(&screen_section); -+ virtual_screen_rect = virtual_rect; -+ primary_monitor_rect = primary_rect; -+ last_query_screen_time = filetime; -+ LeaveCriticalSection(&screen_section); -+ ret = TRUE; -+fail: -+ SetupDiDestroyDeviceInfoList(devinfo); -+ release_display_device_init_mutex(mutex); -+ if (!ret) -+ WARN("Update screen cache failed!\n"); -+ return ret; -+} -+ - POINT virtual_screen_to_root(INT x, INT y) - { - RECT virtual = get_virtual_screen_rect(); -@@ -65,14 +160,22 @@ POINT root_to_virtual_screen(INT x, INT y) - RECT get_virtual_screen_rect(void) - { - RECT virtual; -- NtUserCallOneParam( (UINT_PTR)&virtual, NtUserGetVirtualScreenRect ); -+ -+ update_screen_cache(); -+ EnterCriticalSection(&screen_section); -+ virtual = virtual_screen_rect; -+ LeaveCriticalSection(&screen_section); - return virtual; - } - - RECT get_primary_monitor_rect(void) - { - RECT primary; -- NtUserCallOneParam( (UINT_PTR)&primary, NtUserGetPrimaryMonitorRect ); -+ -+ update_screen_cache(); -+ EnterCriticalSection(&screen_section); -+ primary = primary_monitor_rect; -+ LeaveCriticalSection(&screen_section); - return primary; - } - -diff --git a/include/ntuser.h b/include/ntuser.h -index b7e2e63dcb3..51f1c624ba6 100644 ---- a/include/ntuser.h -+++ b/include/ntuser.h -@@ -75,12 +75,10 @@ enum - NtUserGetClipCursor, - NtUserGetCursorPos, - NtUserGetIconParam, -- NtUserGetPrimaryMonitorRect, - NtUserGetSysColor, - NtUserGetSysColorBrush, - NtUserGetSysColorPen, - NtUserGetSystemMetrics, -- NtUserGetVirtualScreenRect, - NtUserMessageBeep, - NtUserRealizePalette, - /* temporary exports */ --- -2.34.1 - -From 398e397881820bff2add3dd68f1bbc4207294318 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Wed, 15 Jul 2020 11:25:13 -0700 -Subject: [PATCH] HACK: winex11: Support faking AMD PCI IDs for NVIDIA cards - ---- - dlls/winex11.drv/display.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c -index 56a0bf35070..b3ed448c43f 100644 ---- a/dlls/winex11.drv/display.c -+++ b/dlls/winex11.drv/display.c -@@ -21,6 +21,7 @@ - #include "config.h" - - #include -+#include - - #include "windef.h" - #include "winbase.h" -@@ -474,6 +475,18 @@ void CDECL X11DRV_UpdateDisplayDevices( const struct gdi_device_manager *device_ - - for (gpu = 0; gpu < gpu_count; gpu++) - { -+ { -+ const char *sgi = getenv("WINE_HIDE_NVIDIA_GPU"); -+ if (sgi && *sgi != '0') -+ { -+ if (gpus[gpu].vendor_id == 0x10de /* NVIDIA */) -+ { -+ gpus[gpu].vendor_id = 0x1002; /* AMD */ -+ gpus[gpu].device_id = 0x67df; /* RX 480 */ -+ } -+ } -+ } -+ - device_manager->add_gpu( &gpus[gpu], param ); - - /* Initialize adapters */ -diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan -index f584330dc6e..3efdcb4c88c 100755 ---- a/dlls/winevulkan/make_vulkan -+++ b/dlls/winevulkan/make_vulkan -@@ -169,6 +169,7 @@ FUNCTION_OVERRIDES = { - "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, - "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : ThunkType.NONE}, - "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PRIVATE}, -+ "vkGetPhysicalDeviceProperties" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE}, - "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE}, - "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : ThunkType.PUBLIC, "loader_thunk" : ThunkType.PRIVATE}, - diff --git a/patches/proton/fshack/05-steam-overlay-fixes.patch b/patches/proton/fshack/05-steam-overlay-fixes.patch deleted file mode 100644 index 3f169f981..000000000 --- a/patches/proton/fshack/05-steam-overlay-fixes.patch +++ /dev/null @@ -1,483 +0,0 @@ -From 4a40cbd45d370563da0717f965ea19f8016c401f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 11 Oct 2021 10:48:49 +0200 -Subject: [PATCH] HACK: steam: xinput1_3: Check Steam overlay presence and - disconnect controllers when enabled. - ---- - dlls/xinput1_3/main.c | 12 +++++++++--- - 1 file changed, 9 insertions(+), 3 deletions(-) - -diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c -index 506802d142a..cd273c5dd16 100644 ---- a/dlls/xinput1_3/main.c -+++ b/dlls/xinput1_3/main.c -@@ -124,6 +124,7 @@ static HANDLE start_event; - static HANDLE stop_event; - static HANDLE done_event; - static HANDLE update_event; -+static HANDLE steam_overlay_event; - - static BOOL find_opened_device(SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *free_slot) - { -@@ -528,6 +529,7 @@ static void stop_update_thread(void) - CloseHandle(stop_event); - CloseHandle(done_event); - CloseHandle(update_event); -+ CloseHandle(steam_overlay_event); - - for (i = 0; i < XUSER_MAX_COUNT; i++) controller_destroy(&controllers[i], FALSE); - } -@@ -717,6 +719,8 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void - { - HANDLE thread; - -+ steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); -+ - start_event = CreateEventA(NULL, FALSE, FALSE, NULL); - if (!start_event) ERR("failed to create start event, error %u\n", GetLastError()); - -@@ -811,7 +815,8 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION *vib - if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; - if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - -- ret = HID_set_state(&controllers[index], vibration); -+ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) ret = ERROR_SUCCESS; -+ else ret = HID_set_state(&controllers[index], vibration); - - controller_unlock(&controllers[index]); - -@@ -829,7 +834,9 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) - if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; - if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - -- *state = controllers[index].state; -+ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) memset(state, 0, sizeof(*state)); -+ else *state = controllers[index].state; -+ - controller_unlock(&controllers[index]); - - return ERROR_SUCCESS; -@@ -1075,7 +1082,6 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilities(DWORD index, DWORD flags, X - start_update_thread(); - - if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; -- - if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - - if (flags & XINPUT_FLAG_GAMEPAD && controllers[index].caps.SubType != XINPUT_DEVSUBTYPE_GAMEPAD) -From 34007908d03fc78d14087772f32c4a5a4be217ba Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Sat, 9 Jan 2021 20:11:52 +0100 -Subject: [PATCH] HACK: steam: dinput: Check Steam overlay presence and clear - device state when enabled. - -CW-Bug-Id: #20083 ---- - dlls/dinput/dinput_main.c | 4 ++++ - dlls/dinput/dinput_private.h | 1 + - dlls/dinput/joystick_hid.c | 19 +++++++++++++++++++ - 3 files changed, 24 insertions(+) - -diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c -index 8347e3aa586..d1cd10fa04d 100644 ---- a/dlls/dinput/dinput_main.c -+++ b/dlls/dinput/dinput_main.c -@@ -1424,6 +1424,8 @@ void check_dinput_events(void) - MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0); - } - -+HANDLE steam_overlay_event; -+ - BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) - { - TRACE( "inst %p, reason %lu, reserved %p.\n", inst, reason, reserved ); -@@ -1432,6 +1434,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(inst); -+ steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); - DINPUT_instance = inst; - register_di_em_win_class(); - break; -@@ -1476,6 +1479,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) - dinput_thread_stop(); - unregister_di_em_win_class(); - DeleteCriticalSection(&dinput_hook_crit); -+ CloseHandle(steam_overlay_event); - break; - } - return TRUE; -diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h -index 4b36a69c0e1..37d4a4a060a 100644 ---- a/dlls/dinput/dinput_private.h -+++ b/dlls/dinput/dinput_private.h -@@ -48,6 +48,7 @@ struct IDirectInputImpl - - extern const IDirectInput7AVtbl dinput7_a_vtbl DECLSPEC_HIDDEN; - extern const IDirectInput8AVtbl dinput8_a_vtbl DECLSPEC_HIDDEN; -+extern HANDLE steam_overlay_event DECLSPEC_HIDDEN; - - extern HRESULT mouse_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version ); - extern HRESULT mouse_create_device( IDirectInputImpl *dinput, const GUID *guid, IDirectInputDevice8W **out ); -diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c -index 29d1de8b98e..1c17b786fb5 100644 ---- a/dlls/dinput/joystick_hid.c -+++ b/dlls/dinput/joystick_hid.c -@@ -1092,6 +1092,7 @@ struct parse_device_state_params - { - BYTE old_state[DEVICE_STATE_MAX_SIZE]; - BYTE buttons[128]; -+ BOOL reset_state; - DWORD time; - DWORD seq; - }; -@@ -1107,6 +1108,9 @@ static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_val - - value = params->buttons[instance->wUsage - 1]; - old_value = params->old_state[instance->dwOfs]; -+ -+ if (params->reset_state) value = 0; -+ - impl->base.device_state[instance->dwOfs] = value; - if (old_value != value) - queue_event( iface, instance->dwType, value, params->time, params->seq ); -@@ -1189,6 +1193,16 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value - if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, properties ); - else value = scale_value( logical_value, properties ); - -+ if (params->reset_state) -+ { -+ if (instance->dwType & DIDFT_POV) value = -1; -+ else if (instance->dwType & DIDFT_AXIS) -+ { -+ if (!properties->range_min) value = properties->range_max / 2; -+ else value = round( (properties->range_min + properties->range_max) / 2.0 ); -+ } -+ } -+ - old_value = *(LONG *)(params->old_state + instance->dwOfs); - *(LONG *)(impl->base.device_state + instance->dwOfs) = value; - if (old_value != value) -@@ -1233,6 +1247,11 @@ static HRESULT hid_joystick_read( IDirectInputDevice8W *iface ) - } - } - -+ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) /* steam overlay is enabled */ -+ params.reset_state = TRUE; -+ else -+ params.reset_state = FALSE; -+ - EnterCriticalSection( &impl->base.crit ); - while (ret) - { -From 2ba5b9422b88f672f88edd10a8554a72d0fbfddb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 17 Dec 2020 18:47:44 +0100 -Subject: [PATCH] HACK: steam: winex11.drv: Check Steam overlay presence and - drop events when enabled. - ---- - dlls/winex11.drv/event.c | 7 ++++++- - dlls/winex11.drv/x11drv.h | 1 + - dlls/winex11.drv/x11drv_main.c | 5 +++++ - 3 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index d22d34ea1c7..5cb08de99eb 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -447,13 +447,18 @@ static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,X - { - XEvent event, prev_event; - int count = 0; -- BOOL queued = FALSE; -+ BOOL queued = FALSE, overlay_enabled = FALSE; - enum event_merge_action action = MERGE_DISCARD; -+ ULONG_PTR overlay_filter = QS_KEY | QS_MOUSEBUTTON | QS_MOUSEMOVE; -+ -+ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) -+ overlay_enabled = TRUE; - - prev_event.type = 0; - while (XCheckIfEvent( display, &event, filter, (char *)arg )) - { - count++; -+ if (overlay_enabled && filter_event( display, &event, (char *)overlay_filter )) continue; - if (XFilterEvent( &event, None )) - { - /* -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 4e7d602ee73..fb4546e302c 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -449,6 +449,7 @@ extern int xfixes_event_base DECLSPEC_HIDDEN; - extern HMODULE x11drv_module DECLSPEC_HIDDEN; - extern char *process_name DECLSPEC_HIDDEN; - extern Display *clipboard_display DECLSPEC_HIDDEN; -+extern HANDLE steam_overlay_event DECLSPEC_HIDDEN; - - /* atoms */ - -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index c9ca46364cd..4e49de12138 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -89,6 +89,7 @@ int xrender_error_base = 0; - int xfixes_event_base = 0; - HMODULE x11drv_module = 0; - char *process_name = NULL; -+HANDLE steam_overlay_event; - - static x11drv_error_callback err_callback; /* current callback for error */ - static Display *err_callback_display; /* display callback is set for */ -@@ -819,6 +820,10 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) - DisableThreadLibraryCalls( hinst ); - x11drv_module = hinst; - ret = process_attach(); -+ steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); -+ break; -+ case DLL_PROCESS_DETACH: -+ CloseHandle(steam_overlay_event); - break; - } - return ret; -From 714c65ccd3985c25b8f24bfbe8f34d5dba7305fd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 1 Feb 2021 15:34:05 +0100 -Subject: [PATCH] winex11.drv: Don't allow querying pointer while overlay is - active. - ---- - dlls/winex11.drv/mouse.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index cb4363ae02e..0e13ce0e773 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -1553,6 +1553,8 @@ BOOL CDECL X11DRV_GetCursorPos(LPPOINT pos) - unsigned int xstate; - BOOL ret; - -+ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) return FALSE; -+ - ret = XQueryPointer( display, root_window, &root, &child, &rootX, &rootY, &winX, &winY, &xstate ); - if (ret) - { - -From c5a21ea2930f5e391b62c492bdf3f2fd075f310d Mon Sep 17 00:00:00 2001 -From: Giovanni Mascellani -Date: Tue, 27 Apr 2021 10:51:12 +0200 -Subject: [PATCH] HACK: winex11.drv: Fix drawing of layered windows with a - client window. - -CW-Bug-Id: #18807 ---- - dlls/winex11.drv/event.c | 5 ++++- - dlls/winex11.drv/x11drv.h | 2 ++ - dlls/winex11.drv/x11drv_main.c | 12 ++++++++++++ - 3 files changed, 18 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 5cb08de99eb..b0ef922ca5d 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -992,7 +992,10 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev ) - rect.right = pos.x + event->width; - rect.bottom = pos.y + event->height; - -- if (event->window != data->client_window) -+ if (layered_window_client_hack && event->window == data->client_window) -+ OffsetRect( &rect, data->client_rect.left - data->whole_rect.left, -+ data->client_rect.top - data->whole_rect.top ); -+ if (layered_window_client_hack || event->window != data->client_window) - { - if (data->surface) - { -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index fb4546e302c..ed4abd802c1 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -890,4 +890,6 @@ static inline BOOL is_window_rect_mapped( const RECT *rect ) - max( rect->bottom, rect->top + 1 ) > virtual_rect.top); - } - -+extern BOOL layered_window_client_hack; -+ - #endif /* __WINE_X11DRV_H */ -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 4e49de12138..a03eb52ad46 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -90,6 +90,7 @@ int xfixes_event_base = 0; - HMODULE x11drv_module = 0; - char *process_name = NULL; - HANDLE steam_overlay_event; -+BOOL layered_window_client_hack = FALSE; - - static x11drv_error_callback err_callback; /* current callback for error */ - static Display *err_callback_display; /* display callback is set for */ -@@ -713,6 +714,17 @@ static BOOL process_attach(void) - - fs_hack_init(); - -+ { -+ const char *sgi = getenv("SteamGameId"); -+ const char *e = getenv("WINE_LAYERED_WINDOW_CLIENT_HACK"); -+ layered_window_client_hack = -+ (sgi && ( -+ strcmp(sgi, "435150") == 0 || /* Divinity: Original Sin 2 launcher */ -+ strcmp(sgi, "227020") == 0 /* Rise of Venice launcher */ -+ )) || -+ (e && *e != '\0' && *e != '0'); -+ } -+ - init_user_driver(); - X11DRV_DisplayDevices_Init(FALSE); - return TRUE; -From c5aa20a70a5e681ba718feb7db9adc357cb7bec0 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Tue, 31 Aug 2021 00:41:15 +0300 -Subject: [PATCH] winex11.drv: HACK: Mind insert_after X11DRV_WindowPosChanged - in some cases. - -Fixes FH4 rendering black window until focus is lost. - -CW-Bug-Id: #19335 ---- - dlls/winex11.drv/window.c | 51 ++++++++++++++++++++++++++++++++++----- - 1 file changed, 45 insertions(+), 6 deletions(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 4cd2324bff2..815a6279e59 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1481,17 +1481,18 @@ void X11DRV_X_to_window_rect( struct x11drv_win_data *data, RECT *rect, int x, i - * - * Synchronize the X window position with the Windows one - */ --static void sync_window_position( struct x11drv_win_data *data, -+static HWND sync_window_position( struct x11drv_win_data *data, - UINT swp_flags, const RECT *old_window_rect, - const RECT *old_whole_rect, const RECT *old_client_rect ) - { - DWORD style = GetWindowLongW( data->hwnd, GWL_STYLE ); - DWORD ex_style = GetWindowLongW( data->hwnd, GWL_EXSTYLE ); -+ HWND prev_window = NULL; - RECT original_rect = {0}; - XWindowChanges changes; - unsigned int mask = 0; - -- if (data->managed && data->iconic) return; -+ if (data->managed && data->iconic) return NULL; - - /* resizing a managed maximized window is not allowed */ - if (!(style & WS_MAXIMIZE) || !data->managed) -@@ -1529,9 +1530,10 @@ static void sync_window_position( struct x11drv_win_data *data, - { - /* find window that this one must be after */ - HWND prev = GetWindow( data->hwnd, GW_HWNDPREV ); -+ - while (prev && !(GetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE)) - prev = GetWindow( prev, GW_HWNDPREV ); -- if (!prev) /* top child */ -+ if (!(prev_window = prev)) /* top child */ - { - changes.stack_mode = Above; - mask |= CWStackMode; -@@ -1552,6 +1554,7 @@ static void sync_window_position( struct x11drv_win_data *data, - update_net_wm_states( data ); - data->configure_serial = NextRequest( data->display ); - XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); -+ - if (!IsRectEmpty( &original_rect )) - { - data->whole_rect = original_rect; -@@ -1577,6 +1580,8 @@ static void sync_window_position( struct x11drv_win_data *data, - data->whole_rect.right - data->whole_rect.left, - data->whole_rect.bottom - data->whole_rect.top, - changes.sibling, mask, data->configure_serial ); -+ -+ return prev_window; - } - - -@@ -2733,6 +2738,25 @@ BOOL CDECL X11DRV_WindowPosChanging( HWND hwnd, HWND insert_after, UINT swp_flag - } - - -+static void restack_windows( struct x11drv_win_data *data, HWND prev ) -+{ -+ struct x11drv_win_data *prev_data; -+ -+ TRACE("data->hwnd %p, prev %p.\n", data->hwnd, prev); -+ -+ while (prev) -+ { -+ if (!(prev_data = get_win_data( prev ))) break; -+ -+ TRACE( "Raising window %p.\n", prev ); -+ -+ if (prev_data->whole_window && data->display == prev_data->display) -+ XRaiseWindow( prev_data->display, prev_data->whole_window ); -+ release_win_data( prev_data ); -+ prev = GetWindow( prev, GW_HWNDPREV ); -+ } -+} -+ - /*********************************************************************** - * WindowPosChanged (X11DRV.@) - */ -@@ -2745,6 +2769,7 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags - struct x11drv_win_data *data; - DWORD new_style = GetWindowLongW( hwnd, GWL_STYLE ); - RECT old_window_rect, old_whole_rect, old_client_rect; -+ HWND prev_window = NULL; - int event_type; - - if (!(data = get_win_data( hwnd ))) return; -@@ -2847,8 +2872,8 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags - - /* don't change position if we are about to minimize or maximize a managed window */ - if ((!event_type || event_type == PropertyNotify) && -- !(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) -- sync_window_position( data, swp_flags, &old_window_rect, &old_whole_rect, &old_client_rect ); -+ !(data->managed && (swp_flags & SWP_STATECHANGED) && (new_style & (WS_MINIMIZE|WS_MAXIMIZE)))) -+ prev_window = sync_window_position( data, swp_flags, &old_window_rect, &old_whole_rect, &old_client_rect ); - - if ((new_style & WS_VISIBLE) && - ((new_style & WS_MINIMIZE) || is_window_rect_mapped( rectWindow ))) -@@ -2864,6 +2889,10 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags - release_win_data( data ); - if (needs_icon) fetch_icon_data( hwnd, 0, 0 ); - if (needs_map) map_window( hwnd, new_style ); -+ -+ if (!(data = get_win_data( hwnd ))) return; -+ restack_windows( data, prev_window ); -+ release_win_data( data ); - return; - } - else if ((swp_flags & SWP_STATECHANGED) && (!data->iconic != !(new_style & WS_MINIMIZE))) -@@ -2880,10 +2909,20 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags - else - { - if (swp_flags & (SWP_FRAMECHANGED|SWP_STATECHANGED)) set_wm_hints( data ); -- if (!event_type || event_type == PropertyNotify) update_net_wm_states( data ); -+ if (!event_type || event_type == PropertyNotify) -+ { -+ update_net_wm_states( data ); -+ if (!prev_window && insert_after && data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) -+ { -+ prev_window = GetWindow( hwnd, GW_HWNDPREV ); -+ if (prev_window != insert_after) prev_window = NULL; -+ } -+ } - } - } - -+ restack_windows( data, prev_window ); -+ - XFlush( data->display ); /* make sure changes are done before we start painting again */ - if (data->surface && data->vis.visualid != default_visual.visualid) - data->surface->funcs->flush( data->surface ); diff --git a/patches/proton/fshack/06-post-fshack-tweaks.patch b/patches/proton/fshack/06-post-fshack-tweaks.patch deleted file mode 100644 index d674b346e..000000000 --- a/patches/proton/fshack/06-post-fshack-tweaks.patch +++ /dev/null @@ -1,743 +0,0 @@ -From ae84583fc7b97f3cc1d582fb3a91aea31492f637 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 19 Jan 2022 18:19:55 +0300 -Subject: [PATCH] winevulkan: HACK: Report Windows driver version for AMD VAN - GOGH. - -CW-Bug-Id: #20009 ---- - dlls/winevulkan/loader.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c -index fcb79983114..8095f7d4310 100644 ---- a/dlls/winevulkan/loader.c -+++ b/dlls/winevulkan/loader.c -@@ -368,6 +368,15 @@ static void fill_luid_property(VkPhysicalDeviceProperties2 *properties2) - id->deviceNodeMask); - } - -+static void update_driver_version( VkPhysicalDeviceProperties *properties ) -+{ -+ if (properties->vendorID == 0x1002 && properties->deviceID == 0x163f) -+ { -+ /* AMD VANGOGH */ -+ properties->driverVersion = VK_MAKE_VERSION(21, 20, 1); -+ } -+} -+ - void WINAPI vkGetPhysicalDeviceProperties(VkPhysicalDevice physical_device, - VkPhysicalDeviceProperties *properties) - { -@@ -390,6 +399,7 @@ void WINAPI vkGetPhysicalDeviceProperties(VkPhysicalDevice physical_device, - } - } - } -+ update_driver_version(properties); - } - - void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev, -@@ -415,6 +425,7 @@ void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev, - } - } - } -+ update_driver_version(&properties2->properties); - } - - void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev, -@@ -440,6 +451,7 @@ void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev, - } - } - } -+ update_driver_version(&properties2->properties); - } - - VkResult WINAPI vkGetCalibratedTimestampsEXT(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoEXT *pTimestampInfos, uint64_t *pTimestamps, uint64_t *pMaxDeviation) -From 399675bd511cbfd57a44e3afaae32a9ddf6dac87 Mon Sep 17 00:00:00 2001 -From: Zhiyi Zhang -Date: Wed, 11 Nov 2020 10:41:42 +0800 -Subject: [PATCH] winex11.drv: Call XIconifyWindow() after XMapWindow() with a - minimized window. - -Mutter always unminimizes a window when handling map requests. So a window could be in -normal state as far as Mutter concerns while Wine mistakenly considers it still minimized. - -Fix Disgaea PC black screen after Alt+Tab in fullscreen mode. - -CW-Bug-Id: #18364 -Signed-off-by: Zhiyi Zhang ---- - dlls/winex11.drv/window.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 76d06b57814..b8cba02a0a8 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1346,6 +1346,9 @@ static void map_window( HWND hwnd, DWORD new_style ) - update_net_wm_states( data ); - sync_window_style( data ); - XMapWindow( data->display, data->whole_window ); -+ /* Mutter always unminimizes windows when handling map requests. Restore iconic state */ -+ if (new_style & WS_MINIMIZE) -+ XIconifyWindow( data->display, data->whole_window, data->vis.screen ); - XFlush( data->display ); - if (data->surface && data->vis.visualid != default_visual.visualid) - data->surface->funcs->flush( data->surface ); -@@ -2947,9 +2950,17 @@ void CDECL X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags - data->iconic = (new_style & WS_MINIMIZE) != 0; - TRACE( "changing win %p iconic state to %u\n", data->hwnd, data->iconic ); - if (data->iconic) -+ { - XIconifyWindow( data->display, data->whole_window, data->vis.screen ); -+ } - else if (is_window_rect_mapped( rectWindow )) -+ { -+ /* whole_window could be both iconic and mapped. Since XMapWindow() doesn't do -+ * anything if the window is already mapped, we need to unmap it first */ -+ if (data->mapped) -+ XUnmapWindow( data->display, data->whole_window ); - XMapWindow( data->display, data->whole_window ); -+ } - update_net_wm_states( data ); - } - else - -From cbb473f9808f96bb948229536eb5d57ea7629a58 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 23 Nov 2021 10:54:06 +0100 -Subject: [PATCH] winex11.drv: Listen to the root window property changes. - -CW-Bug-Id: #19673 -CW-Bug-Id: #19991 ---- - dlls/winex11.drv/systray.c | 2 +- - dlls/winex11.drv/window.c | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/systray.c b/dlls/winex11.drv/systray.c -index c6d12b21c28..ac6e317ea5c 100644 ---- a/dlls/winex11.drv/systray.c -+++ b/dlls/winex11.drv/systray.c -@@ -625,7 +625,7 @@ static BOOL init_systray(void) - sprintf( systray_buffer, "_NET_SYSTEM_TRAY_S%u", DefaultScreen( display ) ); - systray_atom = XInternAtom( display, systray_buffer, False ); - } -- XSelectInput( display, root_window, StructureNotifyMask ); -+ XSelectInput( display, root_window, StructureNotifyMask | PropertyChangeMask ); - - init_done = TRUE; - return TRUE; -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index b8cba02a0a8..a0d71c6e7f6 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -2233,6 +2233,7 @@ BOOL CDECL X11DRV_CreateWindow( HWND hwnd ) - InputOnly, default_visual.visual, - CWOverrideRedirect | CWEventMask, &attr ); - x11drv_xinput_enable( data->display, data->clip_window, attr.event_mask ); -+ XSelectInput( data->display, DefaultRootWindow( data->display ), PropertyChangeMask ); - XFlush( data->display ); - SetPropA( hwnd, clip_window_prop, (HANDLE)data->clip_window ); - X11DRV_InitClipboard(); -From 14de66fd7ca005a0a4f8ef2d3357a477ad054e5d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 23 Nov 2021 11:15:12 +0100 -Subject: [PATCH] HACK: gamescope: winex11.drv: Track GAMESCOPE_FOCUSED_APP - property changes. - -CW-Bug-Id: #19673 ---- - dlls/winex11.drv/event.c | 32 ++++++++++++++++++++++++++++++++ - dlls/winex11.drv/x11drv.h | 1 + - dlls/winex11.drv/x11drv_main.c | 3 ++- - 3 files changed, 35 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index b0ef922ca5d..53fd1e00b1c 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -1450,6 +1450,36 @@ static void handle__net_wm_state_notify( HWND hwnd, XPropertyEvent *event ) - release_win_data( data ); - } - -+static int handle_gamescope_focused_app_error( Display *dpy, XErrorEvent *event, void *arg ) -+{ -+ WARN( "Failed to read GAMESCOPE_FOCUSED_APP property, ignoring.\n" ); -+ return 1; -+} -+ -+static void handle_gamescope_focused_app( XPropertyEvent *event ) -+{ -+ static const char *sgi = NULL; -+ -+ unsigned long count, remaining, *property; -+ int format, app_id, focused_app_id; -+ Atom type; -+ -+ if (!sgi && !(sgi = getenv( "SteamGameId" ))) return; -+ app_id = atoi( sgi ); -+ -+ X11DRV_expect_error( event->display, handle_gamescope_focused_app_error, NULL ); -+ XGetWindowProperty( event->display, DefaultRootWindow( event->display ), x11drv_atom( GAMESCOPE_FOCUSED_APP ), -+ 0, ~0UL, False, XA_CARDINAL, &type, &format, &count, &remaining, (unsigned char **)&property ); -+ if (X11DRV_check_error()) focused_app_id = app_id; -+ else -+ { -+ if (!property) focused_app_id = app_id; -+ else focused_app_id = *property; -+ XFree( property ); -+ } -+ -+ TRACE( "Got app id %u, focused app %u\n", app_id, focused_app_id ); -+} - - /*********************************************************************** - * X11DRV_PropertyNotify -@@ -1459,6 +1489,8 @@ static BOOL X11DRV_PropertyNotify( HWND hwnd, XEvent *xev ) - XPropertyEvent *event = &xev->xproperty; - char *name; - -+ if (event->atom == x11drv_atom( GAMESCOPE_FOCUSED_APP )) handle_gamescope_focused_app( event ); -+ - if (!hwnd) return FALSE; - - name = XGetAtomName(event->display, event->atom); -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 7bb0e95d8d3..c9033074585 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -547,6 +547,7 @@ enum x11drv_atoms - XATOM_text_rtf, - XATOM_text_richtext, - XATOM_text_uri_list, -+ XATOM_GAMESCOPE_FOCUSED_APP, - NB_XATOMS - }; - -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index a03eb52ad46..2dd81a39e28 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -228,7 +228,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] = - "text/plain", - "text/rtf", - "text/richtext", -- "text/uri-list" -+ "text/uri-list", -+ "GAMESCOPE_FOCUSED_APP" - }; - - /*********************************************************************** -From 266d6749771c5fa21403809f0277070a90626d48 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 23 Nov 2021 11:17:18 +0100 -Subject: [PATCH] HACK: gamescope: winex11.drv: Ignore mouse events when Steam - Keyboard is opened. - -Using a global __wine_steamclient_KeyboardActivated event. We need to -keep keyboard events though as it's how the OSK will communicate its -input. - -CW-Bug-Id: #19673 ---- - dlls/winex11.drv/event.c | 22 +++++++++++++++++++++- - dlls/winex11.drv/mouse.c | 1 + - dlls/winex11.drv/x11drv.h | 1 + - dlls/winex11.drv/x11drv_main.c | 3 +++ - 4 files changed, 26 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 53fd1e00b1c..6aaeafb5dd4 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -447,18 +447,22 @@ static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,X - { - XEvent event, prev_event; - int count = 0; -- BOOL queued = FALSE, overlay_enabled = FALSE; -+ BOOL queued = FALSE, overlay_enabled = FALSE, steam_keyboard_opened = FALSE; - enum event_merge_action action = MERGE_DISCARD; - ULONG_PTR overlay_filter = QS_KEY | QS_MOUSEBUTTON | QS_MOUSEMOVE; -+ ULONG_PTR keyboard_filter = QS_MOUSEBUTTON | QS_MOUSEMOVE; - - if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) - overlay_enabled = TRUE; -+ if (WaitForSingleObject(steam_keyboard_event, 0) == WAIT_OBJECT_0) -+ steam_keyboard_opened = TRUE; - - prev_event.type = 0; - while (XCheckIfEvent( display, &event, filter, (char *)arg )) - { - count++; - if (overlay_enabled && filter_event( display, &event, (char *)overlay_filter )) continue; -+ if (steam_keyboard_opened && filter_event( display, &event, (char *)keyboard_filter )) continue; - if (XFilterEvent( &event, None )) - { - /* -@@ -1459,9 +1463,11 @@ static int handle_gamescope_focused_app_error( Display *dpy, XErrorEvent *event, - static void handle_gamescope_focused_app( XPropertyEvent *event ) - { - static const char *sgi = NULL; -+ static BOOL steam_keyboard_opened; - - unsigned long count, remaining, *property; - int format, app_id, focused_app_id; -+ BOOL keyboard_opened; - Atom type; - - if (!sgi && !(sgi = getenv( "SteamGameId" ))) return; -@@ -1478,7 +1484,21 @@ static void handle_gamescope_focused_app( XPropertyEvent *event ) - XFree( property ); - } - -+ keyboard_opened = app_id != focused_app_id; -+ if (steam_keyboard_opened == keyboard_opened) return; -+ steam_keyboard_opened = keyboard_opened; -+ - TRACE( "Got app id %u, focused app %u\n", app_id, focused_app_id ); -+ if (keyboard_opened) -+ { -+ TRACE( "Steam Keyboard is opened, filtering events.\n" ); -+ SetEvent( steam_keyboard_event ); -+ } -+ else -+ { -+ TRACE( "Steam Keyboard is closed, stopping events filter.\n" ); -+ ResetEvent( steam_keyboard_event ); -+ } - } - - /*********************************************************************** -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 0e13ce0e773..ea479d58264 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -1554,6 +1554,7 @@ BOOL CDECL X11DRV_GetCursorPos(LPPOINT pos) - BOOL ret; - - if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) return FALSE; -+ if (WaitForSingleObject(steam_keyboard_event, 0) == WAIT_OBJECT_0) return FALSE; - - ret = XQueryPointer( display, root_window, &root, &child, &rootX, &rootY, &winX, &winY, &xstate ); - if (ret) -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index c9033074585..612069d30cf 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -450,6 +450,7 @@ extern HMODULE x11drv_module DECLSPEC_HIDDEN; - extern char *process_name DECLSPEC_HIDDEN; - extern Display *clipboard_display DECLSPEC_HIDDEN; - extern HANDLE steam_overlay_event DECLSPEC_HIDDEN; -+extern HANDLE steam_keyboard_event DECLSPEC_HIDDEN; - - /* atoms */ - -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 2dd81a39e28..e22528bdd34 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -90,6 +90,7 @@ int xfixes_event_base = 0; - HMODULE x11drv_module = 0; - char *process_name = NULL; - HANDLE steam_overlay_event; -+HANDLE steam_keyboard_event; - BOOL layered_window_client_hack = FALSE; - - static x11drv_error_callback err_callback; /* current callback for error */ -@@ -834,9 +835,11 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved ) - x11drv_module = hinst; - ret = process_attach(); - steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); -+ steam_keyboard_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_KeyboardActivated"); - break; - case DLL_PROCESS_DETACH: - CloseHandle(steam_overlay_event); -+ CloseHandle(steam_keyboard_event); - break; - } - return ret; -From ed9751078cc384274d780e7ecf2a212e9ea737d4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 26 Jan 2022 19:25:56 +0100 -Subject: [PATCH] HACK: gamescope: dinput: Ignore joystick input when Steam - Keyboard is opened. - ---- - dlls/dinput/dinput_main.c | 3 +++ - dlls/dinput/dinput_private.h | 1 + - dlls/dinput/joystick_hid.c | 3 ++- - 3 files changed, 6 insertions(+), 1 deletion(-) - -diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c -index 87226fff1b9..11ac7c13b8c 100644 ---- a/dlls/dinput/dinput_main.c -+++ b/dlls/dinput/dinput_main.c -@@ -1465,6 +1465,7 @@ void check_dinput_events(void) - } - - HANDLE steam_overlay_event; -+HANDLE steam_keyboard_event; - - BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) - { -@@ -1473,6 +1474,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(inst); - steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); -+ steam_keyboard_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_KeyboardActivated"); - DINPUT_instance = inst; - register_di_em_win_class(); - break; -@@ -1482,6 +1484,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) - unregister_di_em_win_class(); - DeleteCriticalSection(&dinput_hook_crit); - CloseHandle(steam_overlay_event); -+ CloseHandle(steam_keyboard_event); - break; - } - return TRUE; -diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h -index 37d4a4a060a..4c5660baca1 100644 ---- a/dlls/dinput/dinput_private.h -+++ b/dlls/dinput/dinput_private.h -@@ -49,6 +49,7 @@ struct IDirectInputImpl - extern const IDirectInput7AVtbl dinput7_a_vtbl DECLSPEC_HIDDEN; - extern const IDirectInput8AVtbl dinput8_a_vtbl DECLSPEC_HIDDEN; - extern HANDLE steam_overlay_event DECLSPEC_HIDDEN; -+extern HANDLE steam_keyboard_event DECLSPEC_HIDDEN; - - extern HRESULT mouse_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version ); - extern HRESULT mouse_create_device( IDirectInputImpl *dinput, const GUID *guid, IDirectInputDevice8W **out ); -diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c -index 9ffaa2786d4..dd17cd478ae 100644 ---- a/dlls/dinput/joystick_hid.c -+++ b/dlls/dinput/joystick_hid.c -@@ -1252,7 +1252,8 @@ static HRESULT hid_joystick_read( IDirectInputDevice8W *iface ) - } - } - -- if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) /* steam overlay is enabled */ -+ if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0 || /* steam overlay is enabled */ -+ WaitForSingleObject(steam_keyboard_event, 0) == WAIT_OBJECT_0) /* steam keyboard is enabled */ - params.reset_state = TRUE; - else - params.reset_state = FALSE; -From c00909b683c229658ad89f77ceea724e2f0f1bd1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Wed, 26 Jan 2022 19:26:19 +0100 -Subject: [PATCH] HACK: gamescope: xinput1_3: Ignore gamepad input when Steam - Keyboard is opened. - ---- - dlls/xinput1_3/main.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c -index f57b5ee360b..ee132d58aed 100644 ---- a/dlls/xinput1_3/main.c -+++ b/dlls/xinput1_3/main.c -@@ -125,6 +125,7 @@ static HANDLE stop_event; - static HANDLE done_event; - static HANDLE update_event; - static HANDLE steam_overlay_event; -+static HANDLE steam_keyboard_event; - - static BOOL find_opened_device(const WCHAR *device_path, int *free_slot) - { -@@ -547,6 +548,7 @@ static void stop_update_thread(void) - CloseHandle(done_event); - CloseHandle(update_event); - CloseHandle(steam_overlay_event); -+ CloseHandle(steam_keyboard_event); - - for (i = 0; i < XUSER_MAX_COUNT; i++) controller_destroy(&controllers[i], FALSE); - } -@@ -743,6 +745,7 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void - HANDLE thread; - - steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); -+ steam_keyboard_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_KeyboardActivated"); - - start_event = CreateEventA(NULL, FALSE, FALSE, NULL); - if (!start_event) ERR("failed to create start event, error %u\n", GetLastError()); -@@ -839,6 +842,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION *vib - if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - - if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) ret = ERROR_SUCCESS; -+ else if (WaitForSingleObject(steam_keyboard_event, 0) == WAIT_OBJECT_0) ret = ERROR_SUCCESS; - else ret = HID_set_state(&controllers[index], vibration); - - controller_unlock(&controllers[index]); -@@ -858,6 +862,7 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) - if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - - if (WaitForSingleObject(steam_overlay_event, 0) == WAIT_OBJECT_0) memset(state, 0, sizeof(*state)); -+ else if (WaitForSingleObject(steam_keyboard_event, 0) == WAIT_OBJECT_0) memset(state, 0, sizeof(*state)); - else *state = controllers[index].state; - - controller_unlock(&controllers[index]); -From ef828e66f330bc8eaaad45609c45699bba371270 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 28 Oct 2021 16:41:17 +0200 -Subject: [PATCH] HACK: gamescope: winex11.drv: Use native screen rect for - absolute raw event positions. - -CW-Bug-Id: #18214 ---- - dlls/winex11.drv/display.c | 13 +++++++++++++ - dlls/winex11.drv/mouse.c | 1 + - dlls/winex11.drv/x11drv.h | 1 + - 3 files changed, 15 insertions(+) - -diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c -index b3ed448c43f..f3e928ac25e 100644 ---- a/dlls/winex11.drv/display.c -+++ b/dlls/winex11.drv/display.c -@@ -55,6 +55,7 @@ struct x11drv_display_device_handler desktop_handler; - - /* Cached screen information, protected by screen_section */ - static HKEY video_key; -+static RECT native_screen_rect; - static RECT virtual_screen_rect; - static RECT primary_monitor_rect; - static FILETIME last_query_screen_time; -@@ -125,6 +126,7 @@ static BOOL update_screen_cache(void) - } - - EnterCriticalSection(&screen_section); -+ if (!native_screen_rect.bottom) native_screen_rect = virtual_rect; - virtual_screen_rect = virtual_rect; - primary_monitor_rect = primary_rect; - last_query_screen_time = filetime; -@@ -170,6 +172,17 @@ POINT root_to_virtual_screen(INT x, INT y) - return pt; - } - -+RECT get_native_screen_rect(void) -+{ -+ RECT rect; -+ -+ update_screen_cache(); -+ EnterCriticalSection(&screen_section); -+ rect = native_screen_rect; -+ LeaveCriticalSection(&screen_section); -+ return rect; -+} -+ - RECT get_virtual_screen_rect(void) - { - RECT virtual; -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index a7fabcf860d..9511590cdb0 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -1895,6 +1895,7 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) - FIXME( "Unsupported relative/absolute X/Y axis mismatch\n." ); - - if (input->u.mi.dwFlags & MOUSEEVENTF_VIRTUALDESK) SetRect( &virtual_rect, 0, 0, 65535, 65535 ); -+ else if (wm_is_steamcompmgr( event->display )) virtual_rect = get_native_screen_rect(); - else virtual_rect = get_virtual_screen_rect(); - - if (x->max <= x->min) x_scale = 1; -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 5c9dbb88aad..a3f2b5a93e3 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -743,6 +743,7 @@ extern BOOL is_window_rect_full_screen( const RECT *rect ) DECLSPEC_HIDDEN; - extern BOOL is_window_rect_full_virtual_screen( const RECT *rect ) DECLSPEC_HIDDEN; - extern POINT virtual_screen_to_root( INT x, INT y ) DECLSPEC_HIDDEN; - extern POINT root_to_virtual_screen( INT x, INT y ) DECLSPEC_HIDDEN; -+extern RECT get_native_screen_rect(void) DECLSPEC_HIDDEN; - extern RECT get_virtual_screen_rect(void) DECLSPEC_HIDDEN; - extern RECT get_primary_monitor_rect(void) DECLSPEC_HIDDEN; - extern RECT get_host_primary_monitor_rect(void) DECLSPEC_HIDDEN; -From 61521e371ac42b8d91b9af163bbc350bd89e0c5b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 30 Nov 2021 10:38:13 +0100 -Subject: [PATCH] HACK: server: Close desktop immediately when last user is - removed. - -This should speed up prefix shutdown by 1s, making it only depend on -master socket timeout. - -CW-Bug-Id: #19584 ---- - server/user.h | 1 - - server/winstation.c | 12 ++---------- - 2 files changed, 2 insertions(+), 11 deletions(-) - -diff --git a/server/user.h b/server/user.h -index 3f7341a120f..a274b66383d 100644 ---- a/server/user.h -+++ b/server/user.h -@@ -72,7 +72,6 @@ struct desktop - struct window *msg_window; /* HWND_MESSAGE top window */ - struct hook_table *global_hooks; /* table of global hooks on this desktop */ - struct list hotkeys; /* list of registered hotkeys */ -- struct timeout_user *close_timeout; /* timeout before closing the desktop */ - struct thread_input *foreground_input; /* thread input of foreground thread */ - unsigned int users; /* processes and threads using this desktop */ - struct global_cursor cursor; /* global cursor information */ -diff --git a/server/winstation.c b/server/winstation.c -index fabd892f4cc..a9b161312dd 100644 ---- a/server/winstation.c -+++ b/server/winstation.c -@@ -252,7 +252,6 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned - desktop->top_window = NULL; - desktop->msg_window = NULL; - desktop->global_hooks = NULL; -- desktop->close_timeout = NULL; - desktop->foreground_input = NULL; - desktop->users = 0; - desktop->cursor_clip_msg = 0; -@@ -318,7 +317,6 @@ static void desktop_destroy( struct object *obj ) - if (desktop->top_window) destroy_window( desktop->top_window ); - if (desktop->msg_window) destroy_window( desktop->msg_window ); - if (desktop->global_hooks) release_object( desktop->global_hooks ); -- if (desktop->close_timeout) remove_timeout_user( desktop->close_timeout ); - list_remove( &desktop->entry ); - release_object( desktop->shared_mapping ); - release_object( desktop->winstation ); -@@ -334,7 +332,6 @@ static void close_desktop_timeout( void *private ) - { - struct desktop *desktop = private; - -- desktop->close_timeout = NULL; - unlink_named_object( &desktop->obj ); /* make sure no other process can open it */ - post_desktop_message( desktop, WM_CLOSE, 0, 0 ); /* and signal the owner to quit */ - } -@@ -343,11 +340,6 @@ static void close_desktop_timeout( void *private ) - static void add_desktop_user( struct desktop *desktop ) - { - desktop->users++; -- if (desktop->close_timeout) -- { -- remove_timeout_user( desktop->close_timeout ); -- desktop->close_timeout = NULL; -- } - } - - /* remove a user of the desktop and start the close timeout if necessary */ -@@ -358,8 +350,8 @@ static void remove_desktop_user( struct desktop *desktop ) - desktop->users--; - - /* if we have one remaining user, it has to be the manager of the desktop window */ -- if ((process = get_top_window_owner( desktop )) && desktop->users == process->running_threads && !desktop->close_timeout) -- desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop ); -+ if ((process = get_top_window_owner( desktop )) && desktop->users == process->running_threads) -+ close_desktop_timeout( desktop ); - } - - /* set the thread default desktop handle */ -From f5e6cd76159d7bcc4fc8589bbad8e163d3756c85 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 4 Feb 2022 11:34:26 +0100 -Subject: [PATCH] HACK: steam: hidclass.sys: Do not send WM_INPUT messages when - overlay is open. - -So that games listening to them, such as ICEY, do not have input -bleeding through the overlay. Note that some other games, such as Hades, -which are reading the HID devices directly, have the input bleeding -through on Windows, so we do the same here. - -CW-Bug-Id: #20083 ---- - dlls/hidclass.sys/device.c | 7 ++++++- - dlls/hidclass.sys/hid.h | 6 ++++++ - dlls/hidclass.sys/pnp.c | 12 ++++++++++++ - 3 files changed, 24 insertions(+), 1 deletion(-) - -diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c -index 70e1c3d12d4..a0e5e75382d 100644 ---- a/dlls/hidclass.sys/device.c -+++ b/dlls/hidclass.sys/device.c -@@ -223,6 +223,7 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack - const BOOL polled = ext->u.pdo.information.Polled; - ULONG size, report_len = polled ? packet->reportBufferLen : desc->InputLength; - struct hid_report *last_report, *report; -+ BOOL steam_overlay_open = FALSE; - struct hid_queue *queue; - LIST_ENTRY completed, *entry; - RAWINPUT *rawinput; -@@ -231,7 +232,11 @@ static void hid_device_queue_input( DEVICE_OBJECT *device, HID_XFER_PACKET *pack - - TRACE("device %p, packet %p\n", device, packet); - -- if (IsEqualGUID( ext->class_guid, &GUID_DEVINTERFACE_HID )) -+ if (WaitForSingleObject(ext->steam_overlay_event, 0) == WAIT_OBJECT_0 || /* steam overlay is open */ -+ WaitForSingleObject(ext->steam_keyboard_event, 0) == WAIT_OBJECT_0) /* steam keyboard is open */ -+ steam_overlay_open = TRUE; -+ -+ if (IsEqualGUID( ext->class_guid, &GUID_DEVINTERFACE_HID ) && !steam_overlay_open) - { - size = offsetof( RAWINPUT, data.hid.bRawData[report_len] ); - if (!(rawinput = malloc( size ))) ERR( "Failed to allocate rawinput data!\n" ); -diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h -index e20f12809eb..042695dba63 100644 ---- a/dlls/hidclass.sys/hid.h -+++ b/dlls/hidclass.sys/hid.h -@@ -83,6 +83,9 @@ typedef struct _BASE_DEVICE_EXTENSION - WCHAR instance_id[MAX_DEVICE_ID_LEN]; - const GUID *class_guid; - -+ HANDLE steam_overlay_event; -+ HANDLE steam_keyboard_event; -+ - BOOL is_fdo; - } BASE_DEVICE_EXTENSION; - -@@ -114,6 +117,9 @@ typedef struct _minidriver - - PDRIVER_ADD_DEVICE AddDevice; - PDRIVER_DISPATCH PNPDispatch; -+ -+ HANDLE steam_overlay_event; -+ HANDLE steam_keyboard_event; - } minidriver; - - void call_minidriver( ULONG code, DEVICE_OBJECT *device, void *in_buff, ULONG in_size, -diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c -index 096fe54c51b..681fafd610f 100644 ---- a/dlls/hidclass.sys/pnp.c -+++ b/dlls/hidclass.sys/pnp.c -@@ -172,6 +172,9 @@ static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *b - swprintf(ext->device_id, ARRAY_SIZE(ext->device_id), L"HID\\%s", wcsrchr(device_id, '\\') + 1); - wcscpy(ext->instance_id, instance_id); - -+ ext->steam_overlay_event = minidriver->steam_overlay_event; -+ ext->steam_keyboard_event = minidriver->steam_keyboard_event; -+ - is_xinput_class = !wcsncmp(device_id, L"WINEXINPUT\\", 7) && wcsstr(device_id, L"&XI_") != NULL; - if (is_xinput_class) ext->class_guid = &GUID_DEVINTERFACE_WINEXINPUT; - else ext->class_guid = &GUID_DEVINTERFACE_HID; -@@ -235,6 +238,9 @@ static void create_child(minidriver *minidriver, DEVICE_OBJECT *fdo) - pdo_ext->u.pdo.information.VersionNumber = attr.VersionNumber; - pdo_ext->u.pdo.information.Polled = minidriver->minidriver.DevicesArePolled; - -+ pdo_ext->steam_overlay_event = minidriver->steam_overlay_event; -+ pdo_ext->steam_keyboard_event = minidriver->steam_keyboard_event; -+ - call_minidriver( IOCTL_HID_GET_DEVICE_DESCRIPTOR, fdo, NULL, 0, &descriptor, sizeof(descriptor), &io ); - if (io.Status != STATUS_SUCCESS) - { -@@ -582,6 +588,9 @@ static void WINAPI driver_unload(DRIVER_OBJECT *driver) - if (md->DriverUnload) - md->DriverUnload(md->minidriver.DriverObject); - list_remove(&md->entry); -+ -+ CloseHandle(md->steam_overlay_event); -+ CloseHandle(md->steam_keyboard_event); - free(md); - } - } -@@ -593,6 +602,9 @@ NTSTATUS WINAPI HidRegisterMinidriver(HID_MINIDRIVER_REGISTRATION *registration) - if (!(driver = calloc(1, sizeof(*driver)))) - return STATUS_NO_MEMORY; - -+ driver->steam_overlay_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_GameOverlayActivated"); -+ driver->steam_keyboard_event = CreateEventA(NULL, TRUE, FALSE, "__wine_steamclient_KeyboardActivated"); -+ - driver->DriverUnload = registration->DriverObject->DriverUnload; - registration->DriverObject->DriverUnload = driver_unload; - diff --git a/patches/protonprep-valve-staging-7.0.sh b/patches/protonprep-valve-staging-7.0.sh deleted file mode 100755 index 6469e6ce2..000000000 --- a/patches/protonprep-valve-staging-7.0.sh +++ /dev/null @@ -1,418 +0,0 @@ -#!/bin/bash - -### (1) PREP SECTION ### - - cd dxvk - git reset --hard HEAD - git clean -xdf - - # https://github.com/doitsujin/dxvk/pull/2675 - echo "DXVK: [dxgi] Leave fullscreen mode when window looses focus" - patch -Np1 < ../patches/dxvk/2675.patch - - echo "DXVK: Fix Secret World: Legends patcher crash" - patch -Np1 < ../patches/dxvk/secret-world.patch - cd .. - - cd vkd3d-proton - git reset --hard HEAD - git clean -xdf - - cd .. - -### END PREP SECTION ### - -### (2) WINE PATCHING ### - - cd wine - git reset --hard HEAD - git clean -xdf - -### (2-1) PROBLEMATIC COMMIT REVERT SECTION ### - - # nvapi - git revert --no-commit fdfb4b925f52fbec580dd30bef37fb22c219c667 - -### END PROBLEMATIC COMMIT REVERT SECTION ### - - -### (2-2) WINE STAGING APPLY SECTION ### - - echo "WINE: -STAGING- applying staging patches" - - ../wine-staging/patches/patchinstall.sh DESTDIR="." --all \ - -W winex11-_NET_ACTIVE_WINDOW \ - -W winex11-WM_WINDOWPOSCHANGING \ - -W winex11-MWM_Decorations \ - -W winex11-key_translation \ - -W ntdll-Syscall_Emulation \ - -W ntdll-Junction_Points \ - -W server-File_Permissions \ - -W server-Stored_ACLs \ - -W eventfd_synchronization \ - -W d3dx11_43-D3DX11CreateTextureFromMemory \ - -W dbghelp-Debug_Symbols \ - -W ddraw-Device_Caps \ - -W ddraw-version-check \ - -W dwrite-FontFallback \ - -W ntdll-DOS_Attributes \ - -W Pipelight \ - -W dinput-joy-mappings \ - -W server-Key_State \ - -W server-PeekMessage \ - -W server-Realtime_Priority \ - -W server-Signal_Thread \ - -W loader-KeyboardLayouts \ - -W mshtml-HTMLLocation_put_hash \ - -W msxml3-FreeThreadedXMLHTTP60 \ - -W ntdll-ForceBottomUpAlloc \ - -W ntdll-ApiSetMap \ - -W ntdll-WRITECOPY \ - -W ntdll-Builtin_Prot \ - -W ntdll-CriticalSection \ - -W ntdll-Exception \ - -W ntdll-Hide_Wine_Exports \ - -W ntdll-Serial_Port_Detection \ - -W secur32-InitializeSecurityContextW \ - -W server-default_integrity \ - -W user32-rawinput-mouse \ - -W user32-rawinput-mouse-experimental \ - -W user32-recursive-activation \ - -W windows.networking.connectivity-new-dll \ - -W wineboot-ProxySettings \ - -W winex11-UpdateLayeredWindow \ - -W winex11-Vulkan_support \ - -W winex11-wglShareLists \ - -W wintab32-improvements \ - -W xactengine3_7-PrepareWave \ - -W xactengine3_7-Notification \ - -W xactengine-initial \ - -W kernel32-CopyFileEx \ - -W shell32-Progress_Dialog \ - -W shell32-ACE_Viewer \ - -W fltmgr.sys-FltBuildDefaultSecurityDescriptor \ - -W inseng-Implementation \ - -W ntdll-RtlQueryPackageIdentity \ - -W packager-DllMain \ - -W winemenubuilder-Desktop_Icon_Path \ - -W wscript-support-d-u-switches \ - -W wininet-Cleanup \ - -W sapi-ISpObjectToken-CreateInstance \ - -W sapi-iteration-tokens \ - -W cryptext-CryptExtOpenCER \ - -W shell32-NewMenu_Interface \ - -W wintrust-WTHelperGetProvCertFromChain \ - -W user32-FlashWindowEx \ - -W user32-MessageBox_WS_EX_TOPMOST \ - -W wined3d-zero-inf-shaders \ - -W winex11-XEMBED - - # NOTE: Some patches are applied manually because they -do- apply, just not cleanly, ie with patch fuzz. - # A detailed list of why the above patches are disabled is listed below: - - # winex11-_NET_ACTIVE_WINDOW - Causes origin to freeze - # winex11-WM_WINDOWPOSCHANGING - Causes origin to freeze - # winex11-MWM_Decorations - not compatible with fullscreen hack - # winex11-key_translation - replaced by proton's keyboard patches - # winex11-wglShareLists - applied manually - # ntdll-Syscall_Emulation - already applied - # ntdll-Junction_Points - breaks CEG drm - # server-File_Permissions - requires ntdll-Junction_Points - # server-Stored_ACLs - requires ntdll-Junction_Points - # eventfd_synchronization - already applied - # d3dx11_43-D3DX11CreateTextureFromMemory - manually applied - # ddraw-Device_Caps - conflicts with proton's changes - # ddraw-version-check - conflicts with proton's changes - - # dbghelp-Debug_Symbols - see below: - # Sancreed — 11/21/2021 - # Heads up, it appears that a bunch of Ubisoft Connect games (3/3 I had installed and could test) will crash - # almost immediately on newer Wine Staging/TKG inside pe_load_debug_info function unless the dbghelp-Debug_Symbols staging # patchset is disabled. - - # dwrite-FontFallback - replaced by proton's font patches - # ** ntdll-DOS_Attributes - applied manually - # server-Key_State - replaced by proton shared memory patches - # server-PeekMessage - eplaced by proton's version - # server-Realtime_Priority - replaced by proton's patches - # server-Signal_Thread - breaks steamclient for some games -- notably DBFZ - # Pipelight - for MS Silverlight, not needed - # dinput-joy-mappings - disabled in favor of proton's gamepad patches - # ** loader-KeyboardLayouts - applied manually -- needed to prevent Overwatch huge FPS drop - # mshtml-HTMLLocation_put_hash - already applied - # msxml3-FreeThreadedXMLHTTP60 - already applied - # ntdll-ForceBottomUpAlloc - already applied - # ntdll-ApiSetMap - applied manually - # ntdll-WRITECOPY - already applied - # ntdll-Builtin_Prot - already applied - # ntdll-CriticalSection - breaks ffxiv and deep rock galactic - # ** ntdll-Exception - applied manually - # ** ntdll-Hide_Wine_Exports - applied manually - # ** ntdll-Serial_Port_Detection - applied manually - # ** secur32-InitializeSecurityContextW - applied manually - # server-default_integrity - causes steam.exe to stay open after game closes - # user32-rawinput-mouse - already applied - # user32-rawinput-mouse-experimental - already applied - # user32-recursive-activation - already applied - # ** windows.networking.connectivity-new-dll - applied manually - # ** wineboot-ProxySettings - applied manually - # ** winex11-UpdateLayeredWindow - applied manually - # ** winex11-Vulkan_support - applied manually - # wintab32-improvements - for wacom tablets, not needed - # ** xactengine-initial - applied manually - # ** xactengine3_7-Notification - applied manually - # ** xactengine3_7-PrepareWave - applied manually - # ** xactengine3_7-callbacks - applied manually -- added after 7.0 - # kernel32-CopyFileEx - breaks various installers - # shell32-Progress_Dialog - relies on kernel32-CopyFileEx - # shell32-ACE_Viewer - adds a UI tab, not needed, relies on kernel32-CopyFileEx - # ** fltmgr.sys-FltBuildDefaultSecurityDescriptor - applied manually - # ** inseng-Implementation - applied manually - # ** ntdll-RtlQueryPackageIdentity - applied manually - # ** packager-DllMain - applied manually - # ** winemenubuilder-Desktop_Icon_Path - applied manually - # ** wscript-support-d-u-switches - applied manually - # ** wininet-Cleanup - applied manually - # sapi-ISpObjectToken-CreateInstance - already applied - # sapi-iteration-tokens - already applied - # cryptext-CryptExtOpenCER - applied manually - # ** wintrust-WTHelperGetProvCertFromChain - applied manually - # ** shell32-NewMenu_Interface - applied manually - # ** user32-FlashWindowEx - applied manually - # user32-MessageBox_WS_EX_TOPMOST - already applied - # wined3d-zero-inf-shaders - already applied - # ** winex11-XEMBED - applied manually - - echo "WINE: -STAGING- applying staging Compiler_Warnings revert for steamclient compatibility" - # revert this, it breaks lsteamclient compilation - patch -RNp1 < ../wine-staging/patches/Compiler_Warnings/0031-include-Check-element-type-in-CONTAINING_RECORD-and-.patch - - # d3dx11_43-D3DX11CreateTextureFromMemory - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0001-d3dx11_43-Implement-D3DX11GetImageInfoFromMemory.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0002-d3dx11_42-Implement-D3DX11CreateTextureFromMemory.patch - - # ntdll-DOS_Attributes - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch - - # loader-KeyboardLayouts - patch -Np1 < ../wine-staging/patches/loader-KeyboardLayouts/0001-loader-Add-Keyboard-Layouts-registry-enteries.patch - patch -Np1 < ../wine-staging/patches/loader-KeyboardLayouts/0002-user32-Improve-GetKeyboardLayoutList.patch - - # ntdll-ApiSetMap - patch -Np1 < ../wine-staging/patches/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch - - # ntdll-Exception - patch -Np1 < ../wine-staging/patches/ntdll-Exception/0002-ntdll-OutputDebugString-should-throw-the-exception-a.patch - - # ntdll-Hide_Wine_Exports - patch -Np1 < ../wine-staging/patches/ntdll-Hide_Wine_Exports/0001-ntdll-Add-support-for-hiding-wine-version-informatio.patch - - # ntdll-Serial_Port_Detection - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch - - # secur32-InitializeSecurityContextW - patch -Np1 < ../wine-staging/patches/secur32-InitializeSecurityContextW/0001-secur32-Input-Parameter-should-be-NULL-on-first-call.patch - - # mouse rawinput - # per discussion with remi: - #--- - #GloriousEggroll — Today at 4:05 PM - #@rbernon are there any specific rawinput patches from staging that are not in proton? i have someone saying they had better mouse rawinput functionality in my previous wine-staging builds - #rbernon — Today at 4:07 PM - #there's some yes, with truly raw values - #proton still uses transformed value with the desktop mouse acceleration to not change user settings unexpectedly - #--- - # /wine-staging/patches/user32-rawinput-mouse-experimental/0006-winex11.drv-Send-relative-RawMotion-events-unprocess.patch - # we use a rebased version for proton - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/rawinput/0006-winex11.drv-Send-relative-RawMotion-events-unprocess.patch - - # windows.networking.connectivity-new-dll - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0001-include-Add-windows.networking.connectivity.idl.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0002-include-Add-windows.networking.idl.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0003-windows.networking.connectivity-Add-stub-dll.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0004-windows.networking.connectivity-Implement-IActivatio.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0005-windows.networking.connectivity-Implement-INetworkIn.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0006-windows.networking.connectivity-Registry-DLL.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0007-windows.networking.connectivity-Implement-INetworkIn.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0008-windows.networking.connectivity-IConnectionProfile-G.patch - - # wineboot-ProxySettings - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/0001-wineboot-Initialize-proxy-settings-registry-key.patch - - # winex11-UpdateLayeredWindow - patch -Np1 < ../wine-staging/patches/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch - - # winex11-Vulkan_support - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/0001-winex11-Specify-a-default-vulkan-driver-if-one-not-f.patch - - # xactengine-initial - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/xactengine-initial/0001-x3daudio1_7-Create-import-library.patch - - # xactengine3_7-Notification - patch -Np1 < ../wine-staging/patches/xactengine3_7-Notification/0001-xactengine3.7-Delay-Notication-for-WAVEBANKPREPARED.patch - patch -Np1 < ../wine-staging/patches/xactengine3_7-Notification/0002-xactengine3_7-Record-context-for-each-notications.patch - - # xactengine3_7-PrepareWave - patch -Np1 < ../wine-staging/patches/xactengine3_7-PrepareWave/0002-xactengine3_7-Implement-IXACT3Engine-PrepareStreamin.patch - patch -Np1 < ../wine-staging/patches/xactengine3_7-PrepareWave/0003-xactengine3_7-Implement-IXACT3Engine-PrepareInMemory.patch - - # xactengine3_7-callbacks - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch - - # fltmgr.sys-FltBuildDefaultSecurityDescriptor - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0001-fltmgr.sys-Implement-FltBuildDefaultSecurityDescript.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0002-fltmgr.sys-Create-import-library.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0003-ntoskrnl.exe-Add-FltBuildDefaultSecurityDescriptor-t.patch - - # inseng-Implementation - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/inseng-Implementation/0001-inseng-Implement-CIF-reader-and-download-functions.patch - - # ntdll-RtlQueryPackageIdentity - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/0003-ntdll-tests-Add-basic-tests-for-RtlQueryPackageIdent.patch - - # packager-DllMain - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/packager-DllMain/0001-packager-Prefer-native-version.patch - - # winemenubuilder-Desktop_Icon_Path - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch - - # wscript-support-d-u-switches - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/0001-wscript-return-TRUE-for-d-and-u-stub-switches.patch - - # wininet-Cleanup - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0001-wininet-tests-Add-more-tests-for-cookies.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0002-wininet-tests-Test-auth-credential-reusage-with-host.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0003-wininet-tests-Check-cookie-behaviour-when-overriding.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0004-wininet-Strip-filename-if-no-path-is-set-in-cookie.patch - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0005-wininet-Replacing-header-fields-should-fail-if-they-.patch - - # winex11-wglShareLists - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch - - # cryptext-CryptExtOpenCER - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/0001-cryptext-Implement-CryptExtOpenCER.patch - - # wintrust-WTHelperGetProvCertFromChain - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/0001-wintrust-Add-parameter-check-in-WTHelperGetProvCertF.patch - - # shell32-NewMenu_Interface - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/0001-shell32-Implement-NewMenu-with-new-folder-item.patch - - # user32-FlashWindowEx - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/0001-user32-Improve-FlashWindowEx-message-and-return-valu.patch - - # winex11-XEMBED - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch - - # nvapi/nvcuda - # this was added in 7.1, so it's not in the 7.0 tree - patch -Np1 < ../patches/wine-hotfixes/staging-7.0/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch - -### END WINE STAGING APPLY SECTION ### - -### (2-3) GAME PATCH SECTION ### - - echo "WINE: -GAME FIXES- assetto corsa hud fix" - patch -Np1 < ../patches/game-patches/assettocorsa-hud.patch - - echo "WINE: -GAME FIXES- killer instinct vulkan fix" - patch -Np1 < ../patches/game-patches/killer-instinct-winevulkan_fix.patch - - echo "WINE: -GAME FIXES- add powerprof patches for FFVII Remake and SpecialK" - patch -Np1 < ../patches/game-patches/FFVII-and-SpecialK-powerprof.patch - - echo "WINE: -GAME FIXES- add file search workaround hack for Phantasy Star Online 2" - patch -Np1 < ../patches/game-patches/pso2_hack.patch - -### END GAME PATCH SECTION ### - -### (2-4) PROTON PATCH SECTION ### - - echo "WINE: -FSR- fullscreen hack fsr patch" - patch -Np1 < ../patches/proton/48-proton-fshack_amd_fsr.patch - - echo "WINE: -FSR- fake current res patches" - patch -Np1 < ../patches/proton/65-proton-fake_current_res_patches.patch - - echo "WINE: -FSR- add 32:9 FSR resolutions" - patch -Np1 < ../patches/proton/69-proton-fsr-add-329-res.patch - - echo "WINE: -FSR- add FSR resolutions by aspect ratio instead of current screen width" - patch -Np1 < ../patches/proton/70-proton-add_fsr_res_by_aspect_ratio.patch - - echo "WINE: -FSR- enable FSR flag by default (fixes broken fs hack scaling in some games like Apex and FFXIV)" - patch -Np1 < ../patches/proton/71-invert-fsr-logic.patch - - echo "WINE: -FSR- set 'balanced' default mode if no mode is set, and dont set any default mode if a custom mode is set" - patch -Np1 < ../patches/proton/72-fsr-use-balanced-default-mode.patch - - -### END PROTON PATCH SECTION ### - - -### (2-5) WINE HOTFIX SECTION ### - - # https://github.com/Frogging-Family/wine-tkg-git/commit/ca0daac62037be72ae5dd7bf87c705c989eba2cb - echo "WINE: -HOTFIX- unity crash hotfix" - patch -Np1 < ../patches/wine-hotfixes/pending/unity_crash_hotfix.patch - - echo "WINE: -HOTFIX- 32 bit compilation crashes with newer libldap, upstream patch fixes it" - patch -Np1 < ../patches/wine-hotfixes/upstream/32-bit-ldap-upstream-fix.patch - - echo "WINE: -HOTFIX- fix audio regression caused by 0e7fd41" - patch -Np1 < ../patches/wine-hotfixes/upstream/Fix-regression-introduced-by-0e7fd41.patch - - # https://bugs.winehq.org/show_bug.cgi?id=52956 - echo "WINE: -HOTFIX- fix star citizen bug 52956" - patch -Np1 < ../patches/wine-hotfixes/pending/0001-winex11.drv-Define-ControlMask-when-not-available.patch - patch -Np1 < ../patches/wine-hotfixes/pending/0002-include-Add-THREAD_POWER_THROTTLING_STATE-type.patch - patch -Np1 < ../patches/wine-hotfixes/pending/0003-ntdll-Fake-success-for-ThreadPowerThrottlingState.patch - - # https://bugs.winehq.org/show_bug.cgi?id=51683 - echo "WINE: -HOTFIX- Guild Wars 2 patch" - patch -Np1 < ../patches/wine-hotfixes/pending/hotfix-guild_wars_2.patch - - echo "WINE: -HOTFIX- fix Amazon Games launcher" - patch -Np1 < ../patches/wine-hotfixes/upstream/481.patch - - echo "WINE: -HOTFIX- fix Visual Novel Doukyuusei" - patch -Np1 < ../patches/wine-hotfixes/upstream/visual-novel-doukyuusei.patch - - echo "WINE: -HOTFIX- fix Persona 4 Golden" - patch -Np1 < ../patches/wine-hotfixes/upstream/381c2a9ae151f676a009e89b4b101679fd90b9ae.patch - - echo "WINE: -HOTFIX- fix Overwatch 2 shader compilation issue" - # https://gitlab.winehq.org/wine/wine/-/merge_requests/1152 - patch -Np1 < ../patches/wine-hotfixes/pending/1152.patch - - echo "WINE: -HOTFIX- fix Overwatch 2 from freezing on wine 7.12 and older" - # https://gitlab.winehq.org/wine/wine/-/merge_requests/1152 - patch -Np1 < ../patches/wine-hotfixes/pending/4bf9d2403f269e7f3595ad075a4afee9adbda51f.patch - - echo "WINE: -HOTFIX- fix Anno 1800 multiplayer" - # https://gitlab.winehq.org/wine/wine/-/merge_requests/1152 - patch -Np1 < ../patches/wine-hotfixes/pending/181.patch - - echo "WINE: -HOTFIX- Add Star Citizen EAC patch and wrap it around SteamGameId=starcitizen envvar" - patch -Np1 < ../patches/game-patches/star-citizen-eac.patch - -### END WINE HOTFIX SECTION ### - -### (2-6) WINE PENDING UPSTREAM SECTION ### - - -### END WINE PENDING UPSTREAM SECTION ### - - -### (2-7) WINE CUSTOM PATCHES ### - -### END WINE CUSTOM PATCHES ### -### END WINE PATCHING ### diff --git a/patches/protonprep-valve-staging.sh b/patches/protonprep-valve-staging.sh index 551545c89..44c130f0f 100755 --- a/patches/protonprep-valve-staging.sh +++ b/patches/protonprep-valve-staging.sh @@ -5,10 +5,6 @@ cd dxvk git reset --hard HEAD git clean -xdf - - # https://github.com/doitsujin/dxvk/pull/2675 - echo "DXVK: [dxgi] Leave fullscreen mode when window looses focus" - patch -Np1 < ../patches/dxvk/2675.patch echo "DXVK: Fix Secret World: Legends patcher crash" patch -Np1 < ../patches/dxvk/secret-world.patch @@ -241,9 +237,6 @@ # wineboot-ProxySettings patch -Np1 < ../patches/wine-hotfixes/staging/wineboot-ProxySettings/0001-wineboot-Initialize-proxy-settings-registry-key.patch - # winex11-UpdateLayeredWindow - # patch -Np1 < ../wine-staging/patches/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch - # winex11-Vulkan_support patch -Np1 < ../patches/wine-hotfixes/staging/winex11-Vulkan_support/0001-winex11-Specify-a-default-vulkan-driver-if-one-not-f.patch @@ -268,9 +261,6 @@ # packager-DllMain patch -Np1 < ../patches/wine-hotfixes/staging/packager-DllMain/0001-packager-Prefer-native-version.patch - # winemenubuilder-Desktop_Icon_Path - patch -Np1 < ../patches/wine-hotfixes/staging/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch - # wscript-support-d-u-switches patch -Np1 < ../patches/wine-hotfixes/staging/wscript-support-d-u-switches/0001-wscript-return-TRUE-for-d-and-u-stub-switches.patch @@ -281,9 +271,6 @@ patch -Np1 < ../patches/wine-hotfixes/staging/wininet-Cleanup/0004-wininet-Strip-filename-if-no-path-is-set-in-cookie.patch patch -Np1 < ../patches/wine-hotfixes/staging/wininet-Cleanup/0005-wininet-Replacing-header-fields-should-fail-if-they-.patch - # winex11-wglShareLists - # patch -Np1 < ../patches/wine-hotfixes/staging/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch - # cryptext-CryptExtOpenCER patch -Np1 < ../patches/wine-hotfixes/staging/cryptext-CryptExtOpenCER/0001-cryptext-Implement-CryptExtOpenCER.patch @@ -299,9 +286,6 @@ # kernel32-Debugger patch -Np1 < ../wine-staging/patches/kernel32-Debugger/0001-kernel32-Always-start-debugger-on-WinSta0.patch - # winex11-XEMBED - # patch -Np1 < ../patches/wine-hotfixes/staging/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch - ### END WINE STAGING APPLY SECTION ### ### (2-3) GAME PATCH SECTION ### @@ -334,10 +318,6 @@ echo "WINE: -PENDING- Guild Wars 2 patch" patch -Np1 < ../patches/wine-hotfixes/pending/hotfix-guild_wars_2.patch - echo "WINE: -PENDING- Add Star Citizen GameGlass stub" - # added in 8.5 -- backporting - patch -Np1 < ../patches/wine-hotfixes/upstream/2326.patch - ### END WINE PENDING UPSTREAM SECTION ### diff --git a/patches/wine-hotfixes/pending/0001-winex11.drv-Define-ControlMask-when-not-available.patch b/patches/wine-hotfixes/pending/0001-winex11.drv-Define-ControlMask-when-not-available.patch deleted file mode 100644 index 4dde51e79..000000000 --- a/patches/wine-hotfixes/pending/0001-winex11.drv-Define-ControlMask-when-not-available.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 799533014002a61c02b4eae629b8c5cc0ef77e62 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sun, 22 May 2022 17:40:44 +1000 -Subject: [PATCH 1/3] winex11.drv: Define ControlMask when not available - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/winex11.drv/keyboard.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c -index 961b4363240..7b302ec7e60 100644 ---- a/dlls/winex11.drv/keyboard.c -+++ b/dlls/winex11.drv/keyboard.c -@@ -64,6 +64,11 @@ - WINE_DEFAULT_DEBUG_CHANNEL(keyboard); - WINE_DECLARE_DEBUG_CHANNEL(key); - -+/* X.h defines ControlMask but conflicts with struct variable name */ -+#ifndef ControlMask -+#define ControlMask (1<<2) -+#endif -+ - static int min_keycode, max_keycode, keysyms_per_keycode; - static KeySym *key_mapping; - static WORD keyc2vkey[256], keyc2scan[256]; --- -2.35.1 - diff --git a/patches/wine-hotfixes/pending/0002-include-Add-THREAD_POWER_THROTTLING_STATE-type.patch b/patches/wine-hotfixes/pending/0002-include-Add-THREAD_POWER_THROTTLING_STATE-type.patch deleted file mode 100644 index 562ae2022..000000000 --- a/patches/wine-hotfixes/pending/0002-include-Add-THREAD_POWER_THROTTLING_STATE-type.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 2d657d911905772eae4c48157b465d3145bec52f Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sun, 22 May 2022 16:09:23 +1000 -Subject: [PATCH 2/3] include: Add THREAD_POWER_THROTTLING_STATE type - -Signed-off-by: Alistair Leslie-Hughes ---- - include/processthreadsapi.h | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/include/processthreadsapi.h b/include/processthreadsapi.h -index d266b7a727b..f74758d6807 100644 ---- a/include/processthreadsapi.h -+++ b/include/processthreadsapi.h -@@ -37,6 +37,14 @@ typedef struct _MEMORY_PRIORITY_INFORMATION - ULONG MemoryPriority; - } MEMORY_PRIORITY_INFORMATION, *PMEMORY_PRIORITY_INFORMATION; - -+#undef ControlMask -+typedef struct _THREAD_POWER_THROTTLING_STATE -+{ -+ ULONG Version; -+ ULONG ControlMask; -+ ULONG StateMask; -+} THREAD_POWER_THROTTLING_STATE; -+ - WINBASEAPI HRESULT WINAPI GetThreadDescription(HANDLE,PWSTR *); - WINBASEAPI HRESULT WINAPI SetThreadDescription(HANDLE,PCWSTR); - WINBASEAPI BOOL WINAPI SetThreadInformation(HANDLE,THREAD_INFORMATION_CLASS,LPVOID,DWORD); --- -2.35.1 - diff --git a/patches/wine-hotfixes/pending/0003-ntdll-Fake-success-for-ThreadPowerThrottlingState.patch b/patches/wine-hotfixes/pending/0003-ntdll-Fake-success-for-ThreadPowerThrottlingState.patch deleted file mode 100644 index 94f1154dc..000000000 --- a/patches/wine-hotfixes/pending/0003-ntdll-Fake-success-for-ThreadPowerThrottlingState.patch +++ /dev/null @@ -1,30 +0,0 @@ -From d57f4b43c08ba530e1f36edf19691c33ac435c04 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sun, 22 May 2022 16:10:27 +1000 -Subject: [PATCH 3/3] ntdll: Fake success for ThreadPowerThrottlingState - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/ntdll/unix/thread.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index 6d937675bcb..15bb3be34b2 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -2255,6 +2255,12 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class, - FIXME( "ThreadEnableAlignmentFaultFixup stub!\n" ); - return STATUS_SUCCESS; - -+ case ThreadPowerThrottlingState: -+ if (length != sizeof(THREAD_POWER_THROTTLING_STATE)) return STATUS_INFO_LENGTH_MISMATCH; -+ if (!data) return STATUS_ACCESS_VIOLATION; -+ FIXME( "ThreadPowerThrottling stub!\n" ); -+ return STATUS_SUCCESS; -+ - case ThreadBasicInformation: - case ThreadTimes: - case ThreadPriority: --- -2.35.1 - diff --git a/patches/wine-hotfixes/pending/1152.patch b/patches/wine-hotfixes/pending/1152.patch deleted file mode 100644 index dc8865ce6..000000000 --- a/patches/wine-hotfixes/pending/1152.patch +++ /dev/null @@ -1,173 +0,0 @@ -From 591c7383693d3e2f193fe2744a530b0ba3771e09 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Mon, 24 Oct 2022 19:30:25 +0200 -Subject: [PATCH 1/3] ntdll: Align stack pointer when calling - KiUserCallbackDispatcher. - -Overwatch hooks KiUserCallbackDispatcher and expects the stack pointer to be aligned to a multiple of 16 bytes, -instead of the usual 8-byte misalignment, otherwise it will crash on a misaligned movaps. - -Fix this by aligning the stack pointer when calling the dispatcher and again inside the dispatcher. - -Signed-off-by: Torge Matthies ---- - dlls/ntdll/signal_x86_64.c | 28 ++++++++++++++++++++++------ - dlls/ntdll/unix/signal_x86_64.c | 2 +- - 2 files changed, 23 insertions(+), 7 deletions(-) - -diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c -index b1ab4933b93..5af82a6a09f 100644 ---- a/dlls/ntdll/signal_x86_64.c -+++ b/dlls/ntdll/signal_x86_64.c -@@ -654,12 +654,7 @@ __ASM_GLOBAL_FUNC( KiUserApcDispatcher, - "int3") - - --/******************************************************************* -- * KiUserCallbackDispatcher (NTDLL.@) -- * -- * FIXME: not binary compatible -- */ --void WINAPI KiUserCallbackDispatcher( ULONG id, void *args, ULONG len ) -+void WINAPI user_callback_dispatcher( ULONG id, void *args, ULONG len ) - { - NTSTATUS status; - -@@ -678,6 +673,27 @@ void WINAPI KiUserCallbackDispatcher( ULONG id, void *args, ULONG len ) - RtlRaiseStatus( status ); - } - -+/******************************************************************* -+ * KiUserCallbackDispatcher (NTDLL.@) -+ * -+ * FIXME: not binary compatible -+ */ -+#ifdef __x86_64__ -+__ASM_GLOBAL_FUNC( KiUserCallbackDispatcher, -+ "movq %rsp,%rbp\n\t" -+ __ASM_SEH(".seh_setframe %rbp, 0\n\t") -+ __ASM_CFI(".cfi_def_cfa rbp, 8\n\t") -+ "andq $0xFFFFFFFFFFFFFFF0, %rsp\n\t" -+ __ASM_SEH(".seh_endprologue\n\t") -+ "call " __ASM_NAME("user_callback_dispatcher") "\n\t" -+ "int3") -+#else -+void WINAPI DECLSPEC_HOTPATCH KiUserCallbackDispatcher( ULONG id, void *args, ULONG len ) -+{ -+ return user_callback_dispatcher( id, args, len ); -+} -+#endif -+ - - static ULONG64 get_int_reg( CONTEXT *context, int reg ) - { -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 5787f1dc6f9..0526db9d762 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -2399,7 +2399,7 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void - if (!__wine_setjmpex( &callback_frame.jmpbuf, NULL )) - { - struct syscall_frame *frame = amd64_thread_data()->syscall_frame; -- void *args_data = (void *)((frame->rsp - len) & ~15); -+ void *args_data = (void *)(((frame->rsp - len) & ~15) - 8); - - memcpy( args_data, args, len ); - --- -GitLab - - -From e4a83a4b1d5a0dfffa52a7b804c82ddd5aeafb39 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Mon, 24 Oct 2022 19:30:25 +0200 -Subject: [PATCH 2/3] ntdll: Add 5-byte nop to start of - KiUserCallbackDispatcher. - -Overwatch 2 hooks KiUserCallbackDispatcher by overwriting the first five bytes with a jump, and returning to -just after the jump. Make sure there is a five-byte instruction for it to replace. - -Signed-off-by: Torge Matthies ---- - dlls/ntdll/signal_x86_64.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c -index 5af82a6a09f..7757b7b61bd 100644 ---- a/dlls/ntdll/signal_x86_64.c -+++ b/dlls/ntdll/signal_x86_64.c -@@ -680,6 +680,7 @@ void WINAPI user_callback_dispatcher( ULONG id, void *args, ULONG len ) - */ - #ifdef __x86_64__ - __ASM_GLOBAL_FUNC( KiUserCallbackDispatcher, -+ ".byte 0x0f, 0x1f, 0x44, 0x00, 0x00\n\t" /* Overwatch 2 replaces the first 5 bytes with a jump */ - "movq %rsp,%rbp\n\t" - __ASM_SEH(".seh_setframe %rbp, 0\n\t") - __ASM_CFI(".cfi_def_cfa rbp, 8\n\t") --- -GitLab - - -From 15a6e26a2b9559dd785a3cf0e008c05b88c39f17 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Mon, 24 Oct 2022 19:30:26 +0200 -Subject: [PATCH 3/3] ntdll: Pass KiUserCallbackDispatcher parameters on stack. - -In addition to in registers. - -Overwatch 2 hooks KiUserCallbackDispatcher and expects to be able to use all the caller-saved registers, but also -expects the callback id to be in ecx. - -Signed-off-by: Torge Matthies ---- - dlls/ntdll/signal_x86_64.c | 3 +++ - dlls/ntdll/unix/signal_x86_64.c | 10 +++++++++- - 2 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c -index 7757b7b61bd..2bebd9cd934 100644 ---- a/dlls/ntdll/signal_x86_64.c -+++ b/dlls/ntdll/signal_x86_64.c -@@ -686,6 +686,9 @@ __ASM_GLOBAL_FUNC( KiUserCallbackDispatcher, - __ASM_CFI(".cfi_def_cfa rbp, 8\n\t") - "andq $0xFFFFFFFFFFFFFFF0, %rsp\n\t" - __ASM_SEH(".seh_endprologue\n\t") -+ "movq 0x28(%rbp), %rdx\n\t" -+ "movl 0x30(%rbp), %ecx\n\t" -+ "movl 0x34(%rbp), %r8d\n\t" - "call " __ASM_NAME("user_callback_dispatcher") "\n\t" - "int3") - #else -diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index 0526db9d762..019d1ecefa2 100644 ---- a/dlls/ntdll/unix/signal_x86_64.c -+++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -2400,8 +2400,16 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void - { - struct syscall_frame *frame = amd64_thread_data()->syscall_frame; - void *args_data = (void *)(((frame->rsp - len) & ~15) - 8); -+ struct { -+ void *args; -+ ULONG id; -+ ULONG len; -+ } *params = (void *)((ULONG_PTR)args_data - 0x10); - - memcpy( args_data, args, len ); -+ params->args = args_data; -+ params->id = id; -+ params->len = len; - - callback_frame.frame.rcx = id; - callback_frame.frame.rdx = (ULONG_PTR)args; -@@ -2410,7 +2418,7 @@ NTSTATUS WINAPI KeUserModeCallback( ULONG id, const void *args, ULONG len, void - callback_frame.frame.fs = amd64_thread_data()->fs; - callback_frame.frame.gs = ds64_sel; - callback_frame.frame.ss = ds64_sel; -- callback_frame.frame.rsp = (ULONG_PTR)args_data - 0x28; -+ callback_frame.frame.rsp = (ULONG_PTR)params - 0x28; - callback_frame.frame.rip = (ULONG_PTR)pKiUserCallbackDispatcher; - callback_frame.frame.eflags = 0x200; - callback_frame.frame.restore_flags = CONTEXT_CONTROL | CONTEXT_INTEGER; --- -GitLab - diff --git a/patches/wine-hotfixes/pending/181.patch b/patches/wine-hotfixes/pending/181.patch deleted file mode 100644 index 9b64b93fe..000000000 --- a/patches/wine-hotfixes/pending/181.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 4ff23ccae7798c0c0add0e11ed31fa9c17498dbf Mon Sep 17 00:00:00 2001 -From: Jeffrey van Pelt -Date: Sat, 4 Mar 2023 21:30:40 +0100 -Subject: [PATCH] Fix handling for ALG_ID_ECDH_P384, which (among probably some - others) fixes Anno 1800 multiplayer session negotiation - ---- - dlls/bcrypt/bcrypt_main.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c -index cc33a3cc63c..54b95ceed7b 100644 ---- a/dlls/bcrypt/bcrypt_main.c -+++ b/dlls/bcrypt/bcrypt_main.c -@@ -1701,6 +1701,7 @@ NTSTATUS WINAPI BCryptGenerateKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_H - case ALG_ID_ECDSA_P256: - size = sizeof(BCRYPT_ECCKEY_BLOB) + 2 * 256 / 8; - break; -+ case ALG_ID_ECDH_P384: - case ALG_ID_ECDSA_P384: - size = sizeof(BCRYPT_ECCKEY_BLOB) + 2 * 384 / 8; - break; - diff --git a/patches/wine-hotfixes/pending/4bf9d2403f269e7f3595ad075a4afee9adbda51f.patch b/patches/wine-hotfixes/pending/4bf9d2403f269e7f3595ad075a4afee9adbda51f.patch deleted file mode 100644 index 56c683700..000000000 --- a/patches/wine-hotfixes/pending/4bf9d2403f269e7f3595ad075a4afee9adbda51f.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 4bf9d2403f269e7f3595ad075a4afee9adbda51f Mon Sep 17 00:00:00 2001 -From: Alexandre Julliard -Date: Wed, 6 Jul 2022 12:46:50 +0200 -Subject: [PATCH] ntdll: Fix the return value of NtQueryKey for a short buffer. - -Signed-off-by: Alexandre Julliard ---- - dlls/ntdll/unix/registry.c | 8 ++------ - 2 files changed, 17 insertions(+), 7 deletions(-) - -diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c -index 9c98bf48399f..428f8c9eb3ce 100644 ---- a/dlls/ntdll/unix/registry.c -+++ b/dlls/ntdll/unix/registry.c -@@ -268,7 +268,6 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i - case KeyBasicInformation: - { - KEY_BASIC_INFORMATION keyinfo; -- fixed_size = (char *)keyinfo.Name - (char *)&keyinfo; - keyinfo.LastWriteTime.QuadPart = reply->modif; - keyinfo.TitleIndex = 0; - keyinfo.NameLength = reply->namelen; -@@ -279,7 +278,6 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i - case KeyFullInformation: - { - KEY_FULL_INFORMATION keyinfo; -- fixed_size = (char *)keyinfo.Class - (char *)&keyinfo; - keyinfo.LastWriteTime.QuadPart = reply->modif; - keyinfo.TitleIndex = 0; - keyinfo.ClassLength = wine_server_reply_size(reply); -@@ -297,7 +295,6 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i - case KeyNodeInformation: - { - KEY_NODE_INFORMATION keyinfo; -- fixed_size = (char *)keyinfo.Name - (char *)&keyinfo; - keyinfo.LastWriteTime.QuadPart = reply->modif; - keyinfo.TitleIndex = 0; - if (reply->namelen < wine_server_reply_size(reply)) -@@ -318,7 +315,6 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i - case KeyNameInformation: - { - KEY_NAME_INFORMATION keyinfo; -- fixed_size = (char *)keyinfo.Name - (char *)&keyinfo; - keyinfo.NameLength = reply->namelen; - memcpy( info, &keyinfo, min( length, fixed_size ) ); - break; -@@ -327,7 +323,6 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i - case KeyCachedInformation: - { - KEY_CACHED_INFORMATION keyinfo; -- fixed_size = sizeof(keyinfo); - keyinfo.LastWriteTime.QuadPart = reply->modif; - keyinfo.TitleIndex = 0; - keyinfo.SubKeys = reply->subkeys; -@@ -344,7 +339,8 @@ static NTSTATUS enumerate_key( HANDLE handle, int index, KEY_INFORMATION_CLASS i - break; - } - *result_len = fixed_size + reply->total; -- if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW; -+ if (length < fixed_size) ret = STATUS_BUFFER_TOO_SMALL; -+ else if (length < *result_len) ret = STATUS_BUFFER_OVERFLOW; - } - } - SERVER_END_REQ; diff --git a/patches/wine-hotfixes/pending/hotfix-update_mono_version.patch b/patches/wine-hotfixes/pending/hotfix-update_mono_version.patch deleted file mode 100644 index bd45fc99d..000000000 --- a/patches/wine-hotfixes/pending/hotfix-update_mono_version.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 147164fc7738bda2e50421d731e15489188916e1 Mon Sep 17 00:00:00 2001 -From: Esme Povirk -Date: Wed, 26 Jan 2022 11:41:28 -0600 -Subject: [PATCH] mscoree: Update Wine Mono to 7.1.2. - ---- - dlls/appwiz.cpl/addons.c | 6 +++--- - dlls/mscoree/mscoree_private.h | 2 +- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c -index b4da6137d72..8570d58acb7 100644 ---- a/dlls/appwiz.cpl/addons.c -+++ b/dlls/appwiz.cpl/addons.c -@@ -58,10 +58,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl); - #define GECKO_SHA "???" - #endif - --#define MONO_VERSION "7.1.5" -+#define MONO_VERSION "7.1.1" - #if defined(__i386__) || defined(__x86_64__) - #define MONO_ARCH "x86" --#define MONO_SHA "cb03854b5d868b2d0912da42e01536bb673e009ed5263f4eeb8836a2a9c36f43" -+#define MONO_SHA "9dc8e5603b7bc64354eb94ae4ea0f6821424767a3ff44ff0d19e346a490c11ea" - #else - #define MONO_ARCH "" - #define MONO_SHA "???" -diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h -index 1ef5ac200f3..8f826c73252 100644 ---- a/dlls/mscoree/mscoree_private.h -+++ b/dlls/mscoree/mscoree_private.h -@@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version) - extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count) DECLSPEC_HIDDEN; - extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func) DECLSPEC_HIDDEN; - --#define WINE_MONO_VERSION "7.1.5" -+#define WINE_MONO_VERSION "7.1.1" - - /* Mono embedding */ - typedef struct _MonoDomain MonoDomain; diff --git a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0001-ntdll-tests-Add-test-for-file-attributes-of-files-wi.patch b/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0001-ntdll-tests-Add-test-for-file-attributes-of-files-wi.patch deleted file mode 100644 index 5a3d0a0ab..000000000 --- a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0001-ntdll-tests-Add-test-for-file-attributes-of-files-wi.patch +++ /dev/null @@ -1,123 +0,0 @@ -From cd0e7d0bd693a35fde5a83f76af16cd04b17c5e3 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Thu, 30 Mar 2023 05:46:38 +0200 -Subject: [PATCH 1/6] ntdll/tests: Add test for file attributes of files with - names beginning with a dot. - ---- - dlls/ntdll/tests/file.c | 92 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 92 insertions(+) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 6186afdfb63..beaa4734931 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -4051,6 +4051,97 @@ static void test_file_attribute_tag_information(void) - CloseHandle( h ); - } - -+static void rename_file( HANDLE h, const WCHAR *filename ) -+{ -+ FILE_RENAME_INFORMATION *fri; -+ UNICODE_STRING ntpath; -+ IO_STATUS_BLOCK io; -+ NTSTATUS status; -+ BOOLEAN ret; -+ ULONG size; -+ -+ ret = pRtlDosPathNameToNtPathName_U( filename, &ntpath, NULL, NULL ); -+ ok( ret, "RtlDosPathNameToNtPathName_U failed\n" ); -+ -+ size = offsetof( FILE_RENAME_INFORMATION, FileName ) + ntpath.Length; -+ fri = HeapAlloc( GetProcessHeap(), 0, size ); -+ ok( fri != NULL, "HeapAlloc failed\n" ); -+ fri->ReplaceIfExists = TRUE; -+ fri->RootDirectory = NULL; -+ fri->FileNameLength = ntpath.Length; -+ memcpy( fri->FileName, ntpath.Buffer, ntpath.Length ); -+ pRtlFreeUnicodeString( &ntpath ); -+ -+ status = pNtSetInformationFile( h, &io, fri, size, FileRenameInformation ); -+ HeapFree( GetProcessHeap(), 0, fri ); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+} -+ -+static void test_dotfile_file_attributes(void) -+{ -+ char temppath[MAX_PATH], filename[MAX_PATH]; -+ WCHAR temppathW[MAX_PATH], filenameW[MAX_PATH]; -+ FILE_BASIC_INFORMATION info = {}; -+ IO_STATUS_BLOCK io; -+ NTSTATUS status; -+ DWORD attrs; -+ HANDLE h; -+ -+ GetTempPathA( MAX_PATH, temppath ); -+ GetTempFileNameA( temppath, ".foo", 0, filename ); -+ h = CreateFileA( filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); -+ ok( h != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); -+ -+ status = nt_get_file_attrs(filename, &attrs); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+ todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); -+ -+ status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+ ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); -+ -+ info.FileAttributes = FILE_ATTRIBUTE_SYSTEM; -+ status = pNtSetInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+ -+ status = nt_get_file_attrs(filename, &attrs); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+ ok( attrs & FILE_ATTRIBUTE_SYSTEM, "got attributes %#lx\n", attrs ); -+ todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); -+ -+ status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+ ok( info.FileAttributes & FILE_ATTRIBUTE_SYSTEM, "got attributes %#lx\n", info.FileAttributes ); -+ ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); -+ -+ CloseHandle( h ); -+ -+ GetTempPathW( MAX_PATH, temppathW ); -+ GetTempFileNameW( temppathW, L"foo", 0, filenameW ); -+ h = CreateFileW( filenameW, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, 0 ); -+ ok( h != INVALID_HANDLE_VALUE, "failed to create temp file\n" ); -+ -+ GetTempFileNameW( temppathW, L".foo", 0, filenameW ); -+ winetest_push_context("foo -> .foo"); -+ rename_file( h, filenameW ); -+ winetest_pop_context(); -+ -+ status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+ ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); -+ -+ GetTempFileNameW( temppathW, L"foo", 0, filenameW ); -+ winetest_push_context(".foo -> foo"); -+ rename_file( h, filenameW ); -+ winetest_pop_context(); -+ -+ status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+ ok( !(info.FileAttributes & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", info.FileAttributes ); -+ -+ CloseHandle( h ); -+} -+ - static void test_file_mode(void) - { - UNICODE_STRING file_name, pipe_dev_name, mountmgr_dev_name, mailslot_dev_name; -@@ -5499,6 +5590,7 @@ START_TEST(file) - test_file_id_information(); - test_file_access_information(); - test_file_attribute_tag_information(); -+ test_dotfile_file_attributes(); - test_file_mode(); - test_file_readonly_access(); - test_query_volume_information_file(); --- -2.40.0 - diff --git a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0002-ntdll-Do-not-open-code-hidden-file-handling-in-get_d.patch b/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0002-ntdll-Do-not-open-code-hidden-file-handling-in-get_d.patch deleted file mode 100644 index 54ef9640b..000000000 --- a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0002-ntdll-Do-not-open-code-hidden-file-handling-in-get_d.patch +++ /dev/null @@ -1,46 +0,0 @@ -From bf28841ea6e717ed625ccd02a025fb6153f45677 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Thu, 30 Mar 2023 05:46:39 +0200 -Subject: [PATCH 2/6] ntdll: Do not open-code hidden file handling in - get_dir_data_entry. - -Signed-off-by: Torge Matthies ---- - dlls/ntdll/unix/file.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index eca75b2d4fb..f48de4641b3 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -1303,7 +1303,7 @@ static BOOL is_hidden_file( const UNICODE_STRING *name ) - end = p = name->Buffer + name->Length/sizeof(WCHAR); - while (p > name->Buffer && p[-1] == '\\') p--; - while (p > name->Buffer && p[-1] != '\\') p--; -- return (p < end && *p == '.'); -+ return (p < end && p + 1 != end && p[0] == '.' && p[1] != '\\' && (p[1] != '.' || (p + 2 != end && p[2] != '\\'))); - } - - -@@ -2224,6 +2224,7 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I - union file_directory_info *info; - struct stat st; - ULONG name_len, start, dir_size, attributes; -+ UNICODE_STRING name; - - if (get_file_info( names->unix_name, &st, &attributes ) == -1) - { -@@ -2253,8 +2254,8 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I - { - if (st.st_dev != dir_data->id.dev) st.st_ino = 0; /* ignore inode if on a different device */ - -- if (!show_dot_files && names->long_name[0] == '.' && names->long_name[1] && -- (names->long_name[1] != '.' || names->long_name[2])) -+ RtlInitUnicodeString( &name, names->long_name ); -+ if (is_hidden_file( &name )) - attributes |= FILE_ATTRIBUTE_HIDDEN; - - fill_file_info( &st, attributes, info, class ); --- -2.40.0 - diff --git a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0003-ntdll-Handle-hidden-file-names-inside-get_file_info-.patch b/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0003-ntdll-Handle-hidden-file-names-inside-get_file_info-.patch deleted file mode 100644 index 2e50c012a..000000000 --- a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0003-ntdll-Handle-hidden-file-names-inside-get_file_info-.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 46d8829db7ced55d93da228e7777b9f7a6a02e7d Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Thu, 30 Mar 2023 05:46:39 +0200 -Subject: [PATCH 3/6] ntdll: Handle hidden file names inside get_file_info - instead of after it. - -Signed-off-by: Torge Matthies ---- - dlls/ntdll/unix/file.c | 25 +++++++++---------------- - 1 file changed, 9 insertions(+), 16 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index f48de4641b3..59e96a88279 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -1292,17 +1292,17 @@ static BOOLEAN get_dir_case_sensitivity( const char *dir ) - /*********************************************************************** - * is_hidden_file - * -- * Check if the specified file should be hidden based on its name and the show dot files option. -+ * Check if the specified file should be hidden based on its unix path and the show dot files option. - */ --static BOOL is_hidden_file( const UNICODE_STRING *name ) -+static BOOL is_hidden_file( const char *name ) - { -- WCHAR *p, *end; -+ const char *p, *end; - - if (show_dot_files) return FALSE; - -- end = p = name->Buffer + name->Length/sizeof(WCHAR); -- while (p > name->Buffer && p[-1] == '\\') p--; -- while (p > name->Buffer && p[-1] != '\\') p--; -+ end = p = name + strlen( name ); -+ while (p > name && p[-1] == '/') p--; -+ while (p > name && p[-1] != '/') p--; - return (p < end && p + 1 != end && p[0] == '.' && p[1] != '\\' && (p[1] != '.' || (p + 2 != end && p[2] != '\\'))); - } - -@@ -1677,6 +1677,9 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - } - *attr |= get_file_attributes( st ); - -+ if (is_hidden_file( path )) -+ *attr |= FILE_ATTRIBUTE_HIDDEN; -+ - attr_len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); - if (attr_len != -1) - *attr |= parse_samba_dos_attrib_data( attr_data, attr_len ); -@@ -2224,7 +2227,6 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I - union file_directory_info *info; - struct stat st; - ULONG name_len, start, dir_size, attributes; -- UNICODE_STRING name; - - if (get_file_info( names->unix_name, &st, &attributes ) == -1) - { -@@ -2253,11 +2255,6 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I - if (class != FileNamesInformation) - { - if (st.st_dev != dir_data->id.dev) st.st_ino = 0; /* ignore inode if on a different device */ -- -- RtlInitUnicodeString( &name, names->long_name ); -- if (is_hidden_file( &name )) -- attributes |= FILE_ATTRIBUTE_HIDDEN; -- - fill_file_info( &st, attributes, info, class ); - } - -@@ -4219,7 +4216,6 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, - info->AllocationSize = std.AllocationSize; - info->EndOfFile = std.EndOfFile; - info->FileAttributes = basic.FileAttributes; -- if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; - } - free( unix_name ); - } -@@ -4250,10 +4246,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC - else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) - status = STATUS_INVALID_INFO_CLASS; - else -- { - status = fill_file_info( &st, attributes, info, FileBasicInformation ); -- if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; -- } - free( unix_name ); - } - else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); --- -2.40.0 - diff --git a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0004-ntdll-Only-infer-hidden-attribute-from-file-name-if-.patch b/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0004-ntdll-Only-infer-hidden-attribute-from-file-name-if-.patch deleted file mode 100644 index 6543f35c3..000000000 --- a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0004-ntdll-Only-infer-hidden-attribute-from-file-name-if-.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0fa1566f7cab73de95f7d4b51b83766576a60727 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Thu, 30 Mar 2023 05:46:39 +0200 -Subject: [PATCH 4/6] ntdll: Only infer hidden attribute from file name if - xattr is not present. - -Signed-off-by: Torge Matthies ---- - dlls/ntdll/tests/file.c | 2 +- - dlls/ntdll/unix/file.c | 5 ++--- - 2 files changed, 3 insertions(+), 4 deletions(-) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index beaa4734931..cdd924a7226 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -4107,7 +4107,7 @@ static void test_dotfile_file_attributes(void) - status = nt_get_file_attrs(filename, &attrs); - ok( status == STATUS_SUCCESS, "got %#lx\n", status ); - ok( attrs & FILE_ATTRIBUTE_SYSTEM, "got attributes %#lx\n", attrs ); -- todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); -+ ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); - - status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); - ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 59e96a88279..d127e113230 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -1677,14 +1677,13 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - } - *attr |= get_file_attributes( st ); - -- if (is_hidden_file( path )) -- *attr |= FILE_ATTRIBUTE_HIDDEN; -- - attr_len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, attr_data, sizeof(attr_data)-1 ); - if (attr_len != -1) - *attr |= parse_samba_dos_attrib_data( attr_data, attr_len ); - else - { -+ if (is_hidden_file( path )) -+ *attr |= FILE_ATTRIBUTE_HIDDEN; - if (errno == ENOTSUP) return ret; - #ifdef ENODATA - if (errno == ENODATA) return ret; --- -2.40.0 - diff --git a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0005-ntdll-Set-xattr-in-NtCreateFile-if-inferred-and-requ.patch b/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0005-ntdll-Set-xattr-in-NtCreateFile-if-inferred-and-requ.patch deleted file mode 100644 index cf5d0d236..000000000 --- a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0005-ntdll-Set-xattr-in-NtCreateFile-if-inferred-and-requ.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 2ad3cf7addcbf191db85365c0c52aa24935dcdf5 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Thu, 30 Mar 2023 05:46:39 +0200 -Subject: [PATCH 5/6] ntdll: Set xattr in NtCreateFile if inferred and - requested attributes don't match. - -And make sure it doesn't get deleted. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53826 -Signed-off-by: Torge Matthies ---- - dlls/ntdll/tests/file.c | 2 +- - dlls/ntdll/unix/file.c | 26 +++++++++++++++++++------- - 2 files changed, 20 insertions(+), 8 deletions(-) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index cdd924a7226..b96b2e5b072 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -4094,7 +4094,7 @@ static void test_dotfile_file_attributes(void) - - status = nt_get_file_attrs(filename, &attrs); - ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -- todo_wine ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); -+ ok( !(attrs & FILE_ATTRIBUTE_HIDDEN), "got attributes %#lx\n", attrs ); - - status = pNtQueryInformationFile( h, &io, &info, sizeof(info), FileBasicInformation ); - ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index d127e113230..5f5aa9be87c 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -1600,11 +1600,11 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON - } - - --static int fd_set_dos_attrib( int fd, UINT attr ) -+static int fd_set_dos_attrib( int fd, UINT attr, BOOL force_set ) - { - /* we only store the HIDDEN and SYSTEM attributes */ - attr &= XATTR_ATTRIBS_MASK; -- if (attr != 0) -+ if (force_set || attr != 0) - { - /* encode the attributes in Samba 3 ASCII format. Samba 4 has extended - * this format with more features, but retains compatibility with the -@@ -1618,7 +1618,7 @@ static int fd_set_dos_attrib( int fd, UINT attr ) - - - /* set the stat info and file attributes for a file (by file descriptor) */ --NTSTATUS fd_set_file_info( int fd, UINT attr, HANDLE handle ) -+NTSTATUS fd_set_file_info( int fd, UINT attr, HANDLE handle, BOOL force_set_xattr ) - { - struct stat st; - -@@ -1637,7 +1637,8 @@ static NTSTATUS fd_set_file_info( int fd, UINT attr ) - } - if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno ); - -- if (fd_set_dos_attrib( fd, attr ) == -1 && errno != ENOTSUP) -+ force_set_xattr = force_set_xattr || st.st_nlink > 1; -+ if (fd_set_dos_attrib( fd, attr, force_set_xattr ) == -1 && errno != ENOTSUP) - WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)\n", - errno, strerror( errno ) ); - -@@ -3963,6 +3964,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - OBJECT_ATTRIBUTES new_attr; - UNICODE_STRING nt_name; - char *unix_name; -+ BOOL name_hidden = FALSE; - BOOL created = FALSE; - unsigned int status; - -@@ -4005,6 +4007,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - - if (status == STATUS_SUCCESS) - { -+ name_hidden = is_hidden_file( unix_name ); - status = open_unix_file( handle, unix_name, access, &new_attr, attributes, - sharing, disposition, options, ea_buffer, ea_length ); - free( unix_name ); -@@ -4032,14 +4035,15 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - break; - } - -- if (io->Information == FILE_CREATED && (attributes & XATTR_ATTRIBS_MASK)) -+ if (io->Information == FILE_CREATED && -+ ((attributes & XATTR_ATTRIBS_MASK) || name_hidden)) - { - int fd, needs_close; - - /* set any DOS extended attributes */ - if (!server_get_unix_fd( *handle, 0, &fd, &needs_close, NULL, NULL )) - { -- if (fd_set_dos_attrib( fd, attributes ) == -1 && errno != ENOTSUP) -+ if (fd_set_dos_attrib( fd, attributes, TRUE ) == -1 && errno != ENOTSUP) - WARN( "Failed to set extended attribute " SAMBA_XATTR_DOS_ATTRIB ". errno %d (%s)", - errno, strerror( errno ) ); - if (needs_close) close( fd ); -@@ -4561,10 +4565,14 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, - { - const FILE_BASIC_INFORMATION *info = ptr; - LARGE_INTEGER mtime, atime; -+ char *unix_name; - - if ((status = server_get_unix_fd( handle, 0, &fd, &needs_close, NULL, NULL ))) - return io->u.Status = status; - -+ if ((status = server_get_unix_name( handle, &unix_name ))) -+ unix_name = NULL; -+ - mtime.QuadPart = info->LastWriteTime.QuadPart == -1 ? 0 : info->LastWriteTime.QuadPart; - atime.QuadPart = info->LastAccessTime.QuadPart == -1 ? 0 : info->LastAccessTime.QuadPart; - -@@ -4572,9 +4580,13 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, - status = set_file_times( fd, &mtime, &atime ); - - if (status == STATUS_SUCCESS && info->FileAttributes) -- status = fd_set_file_info( fd, info->FileAttributes, handle ); -+ { -+ BOOL force_xattr = unix_name && is_hidden_file( unix_name ); -+ status = fd_set_file_info( fd, info->FileAttributes, handle, force_xattr ); -+ } - - if (needs_close) close( fd ); -+ free( unix_name ); - } - else status = STATUS_INVALID_PARAMETER_3; - break; --- -2.40.0 - diff --git a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0006-ntdll-tests-Increase-margins-in-timer-merging-tests.patch b/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0006-ntdll-tests-Increase-margins-in-timer-merging-tests.patch deleted file mode 100644 index d4c973070..000000000 --- a/patches/wine-hotfixes/pending/ntdll-hidden_file_attr/0006-ntdll-tests-Increase-margins-in-timer-merging-tests.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 6fa8d2eea71223e52ab957247cb91011404ee381 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Thu, 30 Mar 2023 05:46:39 +0200 -Subject: [PATCH 6/6] ntdll/tests: Increase margins in timer merging tests. - -This test failed in the GitLab test runner. - -Signed-off-by: Torge Matthies ---- - dlls/ntdll/tests/threadpool.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/dlls/ntdll/tests/threadpool.c b/dlls/ntdll/tests/threadpool.c -index 168f00c2852..c23157d3207 100644 ---- a/dlls/ntdll/tests/threadpool.c -+++ b/dlls/ntdll/tests/threadpool.c -@@ -1563,18 +1563,18 @@ static void test_tp_window_length(void) - info2.ticks = 0; - - NtQuerySystemTime( &when ); -- when.QuadPart += (ULONGLONG)250 * 10000; -+ when.QuadPart += (ULONGLONG)500 * 10000; - pTpSetTimer(timer2, &when, 0, 0); -- Sleep(50); -- when.QuadPart -= (ULONGLONG)150 * 10000; -- pTpSetTimer(timer1, &when, 0, 75); -+ Sleep(100); -+ when.QuadPart -= (ULONGLONG)300 * 10000; -+ pTpSetTimer(timer1, &when, 0, 150); - - result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); - result = WaitForSingleObject(semaphore, 1000); - ok(result == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", result); - ok(info1.ticks != 0 && info2.ticks != 0, "expected that ticks are nonzero\n"); -- ok(info2.ticks >= info1.ticks + 75 || broken(info2.ticks < info1.ticks + 75) /* Win 2008 */, -+ ok(info2.ticks >= info1.ticks + 150 || broken(info2.ticks < info1.ticks + 150) /* Win 2008 */, - "expected that timers are not merged\n"); - - /* timers will be merged */ --- -2.40.0 - diff --git a/patches/wine-hotfixes/staging-7.0/0002-bcrypt-Add-support-for-calculating-secret-ecc-keys.patch b/patches/wine-hotfixes/staging-7.0/0002-bcrypt-Add-support-for-calculating-secret-ecc-keys.patch deleted file mode 100644 index 84d698155..000000000 --- a/patches/wine-hotfixes/staging-7.0/0002-bcrypt-Add-support-for-calculating-secret-ecc-keys.patch +++ /dev/null @@ -1,476 +0,0 @@ -From 49f3ef13b3fd177293546918b13b843704de6536 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 1 Oct 2021 13:56:55 +0200 -Subject: [PATCH] bcrypt: Add support for calculating secret ecc keys. - ---- - configure.ac | 14 ++ - dlls/bcrypt/bcrypt_internal.h | 1 + - dlls/bcrypt/bcrypt_main.c | 6 + - dlls/bcrypt/gnutls.c | 241 +++++++++++++++++++++++++++++++++- - include/bcrypt.h | 1 + - 5 files changed, 260 insertions(+), 3 deletions(-) - -diff --git a/configure.ac b/configure.ac -index e24a6f02f59..36d5f39158d 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -47,6 +47,7 @@ AC_ARG_WITH(faudio, AS_HELP_STRING([--without-faudio],[do not use FAudio (XAu - AC_ARG_WITH(float-abi, AS_HELP_STRING([--with-float-abi=abi],[specify the ABI (soft|softfp|hard) for ARM platforms])) - AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig])) - AC_ARG_WITH(freetype, AS_HELP_STRING([--without-freetype],[do not use the FreeType library])) -+AC_ARG_WITH(gcrypt, AS_HELP_STRING([--without-gcrypt],[do not use libgcrypt])) - AC_ARG_WITH(gettext, AS_HELP_STRING([--without-gettext],[do not use gettext])) - AC_ARG_WITH(gettextpo, AS_HELP_STRING([--with-gettextpo],[use the GetTextPO library to rebuild po files]), - [if test "x$withval" = "xno"; then ac_cv_header_gettext_po_h=no; fi]) -@@ -2019,6 +2020,19 @@ WINE_NOTICE_WITH(vkd3d,[test "x$ac_cv_lib_soname_vkd3d" = "x"], - [vkd3d ${notice_platform}development files not found (or too old), Direct3D 12 won't be supported.]) - test "x$ac_cv_lib_soname_vkd3d" != "x" || enable_d3d12=${enable_d3d12:-no} - -+dnl **** Check for gcrypt **** -+if test "x$with_gcrypt" != "xno" -+then -+ WINE_PACKAGE_FLAGS(GCRYPT,[libgcrypt],,,, -+ [AC_CHECK_HEADERS([gcrypt.h]) -+ if test "$ac_cv_header_gcrypt_h" = "yes" -+ then -+ WINE_CHECK_SONAME(gcrypt,gcry_sexp_build,,,[$GCRYPT_LIBS]) -+ fi]) -+fi -+WINE_NOTICE_WITH(gcrypt,[test "x$ac_cv_lib_soname_gcrypt" = "x"], -+ [libgcrypt ${notice_platform}development files not found, GCRYPT won't be supported.]) -+ - dnl **** Check for gcc specific options **** - - AC_SUBST(EXTRACFLAGS,"") -diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h -index 6d8b3293d68..5569da34845 100644 ---- a/dlls/bcrypt/bcrypt_internal.h -+++ b/dlls/bcrypt/bcrypt_internal.h -@@ -131,6 +131,7 @@ enum alg_id - /* secret agreement */ - ALG_ID_DH, - ALG_ID_ECDH_P256, -+ ALG_ID_ECDH_P384, - - /* signature */ - ALG_ID_RSA_SIGN, -diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c -index d05301e9d23..0eb64365c7d 100644 ---- a/dlls/bcrypt/bcrypt_main.c -+++ b/dlls/bcrypt/bcrypt_main.c -@@ -113,6 +113,7 @@ builtin_algorithms[] = - { BCRYPT_RSA_ALGORITHM, BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE, 0, 0, 0 }, - { BCRYPT_DH_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, - { BCRYPT_ECDH_P256_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, -+ { BCRYPT_ECDH_P384_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, - { BCRYPT_RSA_SIGN_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, - { BCRYPT_ECDSA_P256_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, - { BCRYPT_ECDSA_P384_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, -@@ -1334,6 +1335,11 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP - magic = BCRYPT_ECDH_PUBLIC_P256_MAGIC; - break; - -+ case ALG_ID_ECDH_P384: -+ key_size = 48; -+ magic = BCRYPT_ECDH_PUBLIC_P384_MAGIC; -+ break; -+ - case ALG_ID_ECDSA_P256: - key_size = 32; - magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC; -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index 9c60e9a28e3..9f5e3fb788e 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -53,6 +53,10 @@ - #include - #endif - -+#ifdef HAVE_GCRYPT_H -+#include -+#endif -+ - - WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); - WINE_DECLARE_DEBUG_CHANNEL(winediag); -@@ -165,6 +169,24 @@ MAKE_FUNCPTR(mpz_mod); - MAKE_FUNCPTR(mpz_powm); - MAKE_FUNCPTR(mpz_sub_ui); - #endif -+ -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+static BOOL gcrypt_available; -+static void *libgcrypt_handle; -+ -+MAKE_FUNCPTR(gcry_check_version); -+MAKE_FUNCPTR(gcry_sexp_build); -+MAKE_FUNCPTR(gcry_pk_encrypt); -+MAKE_FUNCPTR(gcry_mpi_new); -+MAKE_FUNCPTR(gcry_mpi_print); -+MAKE_FUNCPTR(gcry_sexp_release); -+MAKE_FUNCPTR(gcry_mpi_release); -+MAKE_FUNCPTR(gcry_strsource); -+MAKE_FUNCPTR(gcry_strerror); -+MAKE_FUNCPTR(gcry_sexp_find_token); -+MAKE_FUNCPTR(gcry_sexp_nth_mpi); -+#endif -+ - #undef MAKE_FUNCPTR - - static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size) -@@ -335,6 +357,36 @@ static BOOL gnutls_initialize(void) - } - #undef LOAD_FUNCPTR - #undef LOAD_FUNCPTR_STR -+#endif -+ -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+#define LOAD_FUNCPTR(f) \ -+ if (!(p##f = dlsym( libgcrypt_handle, #f ))) \ -+ { \ -+ WARN( "failed to load %s\n", #f ); \ -+ gcrypt_available = FALSE; \ -+ } -+ -+ if ((libgcrypt_handle = dlopen( SONAME_LIBGCRYPT, RTLD_NOW ))) -+ { -+ gcrypt_available = TRUE; -+ -+ LOAD_FUNCPTR(gcry_check_version); -+ LOAD_FUNCPTR(gcry_sexp_build); -+ LOAD_FUNCPTR(gcry_pk_encrypt); -+ LOAD_FUNCPTR(gcry_mpi_new); -+ LOAD_FUNCPTR(gcry_mpi_print); -+ LOAD_FUNCPTR(gcry_sexp_release); -+ LOAD_FUNCPTR(gcry_mpi_release); -+ LOAD_FUNCPTR(gcry_strsource); -+ LOAD_FUNCPTR(gcry_strerror); -+ LOAD_FUNCPTR(gcry_sexp_find_token); -+ LOAD_FUNCPTR(gcry_sexp_nth_mpi); -+ } -+ else -+ WARN("failed to load gcrypt, no support for ECC secret agreement\n"); -+ -+#undef LOAD_FUNCPTR - #endif - - if (!(pgnutls_cipher_tag = dlsym( libgnutls_handle, "gnutls_cipher_tag" ))) -@@ -478,6 +530,11 @@ static void gnutls_uninitialize(void) - dlclose( libgmp_handle ); - libgmp_handle = NULL; - #endif -+ -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+ dlclose( libgcrypt_handle ); -+ libgcrypt_handle = NULL; -+#endif - } - - struct buffer -@@ -849,6 +906,10 @@ static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, enum alg_ - magic = BCRYPT_ECDH_PUBLIC_P256_MAGIC; - size = 32; - break; -+ case ALG_ID_ECDH_P384: -+ magic = BCRYPT_ECDH_PUBLIC_P384_MAGIC; -+ size = 48; -+ break; - case ALG_ID_ECDSA_P256: - magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC; - size = 32; -@@ -864,7 +925,7 @@ static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, enum alg_ - return STATUS_INTERNAL_ERROR; - } - -- if (curve != GNUTLS_ECC_CURVE_SECP256R1) -+ if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1) - { - FIXME( "curve %u not supported\n", curve ); - free( x.data ); free( y.data ); -@@ -1217,6 +1278,11 @@ static NTSTATUS CDECL key_asymmetric_generate( struct key *key ) - bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP256R1 ); - break; - -+ case ALG_ID_ECDH_P384: -+ pk_alg = GNUTLS_PK_ECC; -+ bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP384R1 ); -+ break; -+ - case ALG_ID_DH: - return key_dh_generate( key ); - -@@ -1283,6 +1349,10 @@ static NTSTATUS CDECL key_export_ecc( struct key *key, UCHAR *buf, ULONG len, UL - magic = BCRYPT_ECDH_PRIVATE_P256_MAGIC; - size = 32; - break; -+ case ALG_ID_ECDH_P384: -+ magic = BCRYPT_ECDH_PRIVATE_P384_MAGIC; -+ size = 48; -+ break; - case ALG_ID_ECDSA_P256: - magic = BCRYPT_ECDSA_PRIVATE_P256_MAGIC; - size = 32; -@@ -1299,7 +1369,7 @@ static NTSTATUS CDECL key_export_ecc( struct key *key, UCHAR *buf, ULONG len, UL - return STATUS_INTERNAL_ERROR; - } - -- if (curve != GNUTLS_ECC_CURVE_SECP256R1) -+ if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1) - { - FIXME( "curve %u not supported\n", curve ); - free( x.data ); free( y.data ); free( d.data ); -@@ -1553,6 +1623,7 @@ static NTSTATUS CDECL key_asymmetric_init( struct key *key ) - { - case ALG_ID_DH: - case ALG_ID_ECDH_P256: -+ case ALG_ID_ECDH_P384: - case ALG_ID_ECDSA_P256: - case ALG_ID_ECDSA_P384: - case ALG_ID_RSA: -@@ -2215,6 +2286,59 @@ static NTSTATUS CDECL key_asymmetric_decrypt( struct key *key, UCHAR *input, ULO - return status; - } - -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+static NTSTATUS gcrypt_extract_result_into_secret(gcry_sexp_t result, struct secret *secret) -+{ -+ NTSTATUS status = STATUS_SUCCESS; -+ gcry_mpi_t fullcoords = NULL; -+ gcry_sexp_t fragment = NULL; -+ UCHAR *tmp_buffer = NULL; -+ gcry_error_t err; -+ size_t size; -+ -+ fragment = pgcry_sexp_find_token(result, "s", 0); -+ if (!fragment) -+ { -+ status = STATUS_NO_MEMORY; -+ goto done; -+ } -+ -+ fullcoords = pgcry_sexp_nth_mpi(fragment, 1, GCRYMPI_FMT_USG); -+ if (!fullcoords) -+ { -+ status = STATUS_NO_MEMORY; -+ goto done; -+ } -+ -+ if ((err = pgcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &size, fullcoords))) -+ { -+ ERR("Error = %s/%s.\n", pgcry_strsource(err), pgcry_strerror(err)); -+ status = STATUS_INTERNAL_ERROR; -+ goto done; -+ } -+ -+ tmp_buffer = malloc(size); -+ if ((err = pgcry_mpi_print(GCRYMPI_FMT_STD, tmp_buffer, size, NULL, fullcoords))) -+ { -+ ERR("Error = %s/%s.\n", pgcry_strsource(err), pgcry_strerror(err)); -+ status = STATUS_INTERNAL_ERROR; -+ goto done; -+ } -+ -+ secret->data = malloc(size / 2); -+ memcpy(secret->data, tmp_buffer + size % 2, size / 2); -+ secret->data_len = size / 2; -+ -+done: -+ free(tmp_buffer); -+ -+ pgcry_mpi_release(fullcoords); -+ pgcry_sexp_release(fragment); -+ -+ return status; -+} -+#endif -+ - static NTSTATUS key_secret_agreement( void *args ) - { - struct key_secret_agreement_params *params = args; -@@ -2329,8 +2329,120 @@ static NTSTATUS key_secret_agreement( void *args ) - #endif - - case ALG_ID_ECDH_P256: -- FIXME("ECDH is not supported.\n"); -+ case ALG_ID_ECDH_P384: -+/* this is necessary since GNUTLS doesn't support ECDH public key encryption, maybe we can replace this when it does: -+ https://github.com/gnutls/gnutls/blob/cdc4fc288d87f91f974aa23b6e8595a53970ce00/lib/nettle/pk.c#L495 */ -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+ { -+ const char *pubkey_format; -+ DWORD key_size; -+ UCHAR *pubkey_raw; -+ gcry_sexp_t pubkey = NULL; -+ UCHAR *privkey_raw; -+ ULONG privkey_size; -+ gcry_sexp_t privkey = NULL; -+ gcry_sexp_t xchg_result = NULL; -+ gcry_error_t err; -+ NTSTATUS status = STATUS_SUCCESS; -+ -+ if (!gcrypt_available) -+ { -+ WARN("ECC secret support not available.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+ } -+ -+ if (priv_key->alg_id == ALG_ID_ECDH_P256) -+ { -+ pubkey_format = "NIST P-256"; -+ key_size = 32; -+ } -+ else if (priv_key->alg_id == ALG_ID_ECDH_P384) -+ { -+ pubkey_format = "NIST P-384"; -+ key_size = 48; -+ } -+ -+ /* copy public key into temporary buffer so we can prepend 0x04 (to indicate it is uncompressed) */ -+ pubkey_raw = malloc((key_size * 2) + 1); -+ pubkey_raw[0] = 0x04; -+ memcpy(pubkey_raw + 1, peer_key->u.a.pubkey + sizeof(BCRYPT_ECCKEY_BLOB), key_size * 2); -+ -+ err = pgcry_sexp_build(&pubkey, NULL, -+ "(key-data(public-key(ecdh(curve %s)(q %b))))", -+ pubkey_format, -+ (key_size * 2) + 1, -+ pubkey_raw); -+ -+ free(pubkey_raw); -+ -+ if (err) -+ { -+ ERR("Failed to build gcrypt public key. err %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ /* copy private key from gnutls to gcrypt */ -+ privkey_size = sizeof(BCRYPT_ECCKEY_BLOB) + key_size * 3; -+ privkey_raw = malloc(privkey_size); -+ status = key_export_ecc(priv_key, privkey_raw, privkey_size, &privkey_size); -+ -+ if (status) -+ { -+ ERR("Failed to extra gnutls private key\n"); -+ free(privkey_raw); -+ pgcry_sexp_release(pubkey); -+ return status; -+ } -+ -+ err = pgcry_sexp_build(&privkey, NULL, -+ "(data(flags raw)(value %b))", -+ key_size, -+ privkey_raw + sizeof(BCRYPT_ECCKEY_BLOB) + key_size * 2); -+ -+ free(privkey_raw); -+ -+ if (err) -+ { -+ ERR("Failed to build gcrypt private key. err %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); -+ pgcry_sexp_release(pubkey); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ err = pgcry_pk_encrypt(&xchg_result, privkey, pubkey); -+ -+ pgcry_sexp_release(privkey); -+ pgcry_sexp_release(pubkey); -+ -+ if (err) -+ { -+ ERR("Failed to perform key exchange. err %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ status = gcrypt_extract_result_into_secret(xchg_result, secret); -+ -+ pgcry_sexp_release(xchg_result); -+ -+ if (status) -+ { -+ ERR("Failed to extract secret key.\n"); -+ return status; -+ } -+ -+ if (secret->data_len != key_size) -+ { -+ ERR("got secret size %u, expected %u.\n", secret->data_len, key_size); -+ -+ free(secret->data); -+ return STATUS_INTERNAL_ERROR; -+ } -+ - break; -+ } -+#else -+ WARN("Compiled without ECC secret support.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+#endif - - default: - ERR( "unhandled algorithm %u\n", priv_key->alg_id ); -diff --git a/include/bcrypt.h b/include/bcrypt.h -index e485023abb0..fe69cee1667 100644 ---- a/include/bcrypt.h -+++ b/include/bcrypt.h -@@ -87,6 +87,7 @@ typedef LONG NTSTATUS; - #define BCRYPT_DH_ALGORITHM L"DH" - #define BCRYPT_DSA_ALGORITHM L"DSA" - #define BCRYPT_ECDH_P256_ALGORITHM L"ECDH_P256" -+#define BCRYPT_ECDH_P384_ALGORITHM L"ECDH_P384" - #define BCRYPT_ECDSA_P256_ALGORITHM L"ECDSA_P256" - #define BCRYPT_ECDSA_P384_ALGORITHM L"ECDSA_P384" - #define BCRYPT_ECDSA_P521_ALGORITHM L"ECDSA_P521" --- -2.33.0 -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index 903750f467f..fb488ba2640 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -2335,6 +2335,7 @@ static NTSTATUS key_secret_agreement( void *args ) - #if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) - { - const char *pubkey_format; -+ struct key_export_params key_export; - DWORD key_size; - UCHAR *pubkey_raw; - gcry_sexp_t pubkey = NULL; -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index 829de456113..903750f467f 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -2384,7 +2384,11 @@ static NTSTATUS key_secret_agreement( void *args ) - /* copy private key from gnutls to gcrypt */ - privkey_size = sizeof(BCRYPT_ECCKEY_BLOB) + key_size * 3; - privkey_raw = malloc(privkey_size); -- status = key_export_ecc(priv_key, privkey_raw, privkey_size, &privkey_size); -+ key_export.key = priv_key; -+ key_export.buf = privkey_raw; -+ key_export.len = privkey_size; -+ key_export.ret_len = &privkey_size; -+ status = key_export_ecc( &key_export ); - - if (status) - { -From 5bf7c820d5890f284fb6dac357ba46020678b588 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Wed, 10 Nov 2021 23:54:15 +0200 -Subject: [PATCH] fixup! bcrypt: Add support for calculating secret ecc keys. - ---- - include/bcrypt.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/bcrypt.h b/include/bcrypt.h -index fb7d809bc40..f84ab934ec6 100644 ---- a/include/bcrypt.h -+++ b/include/bcrypt.h -@@ -165,6 +165,7 @@ static const WCHAR BCRYPT_DES_ALGORITHM[] = {'D','E','S',0}; - static const WCHAR BCRYPT_DH_ALGORITHM[] = {'D','H',0}; - static const WCHAR BCRYPT_DSA_ALGORITHM[] = {'D','S','A',0}; - static const WCHAR BCRYPT_ECDH_P256_ALGORITHM[] = {'E','C','D','H','_','P','2','5','6',0}; -+static const WCHAR BCRYPT_ECDH_P384_ALGORITHM[] = {'E','C','D','H','_','P','3','8','4',0}; - static const WCHAR BCRYPT_ECDSA_P256_ALGORITHM[] = {'E','C','D','S','A','_','P','2','5','6',0}; - static const WCHAR BCRYPT_ECDSA_P384_ALGORITHM[] = {'E','C','D','S','A','_','P','3','8','4',0}; - static const WCHAR BCRYPT_ECDSA_P521_ALGORITHM[] = {'E','C','D','S','A','_','P','5','2','1',0}; diff --git a/patches/wine-hotfixes/staging-7.0/0003-bcrypt-Add-support-for-OAEP-padded-asymmetric-key-de.patch b/patches/wine-hotfixes/staging-7.0/0003-bcrypt-Add-support-for-OAEP-padded-asymmetric-key-de.patch deleted file mode 100644 index c52a7f6b2..000000000 --- a/patches/wine-hotfixes/staging-7.0/0003-bcrypt-Add-support-for-OAEP-padded-asymmetric-key-de.patch +++ /dev/null @@ -1,319 +0,0 @@ -From a77c5b4e730814371fccf9c29ee32eec9daa2788 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 1 Oct 2021 14:34:58 +0200 -Subject: [PATCH] bcrypt: Add support for OAEP-padded asymmetric key - decryption. - -For DayZ. - -CW-Bug-Id: #18973 ---- - dlls/bcrypt/bcrypt_internal.h | 13 +++ - dlls/bcrypt/bcrypt_main.c | 38 +++++---- - dlls/bcrypt/gnutls.c | 147 ++++++++++++++++++++++++++++++++++ - include/bcrypt.h | 7 ++ - 4 files changed, 191 insertions(+), 14 deletions(-) - -diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h -index 070dac30a8d..538d063941c 100644 ---- a/dlls/bcrypt/bcrypt_internal.h -+++ b/dlls/bcrypt/bcrypt_internal.h -@@ -236,6 +236,18 @@ struct key_symmetric_get_tag_params - ULONG len; - }; - -+struct key_asymmetric_encrypt_params -+{ -+ struct key *key; -+ void *padding; -+ UCHAR *input; -+ ULONG input_len; -+ UCHAR *output; -+ ULONG output_len; -+ ULONG *ret_len; -+ ULONG flags; -+}; -+ - struct key_asymmetric_decrypt_params - { - struct key *key; -@@ -308,6 +320,7 @@ enum key_funcs - unix_key_symmetric_get_tag, - unix_key_symmetric_destroy, - unix_key_asymmetric_generate, -+ unix_key_asymmetric_encrypt, - unix_key_asymmetric_decrypt, - unix_key_asymmetric_duplicate, - unix_key_asymmetric_sign, -diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c -index d01214c0ca0..479a3414c35 100644 ---- a/dlls/bcrypt/bcrypt_main.c -+++ b/dlls/bcrypt/bcrypt_main.c -@@ -575,7 +575,7 @@ static NTSTATUS get_rsa_property( enum mode_id mode, const WCHAR *prop, UCHAR *b - { - *ret_size = sizeof(ULONG); - if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; -- if (buf) *(ULONG *)buf = BCRYPT_SUPPORTED_PAD_PKCS1_SIG; -+ if (buf) *(ULONG *)buf = BCRYPT_SUPPORTED_PAD_PKCS1_SIG | BCRYPT_SUPPORTED_PAD_OAEP; - return STATUS_SUCCESS; - } - -@@ -1201,6 +1201,12 @@ static NTSTATUS key_symmetric_encrypt( struct key *key, UCHAR *input, ULONG inp - UCHAR *buf; - NTSTATUS status; - -+ if (flags & ~BCRYPT_BLOCK_PADDING) -+ { -+ FIXME( "flags %08x not implemented\n", flags ); -+ return STATUS_NOT_IMPLEMENTED; -+ } -+ - if (key->u.s.mode == MODE_ID_GCM) - { - BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding; -@@ -1968,28 +1968,32 @@ NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle ) - NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, - ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) - { -+ struct key_asymmetric_encrypt_params params; - struct key *key = handle; -- NTSTATUS ret; - - TRACE( "%p, %p, %lu, %p, %p, %lu, %p, %lu, %p, %#lx\n", handle, input, input_len, padding, iv, iv_len, output, - output_len, ret_len, flags ); - - if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE; -- if (!key_is_symmetric( key )) -- { -- FIXME( "encryption with asymmetric keys not yet supported\n" ); -- return STATUS_NOT_IMPLEMENTED; -- } -- if (flags & ~BCRYPT_BLOCK_PADDING) -+ -+ if (key_is_symmetric( key )) - { -- FIXME( "flags %#lx not implemented\n", flags ); -- return STATUS_NOT_IMPLEMENTED; -+ NTSTATUS ret; -+ EnterCriticalSection( &key->u.s.cs ); -+ ret = key_symmetric_encrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags ); -+ LeaveCriticalSection( &key->u.s.cs ); -+ return ret; - } - -- EnterCriticalSection( &key->u.s.cs ); -- ret = key_symmetric_encrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags ); -- LeaveCriticalSection( &key->u.s.cs ); -- return ret; -+ params.key = key; -+ params.input = input; -+ params.input_len = input_len; -+ params.output = output; -+ params.output_len = output_len; -+ params.ret_len = ret_len; -+ params.padding = padding; -+ params.flags = flags; -+ return UNIX_CALL( key_asymmetric_encrypt, ¶ms ); - } - - NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index 12d78fbb0d2..b843a72ad01 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -189,6 +189,7 @@ MAKE_FUNCPTR(gcry_strsource); - MAKE_FUNCPTR(gcry_strerror); - MAKE_FUNCPTR(gcry_sexp_find_token); - MAKE_FUNCPTR(gcry_sexp_nth_mpi); -+MAKE_FUNCPTR(gcry_sexp_nth_data); - #endif - - #undef MAKE_FUNCPTR -@@ -386,6 +387,7 @@ static NTSTATUS gnutls_process_attach( void *args ) - LOAD_FUNCPTR(gcry_strerror); - LOAD_FUNCPTR(gcry_sexp_find_token); - LOAD_FUNCPTR(gcry_sexp_nth_mpi); -+ LOAD_FUNCPTR(gcry_sexp_nth_data); - } - else - WARN("failed to load gcrypt, no support for ECC secret agreement\n"); -@@ -2113,6 +2115,150 @@ static NTSTATUS key_asymmetric_duplicate( void *args ) - return STATUS_SUCCESS; - } - -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+const char * gcrypt_hash_algorithm_name(LPCWSTR alg_id) -+{ -+ if (!wcscmp( alg_id, BCRYPT_SHA1_ALGORITHM )) return "sha1"; -+ if (!wcscmp( alg_id, BCRYPT_SHA256_ALGORITHM )) return "sha256"; -+ if (!wcscmp( alg_id, BCRYPT_SHA384_ALGORITHM )) return "sha384"; -+ if (!wcscmp( alg_id, BCRYPT_SHA512_ALGORITHM )) return "sha512"; -+ if (!wcscmp( alg_id, BCRYPT_MD2_ALGORITHM )) return "md2"; -+ if (!wcscmp( alg_id, BCRYPT_MD5_ALGORITHM )) return "md5"; -+ return NULL; -+} -+ -+static NTSTATUS key_asymmetric_encrypt( void *args ) -+{ -+ struct key_asymmetric_encrypt_params *params = args; -+ struct key *key = params->key; -+ BCRYPT_OAEP_PADDING_INFO *oaep_info = params->padding; -+ UCHAR *input = params->input; -+ ULONG input_len = params->input_len; -+ UCHAR *output = params->output; -+ ULONG output_len = params->output_len; -+ ULONG *ret_len = params->ret_len; -+ ULONG flags = params->flags; -+ NTSTATUS status = STATUS_SUCCESS; -+ gcry_sexp_t sexp_pubkey = NULL; -+ gcry_sexp_t sexp_result = NULL; -+ gcry_sexp_t sexp_input = NULL; -+ BCRYPT_RSAKEY_BLOB *rsa_blob; -+ gcry_sexp_t mpi_a = NULL; -+ const void *result; -+ size_t result_len; -+ gcry_error_t err; -+ -+ if (!gcrypt_available) -+ { -+ ERR("Asymmetric encryption not available.\n"); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ if (key->alg_id != ALG_ID_RSA) -+ { -+ FIXME("Unsupported algorithm id: %u\n", key->alg_id); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ /* import RSA key */ -+ rsa_blob = (BCRYPT_RSAKEY_BLOB *) key->u.a.pubkey; -+ err = pgcry_sexp_build(&sexp_pubkey, NULL, -+ "(public-key(rsa (e %b)(n %b)))", -+ rsa_blob->cbPublicExp, -+ (UCHAR *)(rsa_blob + 1), -+ rsa_blob->cbModulus, -+ (UCHAR *)(rsa_blob + 1) + rsa_blob->cbPublicExp); -+ if (err) -+ { -+ ERR("Failed to build gcrypt public key\n"); -+ goto done; -+ } -+ -+ /* import input data with necessary padding */ -+ if (flags == BCRYPT_PAD_PKCS1) -+ { -+ err = pgcry_sexp_build(&sexp_input, NULL, -+ "(data(flags pksc1)(value %b))", -+ input_len, -+ input); -+ } -+ else if (flags == BCRYPT_PAD_OAEP) -+ { -+ if (oaep_info->pbLabel) -+ err = pgcry_sexp_build(&sexp_input, NULL, -+ "(data(flags oaep)(hash-algo %s)(label %b)(value %b))", -+ gcrypt_hash_algorithm_name(oaep_info->pszAlgId), -+ oaep_info->cbLabel, -+ oaep_info->pbLabel, -+ input_len, -+ input); -+ else -+ err = pgcry_sexp_build(&sexp_input, NULL, -+ "(data(flags oaep)(hash-algo %s)(value %b))", -+ gcrypt_hash_algorithm_name(oaep_info->pszAlgId), -+ input_len, -+ input); -+ } -+ else if (flags == BCRYPT_PAD_NONE) -+ { -+ err = pgcry_sexp_build(&sexp_input, NULL, -+ "(data(flags raw)(value %b))", -+ input_len, -+ input); -+ } -+ else -+ { -+ status = STATUS_INVALID_PARAMETER; -+ goto done; -+ } -+ -+ if (err) -+ { -+ ERR("Failed to build gcrypt padded input data\n"); -+ goto done; -+ } -+ -+ if ((err = pgcry_pk_encrypt(&sexp_result, sexp_input, sexp_pubkey))) -+ { -+ ERR("Failed to encrypt data\n"); -+ goto done; -+ } -+ -+ mpi_a = pgcry_sexp_find_token(sexp_result, "a", 0); -+ result = pgcry_sexp_nth_data(mpi_a, 1, &result_len); -+ -+ *ret_len = result_len; -+ -+ if (output_len < result_len) -+ status = STATUS_BUFFER_TOO_SMALL; -+ else if (output) -+ memcpy(output, result, result_len); -+ -+done: -+ pgcry_sexp_release(sexp_input); -+ pgcry_sexp_release(sexp_pubkey); -+ pgcry_sexp_release(sexp_result); -+ pgcry_sexp_release(mpi_a); -+ -+ if (status) -+ return status; -+ -+ if (err) -+ { -+ ERR("Error = %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ return STATUS_SUCCESS; -+} -+#else -+static NTSTATUS key_asymmetric_encrypt( void *args ) -+{ -+ ERR("Asymmetric key encryption not supported without gcrypt.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+} -+#endif -+ - static NTSTATUS key_asymmetric_decrypt( void *args ) - { - struct key_asymmetric_decrypt_params *params = args; -@@ -2393,6 +2539,7 @@ unixlib_entry_t __wine_unix_call_funcs[] = - key_symmetric_get_tag, - key_symmetric_destroy, - key_asymmetric_generate, -+ key_asymmetric_encrypt, - key_asymmetric_decrypt, - key_asymmetric_duplicate, - key_asymmetric_sign, -diff --git a/include/bcrypt.h b/include/bcrypt.h -index 91647e0f333..928f2627073 100644 ---- a/include/bcrypt.h -+++ b/include/bcrypt.h -@@ -293,6 +293,13 @@ typedef struct _BCRYPT_PKCS1_PADDING_INFO - LPCWSTR pszAlgId; - } BCRYPT_PKCS1_PADDING_INFO; - -+typedef struct _BCRYPT_OAEP_PADING_INFO -+{ -+ LPCWSTR pszAlgId; -+ PUCHAR pbLabel; -+ ULONG cbLabel; -+} BCRYPT_OAEP_PADDING_INFO; -+ - #define BCRYPT_PAD_NONE 0x00000001 - #define BCRYPT_PAD_PKCS1 0x00000002 - #define BCRYPT_PAD_OAEP 0x00000004 --- -2.33.1 - diff --git a/patches/wine-hotfixes/staging-7.0/0020-stdole32.tlb-Compile-typelib-with-oldtlb.patch b/patches/wine-hotfixes/staging-7.0/0020-stdole32.tlb-Compile-typelib-with-oldtlb.patch deleted file mode 100644 index 7089aa268..000000000 --- a/patches/wine-hotfixes/staging-7.0/0020-stdole32.tlb-Compile-typelib-with-oldtlb.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff --git a/dlls/stdole32.tlb/Makefile.in b/dlls/stdole32.tlb/Makefile.in -index 6422325b3c7..226235a9218 100644 ---- a/dlls/stdole32.tlb/Makefile.in -+++ b/dlls/stdole32.tlb/Makefile.in -@@ -1,4 +1,5 @@ - MODULE = stdole32.tlb -+EXTRAIDLFLAGS = --oldtlb - - RC_SRCS = rsrc.rc - IDL_SRCS = std_ole_v1.idl diff --git a/patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/0001-cryptext-Implement-CryptExtOpenCER.patch b/patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/0001-cryptext-Implement-CryptExtOpenCER.patch deleted file mode 100644 index 65330304e..000000000 --- a/patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/0001-cryptext-Implement-CryptExtOpenCER.patch +++ /dev/null @@ -1,231 +0,0 @@ -From a5045503cf3310058cc64814ff9626f4877a13bb Mon Sep 17 00:00:00 2001 -From: Dmitry Timoshkov -Date: Fri, 5 Jul 2019 13:20:23 +0800 -Subject: [PATCH] cryptext: Implement CryptExtOpenCER. - -Signed-off-by: Dmitry Timoshkov ---- - configure | 1 + - configure.ac | 1 + - dlls/cryptext/Makefile.in | 3 +- - dlls/cryptext/cryptext.spec | 4 +-- - dlls/cryptext/cryptext_main.c | 64 +++++++++++++++++++++++++++++++++ - dlls/cryptext/tests/Makefile.in | 4 +++ - dlls/cryptext/tests/cryptext.c | 61 +++++++++++++++++++++++++++++++ - 7 files changed, 135 insertions(+), 3 deletions(-) - create mode 100644 dlls/cryptext/tests/Makefile.in - create mode 100644 dlls/cryptext/tests/cryptext.c - -diff --git a/configure b/configure -index db592f0868d..ba13abacc46 100755 ---- a/configure -+++ b/configure -@@ -20291,6 +20291,7 @@ wine_fn_config_makefile dlls/crypt32/tests enable_tests - wine_fn_config_makefile dlls/cryptdlg enable_cryptdlg - wine_fn_config_makefile dlls/cryptdll enable_cryptdll - wine_fn_config_makefile dlls/cryptext enable_cryptext -+wine_fn_config_makefile dlls/cryptext/tests enable_tests - wine_fn_config_makefile dlls/cryptnet enable_cryptnet - wine_fn_config_makefile dlls/cryptnet/tests enable_tests - wine_fn_config_makefile dlls/cryptsp enable_cryptsp -diff --git a/configure.ac b/configure.ac -index d449b88fb19..af75e0e80ab 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3029,6 +3029,7 @@ WINE_CONFIG_MAKEFILE(dlls/crypt32/tests) - WINE_CONFIG_MAKEFILE(dlls/cryptdlg) - WINE_CONFIG_MAKEFILE(dlls/cryptdll) - WINE_CONFIG_MAKEFILE(dlls/cryptext) -+WINE_CONFIG_MAKEFILE(dlls/cryptext/tests) - WINE_CONFIG_MAKEFILE(dlls/cryptnet) - WINE_CONFIG_MAKEFILE(dlls/cryptnet/tests) - WINE_CONFIG_MAKEFILE(dlls/cryptowinrt) -diff --git a/dlls/cryptext/Makefile.in b/dlls/cryptext/Makefile.in -index 0ec2b8a2045..76accca43eb 100644 ---- a/dlls/cryptext/Makefile.in -+++ b/dlls/cryptext/Makefile.in -@@ -1,4 +1,5 @@ --MODULE = cryptext.dll -+MODULE = cryptext.dll -+IMPORTS = crypt32 cryptui user32 - - EXTRADLLFLAGS = -Wb,--prefer-native - -diff --git a/dlls/cryptext/cryptext.spec b/dlls/cryptext/cryptext.spec -index ee3e155f457..24b4794c198 100644 ---- a/dlls/cryptext/cryptext.spec -+++ b/dlls/cryptext/cryptext.spec -@@ -12,8 +12,8 @@ - @ stub CryptExtAddSPCW - @ stub CryptExtOpenCAT - @ stub CryptExtOpenCATW --@ stub CryptExtOpenCER --@ stub CryptExtOpenCERW -+@ stdcall CryptExtOpenCER(long ptr str long) -+@ stdcall CryptExtOpenCERW(long ptr wstr long) - @ stub CryptExtOpenCRL - @ stub CryptExtOpenCRLW - @ stub CryptExtOpenCTL -diff --git a/dlls/cryptext/cryptext_main.c b/dlls/cryptext/cryptext_main.c -index 537ba66cd3b..f9e34d1f8c5 100644 ---- a/dlls/cryptext/cryptext_main.c -+++ b/dlls/cryptext/cryptext_main.c -@@ -22,10 +22,29 @@ - - #include "windef.h" - #include "winbase.h" -+#include "winnls.h" -+#include "wincrypt.h" -+#include "winuser.h" -+#include "cryptuiapi.h" -+ -+#include "wine/heap.h" - #include "wine/debug.h" - - WINE_DEFAULT_DEBUG_CHANNEL(cryptext); - -+static WCHAR *heap_strdupAtoW(const char *str) -+{ -+ WCHAR *ret; -+ INT len; -+ -+ if (!str) return NULL; -+ len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); -+ ret = heap_alloc(len * sizeof(WCHAR)); -+ if (ret) -+ MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); -+ return ret; -+} -+ - /*********************************************************************** - * CryptExtAddPFX (CRYPTEXT.@) - */ -@@ -43,3 +62,48 @@ HRESULT WINAPI CryptExtAddPFXW(LPCWSTR filename) - FIXME("stub: %s\n", debugstr_w(filename)); - return E_NOTIMPL; - } -+ -+/*********************************************************************** -+ * CryptExtOpenCERW (CRYPTEXT.@) -+ */ -+HRESULT WINAPI CryptExtOpenCERW(HWND hwnd, HINSTANCE hinst, LPCWSTR filename, DWORD showcmd) -+{ -+ PCCERT_CONTEXT ctx; -+ CRYPTUI_VIEWCERTIFICATE_STRUCTW info; -+ -+ TRACE("(%p, %p, %s, %u)\n", hwnd, hinst, debugstr_w(filename), showcmd); -+ -+ if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE, filename, CERT_QUERY_CONTENT_FLAG_CERT, -+ CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, NULL, NULL, NULL, -+ (const void **)&ctx)) -+ { -+ /* FIXME: move to the resources */ -+ static const WCHAR msg[] = {'T','h','i','s',' ','i','s',' ','n','o','t',' ','a',' ','v','a','l','i','d',' ','c','e','r','t','i','f','i','c','a','t','e',0}; -+ MessageBoxW(NULL, msg, filename, MB_OK | MB_ICONERROR); -+ return S_OK; /* according to the tests */ -+ } -+ -+ memset(&info, 0, sizeof(info)); -+ info.dwSize = sizeof(info); -+ info.pCertContext = ctx; -+ CryptUIDlgViewCertificateW(&info, NULL); -+ CertFreeCertificateContext(ctx); -+ -+ return S_OK; -+} -+ -+/*********************************************************************** -+ * CryptExtOpenCER (CRYPTEXT.@) -+ */ -+HRESULT WINAPI CryptExtOpenCER(HWND hwnd, HINSTANCE hinst, LPCSTR filename, DWORD showcmd) -+{ -+ HRESULT hr; -+ LPWSTR filenameW; -+ -+ TRACE("(%p, %p, %s, %u)\n", hwnd, hinst, debugstr_a(filename), showcmd); -+ -+ filenameW = heap_strdupAtoW(filename); -+ hr = CryptExtOpenCERW(hwnd, hinst, filenameW, showcmd); -+ heap_free(filenameW); -+ return hr; -+} -diff --git a/dlls/cryptext/tests/Makefile.in b/dlls/cryptext/tests/Makefile.in -new file mode 100644 -index 00000000000..522fc60a4af ---- /dev/null -+++ b/dlls/cryptext/tests/Makefile.in -@@ -0,0 +1,4 @@ -+TESTDLL = cryptext.dll -+ -+C_SRCS = \ -+ cryptext.c -diff --git a/dlls/cryptext/tests/cryptext.c b/dlls/cryptext/tests/cryptext.c -new file mode 100644 -index 00000000000..cc62a772b59 ---- /dev/null -+++ b/dlls/cryptext/tests/cryptext.c -@@ -0,0 +1,61 @@ -+/* -+ * Copyright 2019 Dmitry Timoshkov -+ * -+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "wine/test.h" -+ -+static HRESULT (WINAPI *pCryptExtOpenCER)(HWND,HINSTANCE,LPCSTR,DWORD); -+ -+static void test_CryptExtOpenCER(void) -+{ -+ HRESULT hr; -+ -+ if (!pCryptExtOpenCER) -+ { -+ win_skip("CryptExtOpenCER is not available on this platform\n"); -+ return; -+ } -+ -+ if (!winetest_interactive) -+ { -+ skip("CryptExtOpenCER test needs user interaction\n"); -+ return; -+ } -+ -+ SetLastError(0xdeadbeef); -+ hr = pCryptExtOpenCER(0, 0, "dead.beef", SW_HIDE); -+ ok(hr == S_OK, "got %#x\n", hr); -+ -+ hr = pCryptExtOpenCER(0, 0, "VeriSign Class 3 Public Primary Certification Authority - G4.txt", SW_SHOW); -+ ok(hr == S_OK, "got %#x\n", hr); -+} -+ -+START_TEST(cryptext) -+{ -+ HMODULE hmod = LoadLibraryA("cryptext.dll"); -+ -+ pCryptExtOpenCER = (void *)GetProcAddress(hmod, "CryptExtOpenCER"); -+ -+ test_CryptExtOpenCER(); -+} --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/definition b/patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/definition deleted file mode 100644 index 2b7bd7f87..000000000 --- a/patches/wine-hotfixes/staging-7.0/cryptext-CryptExtOpenCER/definition +++ /dev/null @@ -1,2 +0,0 @@ -# Taken from the mailing list - July 2019. -Fixes: cryptext: Implement CryptExtOpenCER. diff --git a/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0001-d3dx11_43-Implement-D3DX11GetImageInfoFromMemory.patch b/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0001-d3dx11_43-Implement-D3DX11GetImageInfoFromMemory.patch deleted file mode 100644 index 8a33821d3..000000000 --- a/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0001-d3dx11_43-Implement-D3DX11GetImageInfoFromMemory.patch +++ /dev/null @@ -1,254 +0,0 @@ -From ea3579b5b3d701647f5c7f16de658f1cd7fe876d Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Fri, 30 Jul 2021 15:57:29 +1000 -Subject: [PATCH] d3dx11_43: Implement D3DX11GetImageInfoFromMemory - -Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=50210 - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/d3dx11_42/Makefile.in | 1 + - dlls/d3dx11_43/Makefile.in | 1 + - dlls/d3dx11_43/main.c | 9 -- - dlls/d3dx11_43/texture.c | 176 +++++++++++++++++++++++++++++++++++++ - 4 files changed, 178 insertions(+), 9 deletions(-) - -diff --git a/dlls/d3dx11_42/Makefile.in b/dlls/d3dx11_42/Makefile.in -index 7fcce18a8e1..78ca5f707a7 100644 ---- a/dlls/d3dx11_42/Makefile.in -+++ b/dlls/d3dx11_42/Makefile.in -@@ -2,6 +2,7 @@ EXTRADEFS = -DD3DX11_SDK_VERSION=42 - MODULE = d3dx11_42.dll - IMPORTLIB = d3dx11_42 - IMPORTS = d3dcompiler -+DELAYIMPORTS = windowscodecs - PARENTSRC = ../d3dx11_43 - - EXTRADLLFLAGS = -Wb,--prefer-native -diff --git a/dlls/d3dx11_43/Makefile.in b/dlls/d3dx11_43/Makefile.in -index ccd4319ace2..6854c73ebcb 100644 ---- a/dlls/d3dx11_43/Makefile.in -+++ b/dlls/d3dx11_43/Makefile.in -@@ -2,6 +2,7 @@ EXTRADEFS = -DD3DX11_SDK_VERSION=43 - MODULE = d3dx11_43.dll - IMPORTLIB = d3dx11 - IMPORTS = d3dcompiler -+DELAYIMPORTS = windowscodecs - - EXTRADLLFLAGS = -Wb,--prefer-native - -diff --git a/dlls/d3dx11_43/main.c b/dlls/d3dx11_43/main.c -index 5dad027864f..00c1db35e42 100644 ---- a/dlls/d3dx11_43/main.c -+++ b/dlls/d3dx11_43/main.c -@@ -66,12 +66,3 @@ HRESULT WINAPI D3DX11GetImageInfoFromFileW(const WCHAR *filename, ID3DX11ThreadP - - return E_NOTIMPL; - } -- --HRESULT WINAPI D3DX11GetImageInfoFromMemory(const void *src_data, SIZE_T src_data_size, ID3DX11ThreadPump *pump, -- D3DX11_IMAGE_INFO *img_info, HRESULT *hresult) --{ -- FIXME("src_data %p, src_data_size %Iu, pump %p, img_info %p, hresult %p stub!\n", -- src_data, src_data_size, pump, img_info, hresult); -- -- return E_NOTIMPL; --} -diff --git a/dlls/d3dx11_43/texture.c b/dlls/d3dx11_43/texture.c -index 81ac8ee6db7..6881eec107d 100644 ---- a/dlls/d3dx11_43/texture.c -+++ b/dlls/d3dx11_43/texture.c -@@ -15,14 +15,190 @@ - * 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 "d3dx11.h" - #include "d3dcompiler.h" -+#include "wincodec.h" - - #include "wine/debug.h" - - WINE_DEFAULT_DEBUG_CHANNEL(d3dx); - -+HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT sdk_version, IWICImagingFactory **imaging_factory); -+ -+static const struct -+{ -+ const GUID *wic_container_guid; -+ D3DX11_IMAGE_FILE_FORMAT d3dx_file_format; -+} -+file_formats[] = -+{ -+ { &GUID_ContainerFormatBmp, D3DX11_IFF_BMP }, -+ { &GUID_ContainerFormatJpeg, D3DX11_IFF_JPG }, -+ { &GUID_ContainerFormatPng, D3DX11_IFF_PNG }, -+ { &GUID_ContainerFormatDds, D3DX11_IFF_DDS }, -+ { &GUID_ContainerFormatTiff, D3DX11_IFF_TIFF }, -+ { &GUID_ContainerFormatGif, D3DX11_IFF_GIF }, -+ { &GUID_ContainerFormatWmp, D3DX11_IFF_WMP }, -+}; -+ -+static D3DX11_IMAGE_FILE_FORMAT wic_container_guid_to_file_format(GUID *container_format) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(file_formats); ++i) -+ { -+ if (IsEqualGUID(file_formats[i].wic_container_guid, container_format)) -+ return file_formats[i].d3dx_file_format; -+ } -+ return D3DX11_IFF_FORCE_DWORD; -+} -+ -+static D3D11_RESOURCE_DIMENSION wic_dimension_to_d3dx11_dimension(WICDdsDimension wic_dimension) -+{ -+ switch (wic_dimension) -+ { -+ case WICDdsTexture1D: -+ return D3D11_RESOURCE_DIMENSION_TEXTURE1D; -+ case WICDdsTexture2D: -+ case WICDdsTextureCube: -+ return D3D11_RESOURCE_DIMENSION_TEXTURE2D; -+ case WICDdsTexture3D: -+ return D3D11_RESOURCE_DIMENSION_TEXTURE3D; -+ default: -+ return D3D11_RESOURCE_DIMENSION_UNKNOWN; -+ } -+} -+ -+static const DXGI_FORMAT to_be_converted_format[] = -+{ -+ DXGI_FORMAT_UNKNOWN, -+ DXGI_FORMAT_R8_UNORM, -+ DXGI_FORMAT_R8G8_UNORM, -+ DXGI_FORMAT_B5G6R5_UNORM, -+ DXGI_FORMAT_B4G4R4A4_UNORM, -+ DXGI_FORMAT_B5G5R5A1_UNORM, -+ DXGI_FORMAT_B8G8R8X8_UNORM, -+ DXGI_FORMAT_B8G8R8A8_UNORM -+}; -+ -+static DXGI_FORMAT get_d3dx11_dds_format(DXGI_FORMAT format) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(to_be_converted_format); ++i) -+ { -+ if (format == to_be_converted_format[i]) -+ return DXGI_FORMAT_R8G8B8A8_UNORM; -+ } -+ return format; -+} -+ -+HRESULT WINAPI D3DX11GetImageInfoFromMemory(const void *src_data, SIZE_T src_data_size, ID3DX11ThreadPump *pump, -+ D3DX11_IMAGE_INFO *img_info, HRESULT *hresult) -+{ -+ IWICBitmapFrameDecode *frame = NULL; -+ IWICImagingFactory *factory = NULL; -+ IWICDdsDecoder *dds_decoder = NULL; -+ IWICBitmapDecoder *decoder = NULL; -+ WICDdsParameters dds_params; -+ IWICStream *stream = NULL; -+ unsigned int frame_count; -+ GUID container_format; -+ HRESULT hr; -+ -+ TRACE("src_data %p, src_data_size %Iu, pump %p, img_info %p, hresult %p.\n", -+ src_data, src_data_size, pump, img_info, hresult); -+ -+ if (!src_data || !src_data_size || !img_info) -+ return E_FAIL; -+ if (pump) -+ FIXME("Thread pump is not supported yet.\n"); -+ -+ WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory); -+ IWICImagingFactory_CreateStream(factory, &stream); -+ hr = IWICStream_InitializeFromMemory(stream, (BYTE *)src_data, src_data_size); -+ if (FAILED(hr)) -+ { -+ WARN("Failed to initialize stream.\n"); -+ goto end; -+ } -+ hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream *)stream, NULL, 0, &decoder); -+ if (FAILED(hr)) -+ goto end; -+ -+ hr = IWICBitmapDecoder_GetContainerFormat(decoder, &container_format); -+ if (FAILED(hr)) -+ goto end; -+ img_info->ImageFileFormat = wic_container_guid_to_file_format(&container_format); -+ if (img_info->ImageFileFormat == D3DX11_IFF_FORCE_DWORD) -+ { -+ hr = E_FAIL; -+ WARN("Unsupported image file format %s.\n", debugstr_guid(&container_format)); -+ goto end; -+ } -+ -+ hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); -+ if (FAILED(hr) || !frame_count) -+ goto end; -+ hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); -+ if (FAILED(hr)) -+ goto end; -+ hr = IWICBitmapFrameDecode_GetSize(frame, &img_info->Width, &img_info->Height); -+ if (FAILED(hr)) -+ goto end; -+ -+ if (img_info->ImageFileFormat == D3DX11_IFF_DDS) -+ { -+ hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICDdsDecoder, (void **)&dds_decoder); -+ if (FAILED(hr)) -+ goto end; -+ hr = IWICDdsDecoder_GetParameters(dds_decoder, &dds_params); -+ if (FAILED(hr)) -+ goto end; -+ img_info->ArraySize = dds_params.ArraySize; -+ img_info->Depth = dds_params.Depth; -+ img_info->MipLevels = dds_params.MipLevels; -+ img_info->ResourceDimension = wic_dimension_to_d3dx11_dimension(dds_params.Dimension); -+ img_info->Format = get_d3dx11_dds_format(dds_params.DxgiFormat); -+ img_info->MiscFlags = 0; -+ if (dds_params.Dimension == WICDdsTextureCube) -+ { -+ img_info->MiscFlags = D3D11_RESOURCE_MISC_TEXTURECUBE; -+ img_info->ArraySize *= 6; -+ } -+ } -+ else -+ { -+ img_info->ArraySize = 1; -+ img_info->Depth = 1; -+ img_info->MipLevels = 1; -+ img_info->ResourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D; -+ img_info->Format = DXGI_FORMAT_R8G8B8A8_UNORM; -+ img_info->MiscFlags = 0; -+ } -+ -+end: -+ if (dds_decoder) -+ IWICDdsDecoder_Release(dds_decoder); -+ if (frame) -+ IWICBitmapFrameDecode_Release(frame); -+ if (decoder) -+ IWICBitmapDecoder_Release(decoder); -+ if (stream) -+ IWICStream_Release(stream); -+ if (factory) -+ IWICImagingFactory_Release(factory); -+ -+ if (hr != S_OK) -+ { -+ WARN("Invalid or unsupported image file.\n"); -+ return E_FAIL; -+ } -+ return S_OK; -+} -+ - HRESULT WINAPI D3DX11CreateShaderResourceViewFromMemory(ID3D11Device *device, const void *data, - SIZE_T data_size, D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, - ID3D11ShaderResourceView **view, HRESULT *hresult) --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0002-d3dx11_42-Implement-D3DX11CreateTextureFromMemory.patch b/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0002-d3dx11_42-Implement-D3DX11CreateTextureFromMemory.patch deleted file mode 100644 index 5861e406e..000000000 --- a/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/0002-d3dx11_42-Implement-D3DX11CreateTextureFromMemory.patch +++ /dev/null @@ -1,395 +0,0 @@ -From 5be34c9e347d4379179eeba742b25986152d4e4f Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Tue, 3 Aug 2021 11:13:18 +1000 -Subject: [PATCH] d3dx11_42: Implement D3DX11CreateTextureFromMemory - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/d3dx11_43/texture.c | 347 ++++++++++++++++++++++++++++++++++++++- - 1 file changed, 342 insertions(+), 5 deletions(-) - -diff --git a/dlls/d3dx11_43/texture.c b/dlls/d3dx11_43/texture.c -index 6881eec107d..b91bd8d881a 100644 ---- a/dlls/d3dx11_43/texture.c -+++ b/dlls/d3dx11_43/texture.c -@@ -22,6 +22,7 @@ - #include "wincodec.h" - - #include "wine/debug.h" -+#include "wine/heap.h" - - WINE_DEFAULT_DEBUG_CHANNEL(d3dx); - -@@ -43,6 +44,32 @@ file_formats[] = - { &GUID_ContainerFormatWmp, D3DX11_IFF_WMP }, - }; - -+static const struct -+{ -+ const GUID *wic_guid; -+ DXGI_FORMAT dxgi_format; -+} -+wic_pixel_formats[] = -+{ -+ { &GUID_WICPixelFormatBlackWhite, DXGI_FORMAT_R1_UNORM }, -+ { &GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM }, -+ { &GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM }, -+ { &GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM }, -+ { &GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT }, -+ { &GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT }, -+ { &GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM }, -+ { &GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM }, -+ { &GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, -+ { &GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, -+ { &GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM }, -+ { &GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM }, -+ { &GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, -+ { &GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM }, -+ { &GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT }, -+ { &GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT }, -+ { &GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT } -+}; -+ - static D3DX11_IMAGE_FILE_FORMAT wic_container_guid_to_file_format(GUID *container_format) - { - unsigned int i; -@@ -95,6 +122,175 @@ static DXGI_FORMAT get_d3dx11_dds_format(DXGI_FORMAT format) - return format; - } - -+static const DXGI_FORMAT block_compressed_formats[] = -+{ -+ DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB, -+ DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB, -+ DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB, -+ DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM, -+ DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM, -+ DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16, -+ DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB -+}; -+ -+static BOOL is_block_compressed(DXGI_FORMAT format) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(block_compressed_formats); ++i) -+ if (format == block_compressed_formats[i]) -+ return TRUE; -+ -+ return FALSE; -+} -+ -+static unsigned int get_bpp_from_format(DXGI_FORMAT format) -+{ -+ switch (format) -+ { -+ case DXGI_FORMAT_R32G32B32A32_TYPELESS: -+ case DXGI_FORMAT_R32G32B32A32_FLOAT: -+ case DXGI_FORMAT_R32G32B32A32_UINT: -+ case DXGI_FORMAT_R32G32B32A32_SINT: -+ return 128; -+ case DXGI_FORMAT_R32G32B32_TYPELESS: -+ case DXGI_FORMAT_R32G32B32_FLOAT: -+ case DXGI_FORMAT_R32G32B32_UINT: -+ case DXGI_FORMAT_R32G32B32_SINT: -+ return 96; -+ case DXGI_FORMAT_R16G16B16A16_TYPELESS: -+ case DXGI_FORMAT_R16G16B16A16_FLOAT: -+ case DXGI_FORMAT_R16G16B16A16_UNORM: -+ case DXGI_FORMAT_R16G16B16A16_UINT: -+ case DXGI_FORMAT_R16G16B16A16_SNORM: -+ case DXGI_FORMAT_R16G16B16A16_SINT: -+ case DXGI_FORMAT_R32G32_TYPELESS: -+ case DXGI_FORMAT_R32G32_FLOAT: -+ case DXGI_FORMAT_R32G32_UINT: -+ case DXGI_FORMAT_R32G32_SINT: -+ case DXGI_FORMAT_R32G8X24_TYPELESS: -+ case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: -+ case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: -+ case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: -+ case DXGI_FORMAT_Y416: -+ case DXGI_FORMAT_Y210: -+ case DXGI_FORMAT_Y216: -+ return 64; -+ case DXGI_FORMAT_R10G10B10A2_TYPELESS: -+ case DXGI_FORMAT_R10G10B10A2_UNORM: -+ case DXGI_FORMAT_R10G10B10A2_UINT: -+ case DXGI_FORMAT_R11G11B10_FLOAT: -+ case DXGI_FORMAT_R8G8B8A8_TYPELESS: -+ case DXGI_FORMAT_R8G8B8A8_UNORM: -+ case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: -+ case DXGI_FORMAT_R8G8B8A8_UINT: -+ case DXGI_FORMAT_R8G8B8A8_SNORM: -+ case DXGI_FORMAT_R8G8B8A8_SINT: -+ case DXGI_FORMAT_R16G16_TYPELESS: -+ case DXGI_FORMAT_R16G16_FLOAT: -+ case DXGI_FORMAT_R16G16_UNORM: -+ case DXGI_FORMAT_R16G16_UINT: -+ case DXGI_FORMAT_R16G16_SNORM: -+ case DXGI_FORMAT_R16G16_SINT: -+ case DXGI_FORMAT_R32_TYPELESS: -+ case DXGI_FORMAT_D32_FLOAT: -+ case DXGI_FORMAT_R32_FLOAT: -+ case DXGI_FORMAT_R32_UINT: -+ case DXGI_FORMAT_R32_SINT: -+ case DXGI_FORMAT_R24G8_TYPELESS: -+ case DXGI_FORMAT_D24_UNORM_S8_UINT: -+ case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: -+ case DXGI_FORMAT_X24_TYPELESS_G8_UINT: -+ case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: -+ case DXGI_FORMAT_R8G8_B8G8_UNORM: -+ case DXGI_FORMAT_G8R8_G8B8_UNORM: -+ case DXGI_FORMAT_B8G8R8A8_UNORM: -+ case DXGI_FORMAT_B8G8R8X8_UNORM: -+ case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: -+ case DXGI_FORMAT_B8G8R8A8_TYPELESS: -+ case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: -+ case DXGI_FORMAT_B8G8R8X8_TYPELESS: -+ case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: -+ case DXGI_FORMAT_AYUV: -+ case DXGI_FORMAT_Y410: -+ case DXGI_FORMAT_YUY2: -+ return 32; -+ case DXGI_FORMAT_P010: -+ case DXGI_FORMAT_P016: -+ return 24; -+ case DXGI_FORMAT_R8G8_TYPELESS: -+ case DXGI_FORMAT_R8G8_UNORM: -+ case DXGI_FORMAT_R8G8_UINT: -+ case DXGI_FORMAT_R8G8_SNORM: -+ case DXGI_FORMAT_R8G8_SINT: -+ case DXGI_FORMAT_R16_TYPELESS: -+ case DXGI_FORMAT_R16_FLOAT: -+ case DXGI_FORMAT_D16_UNORM: -+ case DXGI_FORMAT_R16_UNORM: -+ case DXGI_FORMAT_R16_UINT: -+ case DXGI_FORMAT_R16_SNORM: -+ case DXGI_FORMAT_R16_SINT: -+ case DXGI_FORMAT_B5G6R5_UNORM: -+ case DXGI_FORMAT_B5G5R5A1_UNORM: -+ case DXGI_FORMAT_A8P8: -+ case DXGI_FORMAT_B4G4R4A4_UNORM: -+ return 16; -+ case DXGI_FORMAT_NV12: -+ case DXGI_FORMAT_420_OPAQUE: -+ case DXGI_FORMAT_NV11: -+ return 12; -+ case DXGI_FORMAT_R8_TYPELESS: -+ case DXGI_FORMAT_R8_UNORM: -+ case DXGI_FORMAT_R8_UINT: -+ case DXGI_FORMAT_R8_SNORM: -+ case DXGI_FORMAT_R8_SINT: -+ case DXGI_FORMAT_A8_UNORM: -+ case DXGI_FORMAT_AI44: -+ case DXGI_FORMAT_IA44: -+ case DXGI_FORMAT_P8: -+ case DXGI_FORMAT_BC2_TYPELESS: -+ case DXGI_FORMAT_BC2_UNORM: -+ case DXGI_FORMAT_BC2_UNORM_SRGB: -+ case DXGI_FORMAT_BC3_TYPELESS: -+ case DXGI_FORMAT_BC3_UNORM: -+ case DXGI_FORMAT_BC3_UNORM_SRGB: -+ case DXGI_FORMAT_BC5_TYPELESS: -+ case DXGI_FORMAT_BC5_UNORM: -+ case DXGI_FORMAT_BC5_SNORM: -+ case DXGI_FORMAT_BC6H_TYPELESS: -+ case DXGI_FORMAT_BC6H_UF16: -+ case DXGI_FORMAT_BC6H_SF16: -+ case DXGI_FORMAT_BC7_TYPELESS: -+ case DXGI_FORMAT_BC7_UNORM: -+ case DXGI_FORMAT_BC7_UNORM_SRGB: -+ return 8; -+ case DXGI_FORMAT_BC1_TYPELESS: -+ case DXGI_FORMAT_BC1_UNORM: -+ case DXGI_FORMAT_BC1_UNORM_SRGB: -+ case DXGI_FORMAT_BC4_TYPELESS: -+ case DXGI_FORMAT_BC4_UNORM: -+ case DXGI_FORMAT_BC4_SNORM: -+ return 4; -+ case DXGI_FORMAT_R1_UNORM: -+ return 1; -+ default: -+ return 0; -+ } -+} -+ -+static const GUID *dxgi_format_to_wic_guid(DXGI_FORMAT format) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < ARRAY_SIZE(wic_pixel_formats); ++i) -+ { -+ if (wic_pixel_formats[i].dxgi_format == format) -+ return wic_pixel_formats[i].wic_guid; -+ } -+ -+ return NULL; -+} -+ - HRESULT WINAPI D3DX11GetImageInfoFromMemory(const void *src_data, SIZE_T src_data_size, ID3DX11ThreadPump *pump, - D3DX11_IMAGE_INFO *img_info, HRESULT *hresult) - { -@@ -229,14 +425,155 @@ HRESULT WINAPI D3DX11CreateTextureFromFileW(ID3D11Device *device, const WCHAR *f - return E_NOTIMPL; - } - --HRESULT WINAPI D3DX11CreateTextureFromMemory(ID3D11Device *device, const void *data, -- SIZE_T data_size, D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, -+HRESULT WINAPI D3DX11CreateTextureFromMemory(ID3D11Device *device, const void *src_data, -+ SIZE_T src_data_size, D3DX11_IMAGE_LOAD_INFO *load_info, ID3DX11ThreadPump *pump, - ID3D11Resource **texture, HRESULT *hresult) - { -- FIXME("device %p, data %p, data_size %Iu, load_info %p, pump %p, texture %p, hresult %p stub.\n", -- device, data, data_size, load_info, pump, texture, hresult); -+ unsigned int frame_count, width, height, stride, frame_size; -+ IWICFormatConverter *converter = NULL; -+ IWICDdsFrameDecode *dds_frame = NULL; -+ D3D11_TEXTURE2D_DESC texture_2d_desc; -+ D3D11_SUBRESOURCE_DATA resource_data; -+ IWICBitmapFrameDecode *frame = NULL; -+ IWICImagingFactory *factory = NULL; -+ IWICBitmapDecoder *decoder = NULL; -+ ID3D11Texture2D *texture_2d; -+ D3DX11_IMAGE_INFO img_info; -+ IWICStream *stream = NULL; -+ const GUID *dst_format; -+ BYTE *buffer = NULL; -+ BOOL can_convert; -+ GUID src_format; -+ HRESULT hr; - -- return E_NOTIMPL; -+ TRACE("device %p, data %p, data_size %Iu, load_info %p, pump %p, texture %p, hresult %p.\n", -+ device, src_data, src_data_size, load_info, pump, texture, hresult); -+ -+ if (!src_data || !src_data_size || !texture) -+ return E_FAIL; -+ if (load_info) -+ FIXME("load_info is ignored.\n"); -+ if (pump) -+ FIXME("Thread pump is not supported yet.\n"); -+ -+ if (FAILED(D3DX11GetImageInfoFromMemory(src_data, src_data_size, NULL, &img_info, NULL))) -+ return E_FAIL; -+ if (img_info.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) -+ { -+ FIXME("Cube map is not supported.\n"); -+ return E_FAIL; -+ } -+ -+ if (FAILED(hr = WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory))) -+ goto end; -+ if (FAILED(hr = IWICImagingFactory_CreateStream(factory, &stream))) -+ goto end; -+ if (FAILED(hr = IWICStream_InitializeFromMemory(stream, (BYTE *)src_data, src_data_size))) -+ goto end; -+ if (FAILED(hr = IWICImagingFactory_CreateDecoderFromStream(factory, (IStream *)stream, NULL, 0, &decoder))) -+ goto end; -+ if (FAILED(hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count)) || !frame_count) -+ goto end; -+ if (FAILED(hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame))) -+ goto end; -+ if (FAILED(hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &src_format))) -+ goto end; -+ -+ width = img_info.Width; -+ height = img_info.Height; -+ if (is_block_compressed(img_info.Format)) -+ { -+ width = (width + 3) & ~3; -+ height = (height + 3) & ~3; -+ } -+ stride = (width * get_bpp_from_format(img_info.Format) + 7) / 8; -+ frame_size = stride * height; -+ -+ if (!(buffer = heap_alloc(frame_size))) -+ { -+ hr = E_FAIL; -+ goto end; -+ } -+ -+ if (is_block_compressed(img_info.Format)) -+ { -+ if (FAILED(hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICDdsFrameDecode, (void **)&dds_frame))) -+ goto end; -+ if (FAILED(hr = IWICDdsFrameDecode_CopyBlocks(dds_frame, NULL, stride * 4, frame_size, buffer))) -+ goto end; -+ } -+ else -+ { -+ if (!(dst_format = dxgi_format_to_wic_guid(img_info.Format))) -+ { -+ hr = E_FAIL; -+ FIXME("Unsupported DXGI format %#x.\n", img_info.Format); -+ goto end; -+ } -+ -+ if (IsEqualGUID(&src_format, dst_format)) -+ { -+ if (FAILED(hr = IWICBitmapFrameDecode_CopyPixels(frame, NULL, stride, frame_size, buffer))) -+ goto end; -+ } -+ else -+ { -+ if (FAILED(hr = IWICImagingFactory_CreateFormatConverter(factory, &converter))) -+ goto end; -+ if (FAILED(hr = IWICFormatConverter_CanConvert(converter, &src_format, dst_format, &can_convert))) -+ goto end; -+ if (!can_convert) -+ { -+ WARN("Format converting %s to %s is not supported by WIC.\n", -+ debugstr_guid(&src_format), debugstr_guid(dst_format)); -+ goto end; -+ } -+ if (FAILED(hr = IWICFormatConverter_Initialize(converter, (IWICBitmapSource *)frame, dst_format, -+ WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom))) -+ goto end; -+ if (FAILED(hr = IWICFormatConverter_CopyPixels(converter, NULL, stride, frame_size, buffer))) -+ goto end; -+ } -+ } -+ -+ memset(&texture_2d_desc, 0, sizeof(texture_2d_desc)); -+ texture_2d_desc.Width = width; -+ texture_2d_desc.Height = height; -+ texture_2d_desc.MipLevels = 1; -+ texture_2d_desc.ArraySize = img_info.ArraySize; -+ texture_2d_desc.Format = img_info.Format; -+ texture_2d_desc.SampleDesc.Count = 1; -+ texture_2d_desc.Usage = D3D11_USAGE_DEFAULT; -+ texture_2d_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; -+ texture_2d_desc.MiscFlags = img_info.MiscFlags; -+ -+ resource_data.pSysMem = buffer; -+ resource_data.SysMemPitch = stride; -+ resource_data.SysMemSlicePitch = frame_size; -+ -+ if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_2d_desc, &resource_data, &texture_2d))) -+ goto end; -+ -+ *texture = (ID3D11Resource *)texture_2d; -+ hr = S_OK; -+ -+end: -+ if (converter) -+ IWICFormatConverter_Release(converter); -+ if (dds_frame) -+ IWICDdsFrameDecode_Release(dds_frame); -+ if (buffer) -+ heap_free(buffer); -+ if (frame) -+ IWICBitmapFrameDecode_Release(frame); -+ if (decoder) -+ IWICBitmapDecoder_Release(decoder); -+ if (stream) -+ IWICStream_Release(stream); -+ if (factory) -+ IWICImagingFactory_Release(factory); -+ -+ return hr; - } - - HRESULT WINAPI D3DX11SaveTextureToFileW(ID3D11DeviceContext *context, ID3D11Resource *texture, --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/definition b/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/definition deleted file mode 100644 index e8ee507f3..000000000 --- a/patches/wine-hotfixes/staging-7.0/d3dx11_43-D3DX11CreateTextureFromMemory/definition +++ /dev/null @@ -1,4 +0,0 @@ -Fixes: [50210] - Implement D3DX11GetImageInfoFromMemory -Fixes: [45533] - Implement D3DX11CreateTextureFromMemory - -# This patchset will need to wait until the new wined3dx dll implemented. diff --git a/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0001-fltmgr.sys-Implement-FltBuildDefaultSecurityDescript.patch b/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0001-fltmgr.sys-Implement-FltBuildDefaultSecurityDescript.patch deleted file mode 100644 index e3832d19a..000000000 --- a/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0001-fltmgr.sys-Implement-FltBuildDefaultSecurityDescript.patch +++ /dev/null @@ -1,143 +0,0 @@ -From f9da0ca4c7012918b5c8660ebe8a9ea0c74f05b0 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sun, 29 Aug 2021 13:26:53 +1000 -Subject: [PATCH] fltmgr.sys: Implement FltBuildDefaultSecurityDescriptor - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/fltmgr.sys/Makefile.in | 1 + - dlls/fltmgr.sys/fltmgr.sys.spec | 4 +- - dlls/fltmgr.sys/main.c | 71 +++++++++++++++++++++++++++++++++ - include/ddk/fltkernel.h | 3 +- - 4 files changed, 76 insertions(+), 3 deletions(-) - -diff --git a/dlls/fltmgr.sys/Makefile.in b/dlls/fltmgr.sys/Makefile.in -index ba106a43831..bb1f34b4896 100644 ---- a/dlls/fltmgr.sys/Makefile.in -+++ b/dlls/fltmgr.sys/Makefile.in -@@ -1,5 +1,6 @@ - MODULE = fltmgr.sys - EXTRADLLFLAGS = -Wl,--subsystem,native -+IMPORTS = ntoskrnl - - C_SRCS = \ - main.c -diff --git a/dlls/fltmgr.sys/fltmgr.sys.spec b/dlls/fltmgr.sys/fltmgr.sys.spec -index 39ce6798178..8943b9f85cf 100644 ---- a/dlls/fltmgr.sys/fltmgr.sys.spec -+++ b/dlls/fltmgr.sys/fltmgr.sys.spec -@@ -10,7 +10,7 @@ - @ stub FltAllocatePoolAlignedWithTag - @ stub FltAttachVolume - @ stub FltAttachVolumeAtAltitude --@ stub FltBuildDefaultSecurityDescriptor -+@ stdcall FltBuildDefaultSecurityDescriptor(ptr long) - @ stub FltCancelFileOpen - @ stub FltCancelIo - @ stub FltCbdqDisable -@@ -60,7 +60,7 @@ - @ stub FltFreeFileLock - @ stub FltFreeGenericWorkItem - @ stub FltFreePoolAlignedWithTag --@ stub FltFreeSecurityDescriptor -+@ stdcall FltFreeSecurityDescriptor(ptr) - @ stub FltFsControlFile - @ stub FltGetBottomInstance - @ stub FltGetContexts -diff --git a/dlls/fltmgr.sys/main.c b/dlls/fltmgr.sys/main.c -index e1016a4989c..ea9685b4308 100644 ---- a/dlls/fltmgr.sys/main.c -+++ b/dlls/fltmgr.sys/main.c -@@ -93,3 +93,74 @@ void* WINAPI FltGetRoutineAddress(LPCSTR name) - - return func; - } -+ -+NTSTATUS WINAPI FltBuildDefaultSecurityDescriptor(PSECURITY_DESCRIPTOR *descriptor, ACCESS_MASK access) -+{ -+ PACL dacl; -+ NTSTATUS ret = STATUS_INSUFFICIENT_RESOURCES; -+ ULONG sid_len; -+ PSID sid; -+ PSID sid_system; -+ PSECURITY_DESCRIPTOR sec_desc = NULL; -+ SID_IDENTIFIER_AUTHORITY auth = { SECURITY_NULL_SID_AUTHORITY }; -+ -+ *descriptor = NULL; -+ -+ ret = RtlAllocateAndInitializeSid(&auth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_GROUP_RID_ADMINS, -+ 0, 0, 0, 0, 0, 0, &sid); -+ if (ret != STATUS_SUCCESS) -+ goto done; -+ -+ ret = RtlAllocateAndInitializeSid(&auth, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &sid_system); -+ if (ret != STATUS_SUCCESS) -+ goto done; -+ -+ sid_len = SECURITY_DESCRIPTOR_MIN_LENGTH + sizeof(ACL) + -+ sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(sid) + -+ sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(sid_system); -+ -+ sec_desc = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, sid_len); -+ if (!sec_desc) -+ { -+ ret = STATUS_NO_MEMORY; -+ goto done; -+ } -+ -+ ret = RtlCreateSecurityDescriptor(sec_desc, SECURITY_DESCRIPTOR_REVISION); -+ if (ret != STATUS_SUCCESS) -+ goto done; -+ -+ dacl = (PACL)((char*)sec_desc + SECURITY_DESCRIPTOR_MIN_LENGTH); -+ ret = RtlCreateAcl(dacl, sid_len - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION); -+ if (ret != STATUS_SUCCESS) -+ goto done; -+ -+ ret = RtlAddAccessAllowedAce(dacl, ACL_REVISION, access, sid); -+ if (ret != STATUS_SUCCESS) -+ goto done; -+ -+ ret = RtlAddAccessAllowedAce(dacl, ACL_REVISION, access, sid_system); -+ if (ret != STATUS_SUCCESS) -+ goto done; -+ -+ ret = RtlSetDaclSecurityDescriptor(sec_desc, 1, dacl, 0); -+ if (ret == STATUS_SUCCESS) -+ *descriptor = sec_desc; -+ -+done: -+ if (ret != STATUS_SUCCESS && sec_desc != NULL) -+ RtlFreeHeap(GetProcessHeap(), 0, sec_desc); -+ -+ if (sid != NULL) -+ RtlFreeHeap(GetProcessHeap(), 0, sid); -+ -+ if (sid_system != NULL) -+ RtlFreeHeap(GetProcessHeap(), 0, sid_system); -+ -+ return ret; -+} -+ -+void WINAPI FltFreeSecurityDescriptor(PSECURITY_DESCRIPTOR descriptor) -+{ -+ RtlFreeHeap(GetProcessHeap(), 0, descriptor); -+} -\ No newline at end of file -diff --git a/include/ddk/fltkernel.h b/include/ddk/fltkernel.h -index 8ebebfa2e81..9ece0990810 100644 ---- a/include/ddk/fltkernel.h -+++ b/include/ddk/fltkernel.h -@@ -653,7 +653,8 @@ typedef struct _FLT_REGISTRATION - PFLT_SECTION_CONFLICT_NOTIFICATION_CALLBACK SectionNotificationCallback; - } FLT_REGISTRATION, *PFLT_REGISTRATION; - -- -+NTSTATUS WINAPI FltBuildDefaultSecurityDescriptor(PSECURITY_DESCRIPTOR *, ACCESS_MASK); -+void WINAPI FltFreeSecurityDescriptor(PSECURITY_DESCRIPTOR); - void* WINAPI FltGetRoutineAddress(LPCSTR name); - NTSTATUS WINAPI FltRegisterFilter(PDRIVER_OBJECT, const FLT_REGISTRATION *, PFLT_FILTER *); - NTSTATUS WINAPI FltStartFiltering(PFLT_FILTER); --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0002-fltmgr.sys-Create-import-library.patch b/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0002-fltmgr.sys-Create-import-library.patch deleted file mode 100644 index 57aab8bc9..000000000 --- a/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0002-fltmgr.sys-Create-import-library.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 36bb7032734a97c5b9d01ef96d595973ea16eb95 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Mon, 30 Aug 2021 15:15:35 +1000 -Subject: [PATCH] fltmgr.sys: Create import library - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/fltmgr.sys/Makefile.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/fltmgr.sys/Makefile.in b/dlls/fltmgr.sys/Makefile.in -index bb1f34b4896..5540df35d6a 100644 ---- a/dlls/fltmgr.sys/Makefile.in -+++ b/dlls/fltmgr.sys/Makefile.in -@@ -1,4 +1,5 @@ - MODULE = fltmgr.sys -+IMPORTLIB = fltmgr - EXTRADLLFLAGS = -Wl,--subsystem,native - IMPORTS = ntoskrnl - --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0003-ntoskrnl.exe-Add-FltBuildDefaultSecurityDescriptor-t.patch b/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0003-ntoskrnl.exe-Add-FltBuildDefaultSecurityDescriptor-t.patch deleted file mode 100644 index f37f2789f..000000000 --- a/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/0003-ntoskrnl.exe-Add-FltBuildDefaultSecurityDescriptor-t.patch +++ /dev/null @@ -1,117 +0,0 @@ -From ba211cf9d8ca7a462c24a62334813c68d41b3fc0 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Mon, 30 Aug 2021 15:16:06 +1000 -Subject: [PATCH] ntoskrnl.exe: Add FltBuildDefaultSecurityDescriptor test - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/ntoskrnl.exe/tests/Makefile.in | 2 +- - dlls/ntoskrnl.exe/tests/driver.c | 65 +++++++++++++++++++++++++++++ - 2 files changed, 66 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntoskrnl.exe/tests/Makefile.in b/dlls/ntoskrnl.exe/tests/Makefile.in -index 052a8618a81..9028a392002 100644 ---- a/dlls/ntoskrnl.exe/tests/Makefile.in -+++ b/dlls/ntoskrnl.exe/tests/Makefile.in -@@ -2,7 +2,7 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES - TESTDLL = ntoskrnl.exe - IMPORTS = advapi32 crypt32 newdev setupapi user32 wintrust ws2_32 hid - --driver_IMPORTS = winecrt0 ntoskrnl hal -+driver_IMPORTS = winecrt0 ntoskrnl hal fltmgr - driver_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native - driver2_IMPORTS = winecrt0 ntoskrnl hal - driver2_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native -diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c -index dabb3b73f15..187f00c8bcb 100644 ---- a/dlls/ntoskrnl.exe/tests/driver.c -+++ b/dlls/ntoskrnl.exe/tests/driver.c -@@ -32,6 +32,7 @@ - #include "ddk/ntddk.h" - #include "ddk/ntifs.h" - #include "ddk/wdm.h" -+#include "ddk/fltkernel.h" - - #include "driver.h" - -@@ -2338,6 +2339,69 @@ static void test_default_modules(void) - ok(dxgmms1, "Failed to find dxgmms1.sys\n"); - } - -+static void test_default_security(void) -+{ -+ PSECURITY_DESCRIPTOR sd = NULL; -+ NTSTATUS status; -+ PSID group = NULL, owner = NULL; -+ BOOLEAN isdefault, present; -+ PACL acl = NULL; -+ PACCESS_ALLOWED_ACE ace; -+ SID_IDENTIFIER_AUTHORITY auth = { SECURITY_NULL_SID_AUTHORITY }; -+ PSID sid1, sid2; -+ -+ status = FltBuildDefaultSecurityDescriptor(&sd, STANDARD_RIGHTS_ALL); -+ ok(status == STATUS_SUCCESS, "got %#x\n", status); -+ ok(sd != NULL, "Failed to return descriptor\n"); -+ -+ status = RtlGetGroupSecurityDescriptor(sd, &group, &isdefault); -+ ok(status == STATUS_SUCCESS, "got %#x\n", status); -+ ok(group == NULL, "group isn't NULL\n"); -+ -+ status = RtlGetOwnerSecurityDescriptor(sd, &owner, &isdefault); -+ ok(status == STATUS_SUCCESS, "got %#x\n", status); -+ ok(owner == NULL, "owner isn't NULL\n"); -+ -+ status = RtlGetDaclSecurityDescriptor(sd, &present, &acl, &isdefault); -+ ok(status == STATUS_SUCCESS, "got %#x\n", status); -+ ok(acl != NULL, "acl is NULL\n"); -+ ok(acl->AceCount == 2, "got %d\n", acl->AceCount); -+ -+ sid1 = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, RtlLengthRequiredSid(2)); -+ RtlInitializeSid(sid1, &auth, 2); -+ *RtlSubAuthoritySid(sid1, 0) = SECURITY_BUILTIN_DOMAIN_RID; -+ *RtlSubAuthoritySid(sid1, 1) = DOMAIN_GROUP_RID_ADMINS; -+ -+ sid2 = RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, RtlLengthRequiredSid(1)); -+ RtlInitializeSid(sid2, &auth, 1); -+ *RtlSubAuthoritySid(sid2, 0) = SECURITY_LOCAL_SYSTEM_RID; -+ -+ /* SECURITY_BUILTIN_DOMAIN_RID */ -+ status = RtlGetAce(acl, 0, (void**)&ace); -+ ok(status == STATUS_SUCCESS, "got %#x\n", status); -+ -+ ok(ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, "got %#x\n", ace->Header.AceType); -+ ok(ace->Header.AceFlags == 0, "got %#x\n", ace->Header.AceFlags); -+ ok(ace->Mask == STANDARD_RIGHTS_ALL, "got %#x\n", ace->Mask); -+ -+ ok(RtlEqualSid(sid1, (PSID)&ace->SidStart), "SID not equal\n"); -+ -+ /* SECURITY_LOCAL_SYSTEM_RID */ -+ status = RtlGetAce(acl, 1, (void**)&ace); -+ ok(status == STATUS_SUCCESS, "got %#x\n", status); -+ -+ ok(ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, "got %#x\n", ace->Header.AceType); -+ ok(ace->Header.AceFlags == 0, "got %#x\n", ace->Header.AceFlags); -+ ok(ace->Mask == STANDARD_RIGHTS_ALL, "got %#x\n", ace->Mask); -+ -+ ok(RtlEqualSid(sid2, (PSID)&ace->SidStart), "SID not equal\n"); -+ -+ RtlFreeHeap(GetProcessHeap(), 0, sid1); -+ RtlFreeHeap(GetProcessHeap(), 0, sid2); -+ -+ FltFreeSecurityDescriptor(sd); -+} -+ - static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack) - { - void *buffer = irp->AssociatedIrp.SystemBuffer; -@@ -2382,6 +2446,7 @@ static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *st - test_dpc(); - test_process_memory(test_input); - test_permanence(); -+ test_default_security(); - - IoMarkIrpPending(irp); - IoQueueWorkItem(work_item, main_test_task, DelayedWorkQueue, irp); --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/definition b/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/definition deleted file mode 100644 index 407756977..000000000 --- a/patches/wine-hotfixes/staging-7.0/fltmgr.sys-FltBuildDefaultSecurityDescriptor/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [49089] fltmgr.sys: Implement FltBuildDefaultSecurityDescriptor -Depends: winedevice-Default_Drivers diff --git a/patches/wine-hotfixes/staging-7.0/inseng-Implementation/0001-inseng-Implement-CIF-reader-and-download-functions.patch b/patches/wine-hotfixes/staging-7.0/inseng-Implementation/0001-inseng-Implement-CIF-reader-and-download-functions.patch deleted file mode 100644 index 44d277659..000000000 --- a/patches/wine-hotfixes/staging-7.0/inseng-Implementation/0001-inseng-Implement-CIF-reader-and-download-functions.patch +++ /dev/null @@ -1,3866 +0,0 @@ -From eee60c1777c710cfcb4283922990a306361548ba Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Mon, 5 Sep 2016 15:31:29 +0200 -Subject: [PATCH] inseng: Implement CIF reader and download functions. - -FIXME: Needs splitting. ---- - dlls/inseng/Makefile.in | 7 +- - dlls/inseng/icif.c | 1745 ++++++++++++++++++++++++++++++++++ - dlls/inseng/inf.c | 443 +++++++++ - dlls/inseng/inseng.spec | 4 +- - dlls/inseng/inseng_main.c | 990 ++++++++++++++++++- - dlls/inseng/inseng_private.h | 79 ++ - include/inseng.idl | 276 +++++- - 7 files changed, 3490 insertions(+), 54 deletions(-) - create mode 100644 dlls/inseng/icif.c - create mode 100644 dlls/inseng/inf.c - create mode 100644 dlls/inseng/inseng_private.h - -diff --git a/dlls/inseng/Makefile.in b/dlls/inseng/Makefile.in -index 0217203791a..ba2388c97ed 100644 ---- a/dlls/inseng/Makefile.in -+++ b/dlls/inseng/Makefile.in -@@ -1,8 +1,11 @@ - MODULE = inseng.dll --IMPORTS = uuid ole32 advapi32 -+IMPORTS = uuid ole32 advapi32 urlmon shlwapi - - EXTRADLLFLAGS = -Wb,--prefer-native - --C_SRCS = inseng_main.c -+C_SRCS = \ -+ icif.c \ -+ inf.c \ -+ inseng_main.c - - IDL_SRCS = inseng_classes.idl -diff --git a/dlls/inseng/icif.c b/dlls/inseng/icif.c -new file mode 100644 -index 00000000000..11a91b86476 ---- /dev/null -+++ b/dlls/inseng/icif.c -@@ -0,0 +1,1745 @@ -+/* -+ * Copyright 2016 Michael Müller -+ * -+ * 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 -+#include -+ -+#include "windef.h" -+#include "winbase.h" -+#include "winuser.h" -+#include "ole2.h" -+#include "rpcproxy.h" -+#include "inseng.h" -+ -+#include "inseng_private.h" -+ -+#include "wine/list.h" -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(inseng); -+ -+#define DEFAULT_INSTALLER_DESC "Active Setup Installation" -+ -+struct cifgroup -+{ -+ ICifGroup ICifGroup_iface; -+ -+ struct list entry; -+ -+ ICifFile *parent; -+ -+ char *id; -+ char *description; -+ DWORD priority; -+}; -+ -+struct ciffenum_components -+{ -+ IEnumCifComponents IEnumCifComponents_iface; -+ LONG ref; -+ -+ ICifFile *file; -+ struct list *start; -+ struct list *position; -+ -+ char *group_id; -+}; -+ -+struct ciffenum_groups -+{ -+ IEnumCifGroups IEnumCifGroups_iface; -+ LONG ref; -+ -+ ICifFile *file; -+ struct list *start; -+ struct list *position; -+}; -+ -+struct url_info -+{ -+ struct list entry; -+ INT index; -+ char *url; -+ DWORD flags; -+}; -+ -+struct dependency_info -+{ -+ struct list entry; -+ char *id; -+ char *type; -+}; -+ -+struct cifcomponent -+{ -+ ICifComponent ICifComponent_iface; -+ -+ struct list entry; -+ -+ ICifFile *parent; -+ -+ char *id; -+ char *guid; -+ char *description; -+ char *details; -+ char *group; -+ -+ -+ DWORD version; -+ DWORD build; -+ char *patchid; -+ -+ char *locale; -+ char *key_uninstall; -+ -+ DWORD size_win; -+ DWORD size_app; -+ DWORD size_download; -+ DWORD size_extracted; -+ -+ char *key_success; -+ char *key_progress; -+ char *key_cancel; -+ -+ DWORD as_aware; -+ DWORD reboot; -+ DWORD admin; -+ DWORD visibleui; -+ -+ DWORD priority; -+ DWORD platform; -+ -+ struct list dependencies; -+ struct list urls; -+ -+ /* mode */ -+ /* det version */ -+ /* one component */ -+ /* custom data */ -+ -+ /* in memory state */ -+ DWORD queue_state; -+ DWORD current_priority; -+ DWORD size_actual_download; -+ BOOL downloaded; -+ BOOL installed; -+}; -+ -+struct ciffile -+{ -+ ICifFile ICifFile_iface; -+ LONG ref; -+ -+ struct list components; -+ struct list groups; -+ -+ char *name; -+}; -+ -+static inline struct ciffile *impl_from_ICiffile(ICifFile *iface) -+{ -+ return CONTAINING_RECORD(iface, struct ciffile, ICifFile_iface); -+} -+ -+static inline struct cifcomponent *impl_from_ICifComponent(ICifComponent *iface) -+{ -+ return CONTAINING_RECORD(iface, struct cifcomponent, ICifComponent_iface); -+} -+ -+static inline struct cifgroup *impl_from_ICifGroup(ICifGroup *iface) -+{ -+ return CONTAINING_RECORD(iface, struct cifgroup, ICifGroup_iface); -+} -+ -+static inline struct ciffenum_components *impl_from_IEnumCifComponents(IEnumCifComponents *iface) -+{ -+ return CONTAINING_RECORD(iface, struct ciffenum_components, IEnumCifComponents_iface); -+} -+ -+static inline struct ciffenum_groups *impl_from_IEnumCifGroups(IEnumCifGroups *iface) -+{ -+ return CONTAINING_RECORD(iface, struct ciffenum_groups, IEnumCifGroups_iface); -+} -+ -+static HRESULT enum_components_create(ICifFile *file, struct list *start, char *group_id, IEnumCifComponents **iface); -+ -+static HRESULT copy_substring_null(char *dest, int max_len, char *src) -+{ -+ if (!src) -+ return E_FAIL; -+ -+ if (max_len <= 0) -+ return S_OK; -+ -+ if (!dest) -+ return E_FAIL; -+ -+ while (*src && max_len-- > 1) -+ *dest++ = *src++; -+ *dest = 0; -+ -+ return S_OK; -+} -+ -+static void url_entry_free(struct url_info *url) -+{ -+ heap_free(url->url); -+ heap_free(url); -+} -+ -+static void dependency_entry_free(struct dependency_info *dependency) -+{ -+ heap_free(dependency->id); -+ heap_free(dependency); -+} -+ -+static void component_free(struct cifcomponent *comp) -+{ -+ struct dependency_info *dependency, *dependency_next; -+ struct url_info *url, *url_next; -+ -+ heap_free(comp->id); -+ heap_free(comp->guid); -+ heap_free(comp->description); -+ heap_free(comp->details); -+ heap_free(comp->group); -+ -+ heap_free(comp->patchid); -+ -+ heap_free(comp->locale); -+ heap_free(comp->key_uninstall); -+ -+ heap_free(comp->key_success); -+ heap_free(comp->key_progress); -+ heap_free(comp->key_cancel); -+ -+ LIST_FOR_EACH_ENTRY_SAFE(dependency, dependency_next, &comp->dependencies, struct dependency_info, entry) -+ { -+ list_remove(&dependency->entry); -+ dependency_entry_free(dependency); -+ } -+ -+ LIST_FOR_EACH_ENTRY_SAFE(url, url_next, &comp->urls, struct url_info, entry) -+ { -+ list_remove(&url->entry); -+ url_entry_free(url); -+ } -+ -+ heap_free(comp); -+} -+ -+static void group_free(struct cifgroup *group) -+{ -+ heap_free(group->id); -+ heap_free(group->description); -+ heap_free(group); -+} -+ -+static HRESULT WINAPI group_GetID(ICifGroup *iface, char *id, DWORD size) -+{ -+ struct cifgroup *This = impl_from_ICifGroup(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, id, size); -+ -+ return copy_substring_null(id, size, This->id); -+} -+ -+static HRESULT WINAPI group_GetDescription(ICifGroup *iface, char *desc, DWORD size) -+{ -+ struct cifgroup *This = impl_from_ICifGroup(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, desc, size); -+ -+ return copy_substring_null(desc, size, This->description); -+} -+ -+static DWORD WINAPI group_GetPriority(ICifGroup *iface) -+{ -+ struct cifgroup *This = impl_from_ICifGroup(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->priority; -+} -+ -+static HRESULT WINAPI group_EnumComponents(ICifGroup *iface, IEnumCifComponents **enum_components, DWORD filter, LPVOID pv) -+{ -+ struct cifgroup *This = impl_from_ICifGroup(iface); -+ struct ciffile *file; -+ -+ TRACE("(%p)->(%p, %u, %p)\n", This, enum_components, filter, pv); -+ -+ if (filter) -+ FIXME("filter (%x) not supported\n", filter); -+ if (pv) -+ FIXME("how to handle pv (%p)?\n", pv); -+ -+ file = impl_from_ICiffile(This->parent); -+ return enum_components_create(This->parent, &file->components, This->id, enum_components); -+} -+ -+static DWORD WINAPI group_GetCurrentPriority(ICifGroup *iface) -+{ -+ struct cifgroup *This = impl_from_ICifGroup(iface); -+ -+ FIXME("(%p): stub\n", This); -+ -+ return 0; -+} -+ -+static const ICifGroupVtbl cifgroupVtbl = -+{ -+ group_GetID, -+ group_GetDescription, -+ group_GetPriority, -+ group_EnumComponents, -+ group_GetCurrentPriority, -+}; -+ -+void component_set_actual_download_size(ICifComponent *iface, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ This->size_actual_download = size; -+} -+ -+void component_set_downloaded(ICifComponent *iface, BOOL value) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ This->downloaded = value; -+} -+ -+void component_set_installed(ICifComponent *iface, BOOL value) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ This->installed = value; -+} -+ -+char *component_get_id(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ return This->id; -+} -+ -+static HRESULT WINAPI component_GetID(ICifComponent *iface, char *id, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, id, size); -+ -+ return copy_substring_null(id, size, This->id); -+} -+ -+static HRESULT WINAPI component_GetGUID(ICifComponent *iface, char *guid, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, guid, size); -+ -+ return copy_substring_null(guid, size, This->guid); -+} -+ -+static HRESULT WINAPI component_GetDescription(ICifComponent *iface, char *desc, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, desc, size); -+ -+ return copy_substring_null(desc, size, This->description); -+} -+ -+static HRESULT WINAPI component_GetDetails(ICifComponent *iface, char *details, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, details, size); -+ -+ return copy_substring_null(details, size, This->details); -+} -+ -+static HRESULT WINAPI component_GetUrl(ICifComponent *iface, UINT index, char *url, DWORD size, DWORD *flags) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ struct url_info *entry; -+ -+ TRACE("(%p)->(%u, %p, %u, %p)\n", This, index, url, size, flags); -+ -+ /* FIXME: check how functions behaves for url == NULL */ -+ -+ if (!flags) -+ return E_FAIL; -+ -+ LIST_FOR_EACH_ENTRY(entry, &This->urls, struct url_info, entry) -+ { -+ if (entry->index != index) -+ continue; -+ -+ *flags = entry->flags; -+ return copy_substring_null(url, size, entry->url); -+ } -+ -+ return E_FAIL; -+} -+ -+static HRESULT WINAPI component_GetFileExtractList(ICifComponent *iface, UINT index, char *list, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ FIXME("(%p)->(%u, %p, %u): stub\n", This, index, list, size); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI component_GetUrlCheckRange(ICifComponent *iface, UINT index, DWORD *min, DWORD *max) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ FIXME("(%p)->(%u, %p, %p): stub\n", This, index, min, max); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI component_GetCommand(ICifComponent *iface, UINT index, char *cmd, DWORD cmd_size, char *switches, DWORD switch_size, DWORD *type) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ FIXME("(%p)->(%u, %p, %u, %p, %u, %p): stub\n", This, index, cmd, cmd_size, switches, switch_size, type); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI component_GetVersion(ICifComponent *iface, DWORD *version, DWORD *build) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %p)\n", This, version, build); -+ -+ if (!version || !build) -+ return E_FAIL; -+ -+ *version = This->version; -+ *build = This->build; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI component_GetLocale(ICifComponent *iface, char *locale, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, locale, size); -+ -+ return copy_substring_null(locale, size, This->locale); -+} -+ -+static HRESULT WINAPI component_GetUninstallKey(ICifComponent *iface, char *key, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, key, size); -+ -+ return copy_substring_null(key, size, This->key_uninstall); -+} -+ -+static HRESULT WINAPI component_GetInstalledSize(ICifComponent *iface, DWORD *win, DWORD *app) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %p)\n", This, win, app); -+ -+ if (!win || !app) -+ return E_FAIL; -+ -+ *win = This->size_win; -+ *app = This->size_app; -+ -+ return S_OK; -+} -+ -+static DWORD WINAPI component_GetDownloadSize(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->size_download; -+} -+ -+static DWORD WINAPI component_GetExtractSize(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->size_extracted; -+} -+ -+static HRESULT WINAPI component_GetSuccessKey(ICifComponent *iface, char *key, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, key, size); -+ -+ return copy_substring_null(key, size, This->key_success); -+} -+ -+static HRESULT WINAPI component_GetProgressKeys(ICifComponent *iface, char *progress, DWORD progress_size, -+ char *cancel, DWORD cancel_size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ HRESULT hr; -+ -+ TRACE("(%p)->(%p, %u, %p, %u): semi-stub\n", This, progress, progress_size, cancel, cancel_size); -+ -+ hr = copy_substring_null(progress, progress_size, This->key_progress); -+ if (hr != S_OK) return hr; -+ -+ if (cancel_size > 0 && cancel) -+ *cancel = 0; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI component_IsActiveSetupAware(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->as_aware ? S_OK : S_FALSE; -+} -+ -+static HRESULT WINAPI component_IsRebootRequired(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->reboot ? S_OK : S_FALSE; -+} -+ -+static HRESULT WINAPI component_RequiresAdminRights(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->admin ? S_OK : S_FALSE; -+} -+ -+static DWORD WINAPI component_GetPriority(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->priority; -+} -+ -+static HRESULT WINAPI component_GetDependency(ICifComponent *iface, UINT index, char *id, DWORD id_size, char *type, DWORD *ver, DWORD *build) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ struct dependency_info *entry; -+ ICifComponent *dependency; -+ int pos = 0; -+ -+ TRACE("(%p)->(%u, %p, %u, %p, %p, %p)\n", This, index, id, id_size, type, ver, build); -+ -+ if (!id || !ver || !build) -+ return E_FAIL; -+ -+ LIST_FOR_EACH_ENTRY(entry, &This->dependencies, struct dependency_info, entry) -+ { -+ if (pos++ < index) -+ continue; -+ -+ if (ICifFile_FindComponent(This->parent, entry->id, &dependency) == S_OK) -+ { -+ ICifComponent_GetVersion(dependency, ver, build); -+ } -+ else -+ { -+ *ver = -1; -+ *build = -1; -+ } -+ -+ if (entry->type) -+ *type = *entry->type; -+ else -+ *type = 'I'; -+ -+ return copy_substring_null(id, id_size, entry->id); -+ } -+ -+ return E_FAIL; -+} -+ -+static DWORD WINAPI component_GetPlatform(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->platform; -+} -+ -+static HRESULT WINAPI component_GetMode(ICifComponent *iface, UINT index, char *mode, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ FIXME("(%p)->(%u, %p, %u): stub\n", This, index, mode, size); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI component_GetGroup(ICifComponent *iface, char *id, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, id, size); -+ -+ return copy_substring_null(id, size, This->group); -+} -+ -+static HRESULT WINAPI component_IsUIVisible(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->visibleui ? S_OK : S_FALSE; -+} -+ -+static HRESULT WINAPI component_GetPatchID(ICifComponent *iface, char *id, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, id, size); -+ -+ return copy_substring_null(id, size, This->patchid); -+} -+ -+static HRESULT WINAPI component_GetDetVersion(ICifComponent *iface, char *dll, DWORD dll_size, char *entry, DWORD entry_size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ FIXME("(%p)->(%p, %u, %p, %u): stub\n", This, dll, dll_size, entry, entry_size); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI component_GetTreatAsOneComponents(ICifComponent *iface, UINT index, char *id, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ FIXME("(%p)->(%u, %p, %u): stub\n", This, index, id, size); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI component_GetCustomData(ICifComponent *iface, char *key, char *data, DWORD size) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ FIXME("(%p)->(%s, %p, %u): stub\n", This, debugstr_a(key), data, size); -+ -+ return E_NOTIMPL; -+} -+ -+static DWORD WINAPI component_IsComponentInstalled(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->installed; -+} -+ -+static HRESULT WINAPI component_IsComponentDownloaded(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->downloaded ? S_OK : S_FALSE; -+} -+ -+static DWORD WINAPI component_IsThisVersionInstalled(ICifComponent *iface, DWORD version, DWORD build, DWORD *ret_version, DWORD *ret_build) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ FIXME("(%p)->(%u, %u, %p, %p): stub\n", This, version, build, ret_version, ret_build); -+ -+ return 0; -+} -+ -+static DWORD WINAPI component_GetInstallQueueState(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->queue_state; -+} -+ -+static HRESULT WINAPI component_SetInstallQueueState(ICifComponent *iface, DWORD state) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%u)\n", This, state); -+ -+ This->queue_state = state; -+ return S_OK; -+} -+ -+static DWORD WINAPI component_GetActualDownloadSize(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->size_download; -+} -+ -+static DWORD WINAPI component_GetCurrentPriority(ICifComponent *iface) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ return This->current_priority; -+} -+ -+ -+static HRESULT WINAPI component_SetCurrentPriority(ICifComponent *iface, DWORD priority) -+{ -+ struct cifcomponent *This = impl_from_ICifComponent(iface); -+ -+ TRACE("(%p)->(%u)\n", This, priority); -+ -+ This->current_priority = priority; -+ return S_OK; -+} -+ -+static const ICifComponentVtbl cifcomponentVtbl = -+{ -+ component_GetID, -+ component_GetGUID, -+ component_GetDescription, -+ component_GetDetails, -+ component_GetUrl, -+ component_GetFileExtractList, -+ component_GetUrlCheckRange, -+ component_GetCommand, -+ component_GetVersion, -+ component_GetLocale, -+ component_GetUninstallKey, -+ component_GetInstalledSize, -+ component_GetDownloadSize, -+ component_GetExtractSize, -+ component_GetSuccessKey, -+ component_GetProgressKeys, -+ component_IsActiveSetupAware, -+ component_IsRebootRequired, -+ component_RequiresAdminRights, -+ component_GetPriority, -+ component_GetDependency, -+ component_GetPlatform, -+ component_GetMode, -+ component_GetGroup, -+ component_IsUIVisible, -+ component_GetPatchID, -+ component_GetDetVersion, -+ component_GetTreatAsOneComponents, -+ component_GetCustomData, -+ component_IsComponentInstalled, -+ component_IsComponentDownloaded, -+ component_IsThisVersionInstalled, -+ component_GetInstallQueueState, -+ component_SetInstallQueueState, -+ component_GetActualDownloadSize, -+ component_GetCurrentPriority, -+ component_SetCurrentPriority, -+}; -+ -+static HRESULT WINAPI enum_components_QueryInterface(IEnumCifComponents *iface, REFIID riid, void **ppv) -+{ -+ struct ciffenum_components *This = impl_from_IEnumCifComponents(iface); -+ -+ if (IsEqualGUID(&IID_IUnknown, riid)) -+ { -+ TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); -+ *ppv = &This->IEnumCifComponents_iface; -+ } -+ /* -+ else if (IsEqualGUID(&IID_IEnumCifComponents, riid)) -+ { -+ TRACE("(%p)->(IID_ICifFile %p)\n", This, ppv); -+ *ppv = &This->IEnumCifComponents_iface; -+ } -+ */ -+ else -+ { -+ FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv); -+ *ppv = NULL; -+ return E_NOINTERFACE; -+ } -+ -+ IUnknown_AddRef((IUnknown *)*ppv); -+ return S_OK; -+} -+ -+static ULONG WINAPI enum_components_AddRef(IEnumCifComponents *iface) -+{ -+ struct ciffenum_components *This = impl_from_IEnumCifComponents(iface); -+ LONG ref = InterlockedIncrement(&This->ref); -+ -+ TRACE("(%p) ref=%d\n", This, ref); -+ -+ return ref; -+} -+ -+static ULONG WINAPI enum_components_Release(IEnumCifComponents *iface) -+{ -+ struct ciffenum_components *This = impl_from_IEnumCifComponents(iface); -+ LONG ref = InterlockedDecrement(&This->ref); -+ -+ TRACE("(%p) ref=%d\n", This, ref); -+ -+ if(!ref) -+ { -+ ICifFile_Release(This->file); -+ heap_free(This); -+ } -+ -+ return ref; -+} -+ -+static HRESULT WINAPI enum_components_Next(IEnumCifComponents *iface, ICifComponent **component) -+{ -+ struct ciffenum_components *This = impl_from_IEnumCifComponents(iface); -+ struct cifcomponent *comp; -+ -+ TRACE("(%p)->(%p)\n", This, component); -+ -+ if (!component) -+ return E_FAIL; -+ -+ if (!This->position) -+ { -+ *component = NULL; -+ return E_FAIL; -+ } -+ -+ do -+ { -+ This->position = list_next(This->start, This->position); -+ if (!This->position) -+ { -+ *component = NULL; -+ return E_FAIL; -+ } -+ -+ comp = CONTAINING_RECORD(This->position, struct cifcomponent, entry); -+ } while (This->group_id && (!comp->group || strcmp(This->group_id, comp->group))); -+ -+ *component = &comp->ICifComponent_iface; -+ return S_OK; -+} -+ -+static HRESULT WINAPI enum_components_Reset(IEnumCifComponents *iface) -+{ -+ struct ciffenum_components *This = impl_from_IEnumCifComponents(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ This->position = This->start; -+ return S_OK; -+} -+ -+static const IEnumCifComponentsVtbl enum_componentsVtbl = -+{ -+ enum_components_QueryInterface, -+ enum_components_AddRef, -+ enum_components_Release, -+ enum_components_Next, -+ enum_components_Reset, -+}; -+ -+static HRESULT enum_components_create(ICifFile *file, struct list *start, char *group_id, IEnumCifComponents **iface) -+{ -+ struct ciffenum_components *enumerator; -+ -+ enumerator = heap_alloc_zero(sizeof(*enumerator)); -+ if (!enumerator) return E_OUTOFMEMORY; -+ -+ enumerator->IEnumCifComponents_iface.lpVtbl = &enum_componentsVtbl; -+ enumerator->ref = 1; -+ enumerator->file = file; -+ enumerator->start = start; -+ enumerator->position = start; -+ enumerator->group_id = group_id; -+ -+ ICifFile_AddRef(file); -+ -+ *iface = &enumerator->IEnumCifComponents_iface; -+ return S_OK; -+} -+ -+static HRESULT WINAPI enum_groups_QueryInterface(IEnumCifGroups *iface, REFIID riid, void **ppv) -+{ -+ struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface); -+ -+ if (IsEqualGUID(&IID_IUnknown, riid)) -+ { -+ TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); -+ *ppv = &This->IEnumCifGroups_iface; -+ } -+ /* -+ else if (IsEqualGUID(&IID_IEnumCifGroups, riid)) -+ { -+ TRACE("(%p)->(IID_ICifFile %p)\n", This, ppv); -+ *ppv = &This->IEnumCifGroups_iface; -+ } -+ */ -+ else -+ { -+ FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv); -+ *ppv = NULL; -+ return E_NOINTERFACE; -+ } -+ -+ IUnknown_AddRef((IUnknown *)*ppv); -+ return S_OK; -+} -+ -+static ULONG WINAPI enum_groups_AddRef(IEnumCifGroups *iface) -+{ -+ struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface); -+ LONG ref = InterlockedIncrement(&This->ref); -+ -+ TRACE("(%p) ref=%d\n", This, ref); -+ -+ return ref; -+} -+ -+static ULONG WINAPI enum_groups_Release(IEnumCifGroups *iface) -+{ -+ struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface); -+ LONG ref = InterlockedDecrement(&This->ref); -+ -+ TRACE("(%p) ref=%d\n", This, ref); -+ -+ if(!ref) -+ { -+ ICifFile_Release(This->file); -+ heap_free(This); -+ } -+ -+ return ref; -+} -+ -+static HRESULT WINAPI enum_groups_Next(IEnumCifGroups *iface, ICifGroup **group) -+{ -+ struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface); -+ struct cifgroup *gp; -+ -+ TRACE("(%p)->(%p)\n", This, group); -+ -+ if (!This->position || !group) -+ return E_FAIL; -+ -+ This->position = list_next(This->start, This->position); -+ -+ if (!This->position) -+ return E_FAIL; -+ -+ gp = CONTAINING_RECORD(This->position, struct cifgroup, entry); -+ *group = &gp->ICifGroup_iface; -+ return S_OK; -+} -+ -+static HRESULT WINAPI enum_groups_Reset(IEnumCifGroups *iface) -+{ -+ struct ciffenum_groups *This = impl_from_IEnumCifGroups(iface); -+ -+ TRACE("(%p)\n", This); -+ -+ This->position = This->start; -+ return S_OK; -+} -+ -+static const IEnumCifGroupsVtbl enum_groupsVtbl = -+{ -+ enum_groups_QueryInterface, -+ enum_groups_AddRef, -+ enum_groups_Release, -+ enum_groups_Next, -+ enum_groups_Reset, -+}; -+ -+static HRESULT enum_groups_create(ICifFile *file, struct list *start, IEnumCifGroups **iface) -+{ -+ struct ciffenum_groups *enumerator; -+ -+ enumerator = heap_alloc_zero(sizeof(*enumerator)); -+ if (!enumerator) return E_OUTOFMEMORY; -+ -+ enumerator->IEnumCifGroups_iface.lpVtbl = &enum_groupsVtbl; -+ enumerator->ref = 1; -+ enumerator->file = file; -+ enumerator->start = start; -+ enumerator->position = start; -+ -+ ICifFile_AddRef(file); -+ -+ *iface = &enumerator->IEnumCifGroups_iface; -+ return S_OK; -+} -+ -+static HRESULT WINAPI ciffile_QueryInterface(ICifFile *iface, REFIID riid, void **ppv) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ -+ if (IsEqualGUID(&IID_IUnknown, riid)) -+ { -+ TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); -+ *ppv = &This->ICifFile_iface; -+ } -+ else if (IsEqualGUID(&IID_ICifFile, riid)) -+ { -+ TRACE("(%p)->(IID_ICifFile %p)\n", This, ppv); -+ *ppv = &This->ICifFile_iface; -+ } -+ else -+ { -+ FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv); -+ *ppv = NULL; -+ return E_NOINTERFACE; -+ } -+ -+ IUnknown_AddRef((IUnknown *)*ppv); -+ return S_OK; -+} -+ -+static ULONG WINAPI ciffile_AddRef(ICifFile *iface) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ LONG ref = InterlockedIncrement(&This->ref); -+ -+ TRACE("(%p) ref=%d\n", This, ref); -+ -+ return ref; -+} -+ -+static ULONG WINAPI ciffile_Release(ICifFile *iface) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ LONG ref = InterlockedDecrement(&This->ref); -+ -+ TRACE("(%p) ref=%d\n", This, ref); -+ -+ if(!ref) -+ { -+ struct cifcomponent *comp, *comp_next; -+ struct cifgroup *group, *group_next; -+ -+ heap_free(This->name); -+ -+ LIST_FOR_EACH_ENTRY_SAFE(comp, comp_next, &This->components, struct cifcomponent, entry) -+ { -+ list_remove(&comp->entry); -+ component_free(comp); -+ } -+ -+ LIST_FOR_EACH_ENTRY_SAFE(group, group_next, &This->groups, struct cifgroup, entry) -+ { -+ list_remove(&group->entry); -+ group_free(group); -+ } -+ -+ heap_free(This); -+ } -+ -+ return ref; -+} -+ -+static HRESULT WINAPI ciffile_EnumComponents(ICifFile *iface, IEnumCifComponents **enum_components, DWORD filter, void *pv) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ -+ TRACE("(%p)->(%p, %u, %p)\n", This, enum_components, filter, pv); -+ -+ if (filter) -+ FIXME("filter (%x) not supported\n", filter); -+ if (pv) -+ FIXME("how to handle pv (%p)?\n", pv); -+ -+ return enum_components_create(iface, &This->components, NULL, enum_components); -+} -+ -+static HRESULT WINAPI ciffile_FindComponent(ICifFile *iface, const char *id, ICifComponent **component) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ struct cifcomponent *comp; -+ -+ TRACE("(%p)->(%s, %p)\n", This, debugstr_a(id), component); -+ -+ LIST_FOR_EACH_ENTRY(comp, &This->components, struct cifcomponent, entry) -+ { -+ if (strcmp(comp->id, id) != 0) -+ continue; -+ -+ *component = &comp->ICifComponent_iface; -+ return S_OK; -+ } -+ -+ return E_FAIL; -+} -+ -+static HRESULT WINAPI ciffile_EnumGroups(ICifFile *iface, IEnumCifGroups **enum_groups, DWORD filter, void *pv) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ -+ TRACE("(%p)->(%p, %u, %p)\n", This, enum_groups, filter, pv); -+ -+ if (filter) -+ FIXME("filter (%x) not supported\n", filter); -+ if (pv) -+ FIXME("how to handle pv (%p)?\n", pv); -+ -+ return enum_groups_create(iface, &This->groups, enum_groups); -+} -+ -+static HRESULT WINAPI ciffile_FindGroup(ICifFile *iface, const char *id, ICifGroup **group) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ struct cifgroup *gp; -+ -+ TRACE("(%p)->(%s, %p)\n", This, debugstr_a(id), group); -+ -+ LIST_FOR_EACH_ENTRY(gp, &This->groups, struct cifgroup, entry) -+ { -+ if (strcmp(gp->id, id) != 0) -+ continue; -+ -+ *group = &gp->ICifGroup_iface; -+ return S_OK; -+ } -+ -+ return E_FAIL; -+} -+ -+static HRESULT WINAPI ciffile_EnumModes(ICifFile *iface, IEnumCifModes **cuf_modes, DWORD filter, void *pv) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ -+ FIXME("(%p)->(%p, %u, %p): stub\n", This, cuf_modes, filter, pv); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI ciffile_FindMode(ICifFile *iface, const char *id, ICifMode **mode) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ -+ FIXME("(%p)->(%s, %p): stub\n", This, debugstr_a(id), mode); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI ciffile_GetDescription(ICifFile *iface, char *desc, DWORD size) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ -+ TRACE("(%p)->(%p, %u)\n", This, desc, size); -+ -+ return copy_substring_null(desc, size, This->name); -+} -+ -+static HRESULT WINAPI ciffile_GetDetDlls(ICifFile *iface, char *dlls, DWORD size) -+{ -+ struct ciffile *This = impl_from_ICiffile(iface); -+ -+ FIXME("(%p)->(%p, %u): stub\n", This, dlls, size); -+ -+ return E_NOTIMPL; -+} -+ -+static const ICifFileVtbl ciffileVtbl = -+{ -+ ciffile_QueryInterface, -+ ciffile_AddRef, -+ ciffile_Release, -+ ciffile_EnumComponents, -+ ciffile_FindComponent, -+ ciffile_EnumGroups, -+ ciffile_FindGroup, -+ ciffile_EnumModes, -+ ciffile_FindMode, -+ ciffile_GetDescription, -+ ciffile_GetDetDlls, -+}; -+ -+static BOOL copy_string(char **dest, const char *source) -+{ -+ if (!source) -+ { -+ *dest = NULL; -+ return TRUE; -+ } -+ -+ *dest = strdupA(source); -+ if (!dest) return FALSE; -+ return TRUE; -+} -+ -+static BOOL section_get_str(struct inf_section *inf_sec, const char *key, char **value, const char *def) -+{ -+ struct inf_value *inf_val; -+ -+ inf_val = inf_get_value(inf_sec, key); -+ if (!inf_val) return copy_string(value, def); -+ -+ *value = inf_value_get_value(inf_val); -+ if (!*value) return FALSE; -+ -+ return TRUE; -+} -+ -+static char *next_part(char **str, BOOL strip_quotes) -+{ -+ char *start = *str; -+ char *next = *str; -+ -+ while (*next && *next != ',') -+ next++; -+ -+ if (!*next) -+ { -+ *str = trim(start, NULL, strip_quotes); -+ return NULL; -+ } -+ -+ *next = 0; -+ *str = trim(start, NULL, strip_quotes); -+ return ++next; -+} -+ -+static BOOL value_get_str_field(struct inf_value *inf_val, int field, char **value, const char *def) -+{ -+ char *line, *str, *next; -+ int i = 0; -+ -+ line = inf_value_get_value(inf_val); -+ if (!line) return FALSE; -+ -+ str = line; -+ do -+ { -+ i++; -+ next = next_part(&str, TRUE); -+ -+ if (field == i) -+ { -+ BOOL ret = copy_string(value, str); -+ heap_free(line); -+ return ret; -+ } -+ -+ str = next; -+ } while (str); -+ -+ return copy_string(value, def); -+} -+ -+/* -+static BOOL section_get_str_field(struct inf_section *inf_sec, const char *key, int field, char **value, const char *def) -+{ -+ struct inf_value *inf_val; -+ -+ inf_val = inf_get_value(inf_sec, key); -+ if (!inf_val) return copy_string(value, def); -+ -+ return value_get_str_field(inf_val, field, value, def); -+} -+*/ -+ -+static BOOL section_get_dword(struct inf_section *inf_sec, const char *key, DWORD *value, DWORD def) -+{ -+ struct inf_value *inf_val; -+ char *str; -+ -+ inf_val = inf_get_value(inf_sec, key); -+ if (!inf_val) -+ { -+ *value = def; -+ return TRUE; -+ } -+ -+ str = inf_value_get_value(inf_val); -+ if (!str) return FALSE; -+ -+ *value = atoi(str); -+ heap_free(str); -+ -+ return TRUE; -+} -+ -+static BOOL value_get_dword_field(struct inf_value *inf_val, int field, DWORD *value, DWORD def) -+{ -+ char *value_str; -+ BOOL ret; -+ -+ ret = value_get_str_field(inf_val, field, &value_str, NULL); -+ if (!ret) return FALSE; -+ if (!value_str) -+ { -+ *value = def; -+ return TRUE; -+ } -+ -+ *value = atoi(value_str); -+ heap_free(value_str); -+ -+ return TRUE; -+} -+ -+static BOOL section_get_dword_field(struct inf_section *inf_sec, const char *key, int field, DWORD *value, DWORD def) -+{ -+ struct inf_value *inf_val; -+ -+ inf_val = inf_get_value(inf_sec, key); -+ if (!inf_val) -+ { -+ *value = def; -+ return TRUE; -+ } -+ -+ return value_get_dword_field(inf_val, field, value, def); -+} -+ -+static HRESULT process_version(struct ciffile *file, struct inf_section *section) -+{ -+ if (!section_get_str(section, "DisplayName", &file->name, DEFAULT_INSTALLER_DESC)) -+ return E_OUTOFMEMORY; -+ -+ return S_OK; -+} -+ -+static BOOL read_version_entry(struct inf_section *section, DWORD *ret_ver, DWORD *ret_build) -+{ -+ DWORD version = 0; -+ DWORD build = 0; -+ char *line, *str, *next; -+ -+ if (!section_get_str(section, "Version", &line, NULL)) -+ return FALSE; -+ if (!line) goto done; -+ -+ str = line; -+ -+ next = next_part(&str, TRUE); -+ version |= atoi(str) << 16; -+ if (!next) goto done; -+ str = next; -+ -+ next = next_part(&str, TRUE); -+ version |= atoi(str) & 0xffff; -+ if (!next) goto done; -+ str = next; -+ -+ next = next_part(&str, TRUE); -+ build |= atoi(str) << 16; -+ if (!next) goto done; -+ str = next; -+ -+ next_part(&str, TRUE); -+ build |= atoi(str) & 0xffff; -+ -+done: -+ heap_free(line); -+ *ret_ver = version; -+ *ret_build = build; -+ return TRUE; -+} -+ -+static BOOL read_platform_entry(struct inf_section *section, DWORD *ret_platform) -+{ -+ DWORD platform = PLATFORM_ALL; -+ char *line, *str, *next; -+ -+ if (!section_get_str(section, "Platform", &line, NULL)) -+ return FALSE; -+ if (!line) goto done; -+ -+ platform = 0; -+ str = line; -+ do -+ { -+ next = next_part(&str, TRUE); -+ -+ if (strcasecmp(str, "Win95") == 0) -+ platform |= PLATFORM_WIN98; -+ else if (strcasecmp(str, "Win98") == 0) -+ platform |= PLATFORM_WIN98; -+ else if (strcasecmp(str, "NT4") == 0) -+ platform |= PLATFORM_NT4; -+ else if (strcasecmp(str, "NT5") == 0) -+ platform |= PLATFORM_NT5; -+ else if (strcasecmp(str, "NT4Alpha") == 0) -+ platform |= PLATFORM_NT4; -+ else if (strcasecmp(str, "NT5Alpha") == 0) -+ platform |= PLATFORM_NT5; -+ else if (strcasecmp(str, "Millen") == 0) -+ platform |= PLATFORM_MILLEN; -+ else -+ FIXME("Unknown platform: %s\n", debugstr_a(str)); -+ -+ str = next; -+ } while (str); -+ -+done: -+ heap_free(line); -+ *ret_platform = platform; -+ return TRUE; -+} -+ -+static BOOL read_dependencies(struct cifcomponent *component, struct inf_section *section) -+{ -+ struct dependency_info *dependency; -+ char *line, *str, *next; -+ BOOL ret = TRUE; -+ -+ if (!section_get_str(section, "Dependencies", &line, NULL)) -+ return E_OUTOFMEMORY; -+ if (!line) goto done; -+ -+ ret = FALSE; -+ str = line; -+ do -+ { -+ next = next_part(&str, TRUE); -+ -+ dependency = heap_alloc_zero(sizeof(*dependency)); -+ if (!dependency) goto done; -+ -+ dependency->id = strdupA(str); -+ if (!dependency->id) -+ { -+ heap_free(dependency); -+ goto done; -+ } -+ -+ dependency->type = strstr(dependency->id, ":"); -+ if (dependency->type) *dependency->type++ = 0; -+ -+ list_add_tail(&component->dependencies, &dependency->entry); -+ -+ str = next; -+ } while (str); -+ -+ ret = TRUE; -+ -+done: -+ heap_free(line); -+ return ret; -+} -+ -+static BOOL read_urls(struct cifcomponent *component, struct inf_section *section) -+{ -+ struct inf_value *inf_value = NULL; -+ struct url_info *url_entry; -+ char *str, *next; -+ int index; -+ -+ while (inf_section_next_value(section, &inf_value)) -+ { -+ str = inf_value_get_key(inf_value); -+ if (!str) return E_OUTOFMEMORY; -+ -+ if (strncasecmp(str, "URL", 3)) -+ goto next; -+ -+ if (!str[3]) -+ goto next; -+ -+ index = strtol(str+3, &next, 10); -+ if (next == str+3 || *next != 0 || index < 1) -+ goto next; -+ index--; -+ -+ url_entry = heap_alloc_zero(sizeof(*url_entry)); -+ if (!url_entry) goto error; -+ -+ url_entry->index = index; -+ -+ if (!value_get_str_field(inf_value, 1, &url_entry->url, NULL)) -+ goto error; -+ if (!url_entry->url || !*url_entry->url) -+ { -+ url_entry_free(url_entry); -+ goto next; -+ } -+ -+ if (!value_get_dword_field(inf_value, 2, &url_entry->flags, 0)) -+ goto error; -+ -+ list_add_tail(&component->urls, &url_entry->entry); -+ -+ next: -+ heap_free(str); -+ } -+ -+ return TRUE; -+ -+error: -+ heap_free(str); -+ url_entry_free(url_entry); -+ return FALSE; -+}; -+ -+void add_component_by_priority(struct ciffile *file, struct cifcomponent *component) -+{ -+ struct cifcomponent *entry; -+ -+ LIST_FOR_EACH_ENTRY(entry, &file->components, struct cifcomponent, entry) -+ { -+ if (entry->priority > component->priority) -+ continue; -+ -+ list_add_before(&entry->entry, &component->entry); -+ return; -+ } -+ -+ list_add_tail(&file->components, &component->entry); -+} -+ -+static HRESULT process_component(struct ciffile *file, struct inf_section *section, const char *section_name) -+{ -+ struct cifcomponent *component; -+ HRESULT hr = E_OUTOFMEMORY; -+ -+ component = heap_alloc_zero(sizeof(*component)); -+ if (!component) return E_OUTOFMEMORY; -+ -+ component->ICifComponent_iface.lpVtbl = &cifcomponentVtbl; -+ component->parent = &file->ICifFile_iface; -+ -+ list_init(&component->urls); -+ list_init(&component->dependencies); -+ -+ component->queue_state = ActionNone; -+ -+ component->id = strdupA(section_name); -+ if (!component->id) goto error; -+ -+ if (!section_get_str(section, "DisplayName", &component->description, NULL)) -+ goto error; -+ if (!section_get_str(section, "GUID", &component->guid, NULL)) -+ goto error; -+ if (!section_get_str(section, "Details", &component->details, NULL)) -+ goto error; -+ if (!section_get_str(section, "Group", &component->group, NULL)) -+ goto error; -+ if (!section_get_str(section, "Locale", &component->locale, "en")) -+ goto error; -+ if (!section_get_str(section, "PatchID", &component->patchid, NULL)) -+ goto error; -+ -+ if (!section_get_dword_field(section, "Size", 1, &component->size_download, 0)) -+ goto error; -+ if (!section_get_dword_field(section, "Size", 2, &component->size_extracted, 0)) -+ goto error; -+ if (!section_get_dword_field(section, "InstalledSize", 1, &component->size_app, 0)) -+ goto error; -+ if (!section_get_dword_field(section, "InstalledSize", 2, &component->size_win, 0)) -+ goto error; -+ -+ if (!section_get_str(section, "SuccessKey", &component->key_success, NULL)) -+ goto error; -+ if (!section_get_str(section, "CancelKey", &component->key_cancel, NULL)) -+ goto error; -+ if (!section_get_str(section, "ProgressKey", &component->key_progress, NULL)) -+ goto error; -+ if (!section_get_str(section, "UninstallKey", &component->key_uninstall, NULL)) -+ goto error; -+ if (!section_get_dword(section, "Reboot", &component->reboot, 0)) -+ goto error; -+ if (!section_get_dword(section, "AdminCheck", &component->admin, 0)) -+ goto error; -+ if (!section_get_dword(section, "UIVisible", &component->visibleui, 1)) -+ goto error; -+ if (!section_get_dword(section, "ActiveSetupAware", &component->as_aware, 0)) -+ goto error; -+ if (!section_get_dword(section, "Priority", &component->priority, 0)) -+ goto error; -+ -+ if (!read_version_entry(section, &component->version, &component->build)) -+ goto error; -+ if (!read_platform_entry(section, &component->platform)) -+ goto error; -+ if (!read_urls(component, section)) -+ goto error; -+ if (!read_dependencies(component, section)) -+ goto error; -+ -+ component->current_priority = component->priority; -+ -+ add_component_by_priority(file, component); -+ return S_OK; -+ -+error: -+ component_free(component); -+ return hr; -+} -+ -+static HRESULT process_group(struct ciffile *file, struct inf_section *section, const char *section_name) -+{ -+ struct cifgroup *group; -+ HRESULT hr = E_OUTOFMEMORY; -+ -+ group = heap_alloc_zero(sizeof(*group)); -+ if (!group) return E_OUTOFMEMORY; -+ -+ group->ICifGroup_iface.lpVtbl = &cifgroupVtbl; -+ group->parent = &file->ICifFile_iface; -+ -+ group->id = strdupA(section_name); -+ if (!group->id) goto error; -+ -+ if (!section_get_str(section, "DisplayName", &group->description, NULL)) -+ goto error; -+ if (!section_get_dword(section, "Priority", &group->priority, 0)) -+ goto error; -+ -+ list_add_head(&file->groups, &group->entry); -+ return S_OK; -+ -+error: -+ group_free(group); -+ return hr; -+} -+ -+static HRESULT process_section(struct ciffile *file, struct inf_section *section, const char *section_name) -+{ -+ HRESULT hr = S_OK; -+ char *type; -+ -+ if (!section_get_str(section, "SectionType", &type, "Component")) -+ return E_OUTOFMEMORY; -+ -+ if (!strcasecmp(type, "Component")) -+ hr = process_component(file, section, section_name); -+ else if (strcasecmp(type, "Group") == 0) -+ hr = process_group(file, section, section_name); -+ else -+ FIXME("Don't know how to process %s\n", debugstr_a(type)); -+ -+ heap_free(type); -+ return hr; -+} -+ -+static HRESULT process_inf(struct ciffile *file, struct inf_file *inf) -+{ -+ struct inf_section *section = NULL; -+ char *section_name; -+ HRESULT hr = S_OK; -+ -+ while (SUCCEEDED(hr) && inf_next_section(inf, §ion)) -+ { -+ section_name = inf_section_get_name(section); -+ if (!section_name) return E_OUTOFMEMORY; -+ -+ TRACE("start processing section %s\n", debugstr_a(section_name)); -+ -+ if (!strcasecmp(section_name, "Strings") || -+ !strncasecmp(section_name, "Strings.", strlen("Strings."))) -+ { -+ /* Ignore string sections */ -+ } -+ else if (strcasecmp(section_name, "Version") == 0) -+ hr = process_version(file, section); -+ else -+ hr = process_section(file, section, section_name); -+ -+ TRACE("finished processing section %s (%x)\n", debugstr_a(section_name), hr); -+ heap_free(section_name); -+ } -+ -+ /* In case there was no version section, set the default installer description */ -+ if (SUCCEEDED(hr) && !file->name) -+ { -+ file->name = strdupA(DEFAULT_INSTALLER_DESC); -+ if (!file->name) hr = E_OUTOFMEMORY; -+ } -+ -+ return hr; -+} -+ -+static HRESULT load_ciffile(const char *path, ICifFile **icif) -+{ -+ struct inf_file *inf = NULL; -+ struct ciffile *file; -+ HRESULT hr = E_FAIL; -+ -+ file = heap_alloc_zero(sizeof(*file)); -+ if(!file) return E_OUTOFMEMORY; -+ -+ file->ICifFile_iface.lpVtbl = &ciffileVtbl; -+ file->ref = 1; -+ -+ list_init(&file->components); -+ list_init(&file->groups); -+ -+ hr = inf_load(path, &inf); -+ if (FAILED(hr)) goto error; -+ -+ hr = process_inf(file, inf); -+ if (FAILED(hr)) goto error; -+ -+ *icif = &file->ICifFile_iface; -+ return S_OK; -+ -+error: -+ if (inf) inf_free(inf); -+ ICifFile_Release(&file->ICifFile_iface); -+ return hr; -+} -+ -+HRESULT WINAPI GetICifFileFromFile(ICifFile **icif, const char *path) -+{ -+ TRACE("(%p, %s)\n", icif, debugstr_a(path)); -+ -+ return load_ciffile(path, icif); -+} -+ -+ -+HRESULT WINAPI GetICifRWFileFromFile(ICifRWFile **icif, const char *path) -+{ -+ FIXME("(%p, %s): stub\n", icif, debugstr_a(path)); -+ -+ return E_NOTIMPL; -+} -diff --git a/dlls/inseng/inf.c b/dlls/inseng/inf.c -new file mode 100644 -index 00000000000..bead72c082c ---- /dev/null -+++ b/dlls/inseng/inf.c -@@ -0,0 +1,443 @@ -+/* -+ * Copyright 2016 Michael Müller -+ * -+ * 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 -+#include -+ -+#include "windef.h" -+#include "winbase.h" -+#include "winuser.h" -+ -+#include "inseng_private.h" -+ -+#include "wine/list.h" -+ -+struct inf_value -+{ -+ struct list entry; -+ char *key; -+ char *value; -+ -+ struct inf_section *section; -+}; -+ -+struct inf_section -+{ -+ struct list entry; -+ char *name; -+ struct list values; -+ -+ struct inf_file *file; -+}; -+ -+struct inf_file -+{ -+ char *content; -+ DWORD size; -+ struct list sections; -+}; -+ -+static void inf_value_free(struct inf_value *value) -+{ -+ heap_free(value); -+} -+ -+static void inf_section_free(struct inf_section *section) -+{ -+ struct inf_value *val, *val_next; -+ LIST_FOR_EACH_ENTRY_SAFE(val, val_next, §ion->values, struct inf_value, entry) -+ { -+ list_remove(&val->entry); -+ inf_value_free(val); -+ } -+ -+ heap_free(section); -+} -+ -+static const char *get_substitution(struct inf_file *inf, const char *name, int len) -+{ -+ struct inf_section *sec; -+ struct inf_value *value = NULL; -+ -+ sec = inf_get_section(inf, "Strings"); -+ if (!sec) return NULL; -+ -+ while (inf_section_next_value(sec, &value)) -+ { -+ if (strlen(value->key) == len && !strncasecmp(value->key, name, len)) -+ return value->value; -+ } -+ -+ return NULL; -+} -+ -+static int expand_variables_buffer(struct inf_file *inf, const char *str, char *output) -+{ -+ const char *p, *var_start = NULL; -+ int var_len = 0, len = 0; -+ const char *substitution; -+ -+ for (p = str; *p; p++) -+ { -+ if (*p != '%') -+ { -+ if (var_start) -+ var_len++; -+ else -+ { -+ if (output) -+ *output++ = *p; -+ len++; -+ } -+ -+ continue; -+ } -+ -+ if (!var_start) -+ { -+ var_start = p; -+ var_len = 0; -+ -+ continue; -+ } -+ -+ if (!var_len) -+ { -+ /* just an escaped % */ -+ if (output) -+ *output++ = '%'; -+ len += 1; -+ -+ var_start = NULL; -+ continue; -+ } -+ -+ substitution = get_substitution(inf, var_start + 1, var_len); -+ if (!substitution) -+ { -+ if (output) -+ { -+ memcpy(output, var_start, var_len + 2); -+ output += var_len + 2; -+ } -+ len += var_len + 2; -+ } -+ else -+ { -+ int sub_len = strlen(substitution); -+ -+ if (output) -+ { -+ memcpy(output, substitution, sub_len); -+ output += sub_len; -+ } -+ len += sub_len; -+ } -+ -+ var_start = NULL; -+ } -+ -+ if (output) *output = 0; -+ return len + 1; -+} -+ -+static char *expand_variables(struct inf_file *inf, const char *str) -+{ -+ char *buffer; -+ int len; -+ -+ len = expand_variables_buffer(inf, str, NULL); -+ buffer = heap_alloc(len); -+ if (!len) return NULL; -+ -+ expand_variables_buffer(inf, str, buffer); -+ return buffer; -+} -+ -+void inf_free(struct inf_file *inf) -+{ -+ struct inf_section *sec, *sec_next; -+ LIST_FOR_EACH_ENTRY_SAFE(sec, sec_next, &inf->sections, struct inf_section, entry) -+ { -+ list_remove(&sec->entry); -+ inf_section_free(sec); -+ } -+ -+ heap_free(inf->content); -+ heap_free(inf); -+} -+ -+BOOL inf_next_section(struct inf_file *inf, struct inf_section **sec) -+{ -+ struct list *next_entry, *cur_position; -+ -+ if (*sec) -+ cur_position = &(*sec)->entry; -+ else -+ cur_position = &inf->sections; -+ -+ next_entry = list_next(&inf->sections, cur_position); -+ if (!next_entry) return FALSE; -+ -+ *sec = CONTAINING_RECORD(next_entry, struct inf_section, entry); -+ return TRUE; -+} -+ -+struct inf_section *inf_get_section(struct inf_file *inf, const char *name) -+{ -+ struct inf_section *sec = NULL; -+ -+ while (inf_next_section(inf, &sec)) -+ { -+ if (!strcasecmp(sec->name, name)) -+ return sec; -+ } -+ -+ return NULL; -+} -+ -+char *inf_section_get_name(struct inf_section *section) -+{ -+ return strdupA(section->name); -+} -+ -+BOOL inf_section_next_value(struct inf_section *sec, struct inf_value **value) -+{ -+ struct list *next_entry, *cur_position; -+ -+ if (*value) -+ cur_position = &(*value)->entry; -+ else -+ cur_position = &sec->values; -+ -+ next_entry = list_next(&sec->values, cur_position); -+ if (!next_entry) return FALSE; -+ -+ *value = CONTAINING_RECORD(next_entry, struct inf_value, entry); -+ return TRUE; -+} -+ -+struct inf_value *inf_get_value(struct inf_section *sec, const char *key) -+{ -+ struct inf_value *value = NULL; -+ -+ while (inf_section_next_value(sec, &value)) -+ { -+ if (!strcasecmp(value->key, key)) -+ return value; -+ } -+ -+ return NULL; -+} -+ -+char *inf_value_get_key(struct inf_value *value) -+{ -+ return strdupA(value->key); -+} -+ -+char *inf_value_get_value(struct inf_value *value) -+{ -+ return expand_variables(value->section->file, value->value); -+} -+ -+char *trim(char *str, char **last_chr, BOOL strip_quotes) -+{ -+ char *last; -+ -+ for (; *str; str++) -+ { -+ if (*str != '\t' && *str != ' ') -+ break; -+ } -+ -+ if (!*str) -+ { -+ if (last_chr) *last_chr = str; -+ return str; -+ } -+ -+ last = str + strlen(str) - 1; -+ -+ for (; last > str; last--) -+ { -+ if (*last != '\t' && *last != ' ') -+ break; -+ *last = 0; -+ } -+ -+ if (strip_quotes && last != str) -+ { -+ if (*last == '"' && *str == '"') -+ { -+ str++; -+ *last = 0; -+ } -+ } -+ -+ if (last_chr) *last_chr = last; -+ return str; -+} -+ -+static char *get_next_line(char **str, char **last_chr) -+{ -+ BOOL in_next_line = FALSE; -+ char *start, *next; -+ -+ start = *str; -+ if (!start || !*start) return NULL; -+ -+ for (next = start; *next; next++) -+ { -+ if (*next == '\n' || *next == '\r') -+ { -+ *next = 0; -+ in_next_line = TRUE; -+ } -+ else if (in_next_line) -+ { -+ break; -+ } -+ } -+ -+ *str = next; -+ return trim(start, last_chr, FALSE); -+} -+ -+/* This function only fails in case of an memory allocation error -+ * and does not touch section in case the parsing failed. */ -+static HRESULT inf_section_parse(struct inf_file *inf, char *line, char *last_chr, struct inf_section **section) -+{ -+ struct inf_section *sec; -+ char *comment; -+ char *name; -+ -+ if (*line != '[') -+ return S_OK; -+ -+ line++; -+ -+ comment = strchr(line, ';'); -+ if (comment) -+ { -+ *comment = 0; -+ line = trim(line, &last_chr, FALSE); -+ } -+ -+ if (*last_chr != ']') -+ return S_OK; -+ -+ *last_chr = 0; -+ name = trim(line, NULL, FALSE); -+ if (!name) return S_OK; -+ -+ sec = heap_alloc_zero(sizeof(*sec)); -+ if (!sec) return E_OUTOFMEMORY; -+ -+ sec->name = name; -+ sec->file = inf; -+ list_init(&sec->values); -+ -+ list_add_tail(&inf->sections, &sec->entry); -+ -+ *section = sec; -+ return S_OK; -+} -+ -+static HRESULT inf_value_parse(struct inf_section *sec, char *line) -+{ -+ struct inf_value *key_val; -+ char *key, *value, *del; -+ -+ del = strchr(line, '='); -+ if (!del) return S_OK; -+ -+ *del = 0; -+ key = line; -+ value = del + 1; -+ -+ key = trim(key, NULL, FALSE); -+ value = trim(value, NULL, TRUE); -+ -+ key_val = heap_alloc_zero(sizeof(*key_val)); -+ if (!key_val) return E_OUTOFMEMORY; -+ -+ key_val->key = key; -+ key_val->value = value; -+ key_val->section = sec; -+ -+ list_add_tail(&sec->values, &key_val->entry); -+ return S_OK; -+} -+ -+static HRESULT inf_process_content(struct inf_file *inf) -+{ -+ struct inf_section *section = NULL; -+ char *content = inf->content; -+ char *line, *last_chr; -+ HRESULT hr = S_OK; -+ -+ while (SUCCEEDED(hr) && (line = get_next_line(&content, &last_chr))) -+ { -+ if (*line == '[') -+ hr = inf_section_parse(inf, line, last_chr, §ion); -+ else if (strchr(line, '=') && section) -+ hr = inf_value_parse(section, line); -+ } -+ -+ return hr; -+} -+ -+HRESULT inf_load(const char *path, struct inf_file **inf_file) -+{ -+ LARGE_INTEGER file_size; -+ struct inf_file *inf; -+ HRESULT hr = E_FAIL; -+ HANDLE file; -+ DWORD read; -+ -+ file = CreateFileA(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -+ if (file == INVALID_HANDLE_VALUE) return E_FAIL; -+ -+ inf = heap_alloc_zero(sizeof(*inf)); -+ if (!inf) goto error; -+ -+ if (!GetFileSizeEx(file, &file_size)) -+ goto error; -+ -+ inf->size = file_size.QuadPart; -+ -+ inf->content = heap_alloc_zero(inf->size); -+ if (!inf->content) goto error; -+ -+ list_init(&inf->sections); -+ -+ if (!ReadFile(file, inf->content, inf->size, &read, NULL) || read != inf->size) -+ goto error; -+ -+ hr = inf_process_content(inf); -+ if (FAILED(hr)) goto error; -+ -+ CloseHandle(file); -+ *inf_file = inf; -+ return S_OK; -+ -+error: -+ if (inf) inf_free(inf); -+ CloseHandle(file); -+ return hr; -+} -diff --git a/dlls/inseng/inseng.spec b/dlls/inseng/inseng.spec -index 82c0b4d5fe1..7ae46fad3a7 100644 ---- a/dlls/inseng/inseng.spec -+++ b/dlls/inseng/inseng.spec -@@ -7,6 +7,6 @@ - @ stdcall -private DllRegisterServer() - @ stdcall -private DllUnregisterServer() - @ stub DownloadFile --@ stub GetICifFileFromFile --@ stub GetICifRWFileFromFile -+@ stdcall GetICifFileFromFile(ptr str) -+@ stdcall GetICifRWFileFromFile(ptr str) - @ stub PurgeDownloadDirectory -diff --git a/dlls/inseng/inseng_main.c b/dlls/inseng/inseng_main.c -index 2c95a2e72bd..6a926ccb379 100644 ---- a/dlls/inseng/inseng_main.c -+++ b/dlls/inseng/inseng_main.c -@@ -2,6 +2,7 @@ - * INSENG Implementation - * - * Copyright 2006 Mike McCormack -+ * Copyright 2016 Michael Müller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -28,17 +29,68 @@ - #include "winuser.h" - #include "ole2.h" - #include "rpcproxy.h" -+#include "urlmon.h" -+#include "shlwapi.h" - #include "initguid.h" - #include "inseng.h" - -+#include "inseng_private.h" -+ - #include "wine/debug.h" --#include "wine/heap.h" - - WINE_DEFAULT_DEBUG_CHANNEL(inseng); - -+enum thread_operation -+{ -+ OP_DOWNLOAD, -+ OP_INSTALL -+}; -+ -+struct thread_info -+{ -+ DWORD operation; -+ DWORD jobflags; -+ IEnumCifComponents *enum_comp; -+ -+ DWORD download_size; -+ DWORD install_size; -+ -+ DWORD downloaded_kb; -+ ULONGLONG download_start; -+}; -+ - struct InstallEngine { - IInstallEngine2 IInstallEngine2_iface; -+ IInstallEngineTiming IInstallEngineTiming_iface; - LONG ref; -+ -+ IInstallEngineCallback *callback; -+ char *baseurl; -+ char *downloaddir; -+ ICifFile *icif; -+ DWORD status; -+ -+ /* used for the installation thread */ -+ struct thread_info thread; -+}; -+ -+struct downloadcb -+{ -+ IBindStatusCallback IBindStatusCallback_iface; -+ LONG ref; -+ -+ WCHAR *file_name; -+ WCHAR *cache_file; -+ -+ char *id; -+ char *display; -+ -+ DWORD dl_size; -+ DWORD dl_previous_kb; -+ -+ InstallEngine *engine; -+ HANDLE event_done; -+ HRESULT hr; - }; - - static inline InstallEngine *impl_from_IInstallEngine2(IInstallEngine2 *iface) -@@ -46,6 +98,250 @@ static inline InstallEngine *impl_from_IInstallEngine2(IInstallEngine2 *iface) - return CONTAINING_RECORD(iface, InstallEngine, IInstallEngine2_iface); - } - -+static inline struct downloadcb *impl_from_IBindStatusCallback(IBindStatusCallback *iface) -+{ -+ return CONTAINING_RECORD(iface, struct downloadcb, IBindStatusCallback_iface); -+} -+ -+static inline InstallEngine *impl_from_IInstallEngineTiming(IInstallEngineTiming *iface) -+{ -+ return CONTAINING_RECORD(iface, InstallEngine, IInstallEngineTiming_iface); -+} -+ -+static HRESULT WINAPI downloadcb_QueryInterface(IBindStatusCallback *iface, REFIID riid, void **ppv) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ -+ if (IsEqualGUID(&IID_IUnknown, riid)) -+ { -+ TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); -+ *ppv = &This->IBindStatusCallback_iface; -+ } -+ else if (IsEqualGUID(&IID_IBindStatusCallback, riid)) -+ { -+ TRACE("(%p)->(IID_IBindStatusCallback %p)\n", This, ppv); -+ *ppv = &This->IBindStatusCallback_iface; -+ } -+ else -+ { -+ FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv); -+ *ppv = NULL; -+ return E_NOINTERFACE; -+ } -+ -+ IUnknown_AddRef((IUnknown *)*ppv); -+ return S_OK; -+} -+ -+static ULONG WINAPI downloadcb_AddRef(IBindStatusCallback *iface) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ LONG ref = InterlockedIncrement(&This->ref); -+ -+ TRACE("(%p) ref = %d\n", This, ref); -+ -+ return ref; -+} -+ -+static ULONG WINAPI downloadcb_Release(IBindStatusCallback *iface) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ LONG ref = InterlockedDecrement(&This->ref); -+ -+ TRACE("(%p) ref = %d\n", This, ref); -+ -+ if (!ref) -+ { -+ heap_free(This->file_name); -+ heap_free(This->cache_file); -+ -+ IInstallEngine2_Release(&This->engine->IInstallEngine2_iface); -+ heap_free(This); -+ } -+ -+ return ref; -+} -+ -+static HRESULT WINAPI downloadcb_OnStartBinding(IBindStatusCallback *iface, DWORD reserved, IBinding *pbind) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ -+ TRACE("(%p)->(%u %p)\n", This, reserved, pbind); -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI downloadcb_GetPriority(IBindStatusCallback *iface, LONG *priority) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ -+ FIXME("(%p)->(%p): stub\n", This, priority); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI downloadcb_OnLowResource(IBindStatusCallback *iface, DWORD reserved) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ -+ FIXME("(%p)->(%u): stub\n", This, reserved); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI downloadcb_OnProgress(IBindStatusCallback *iface, ULONG progress, -+ ULONG progress_max, ULONG status, const WCHAR *status_text) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ HRESULT hr = S_OK; -+ -+ TRACE("%p)->(%u %u %u %s)\n", This, progress, progress_max, status, debugstr_w(status_text)); -+ -+ switch(status) -+ { -+ case BINDSTATUS_BEGINDOWNLOADDATA: -+ if (!This->engine->thread.download_start) -+ This->engine->thread.download_start = GetTickCount64(); -+ /* fall-through */ -+ case BINDSTATUS_DOWNLOADINGDATA: -+ case BINDSTATUS_ENDDOWNLOADDATA: -+ This->engine->thread.downloaded_kb = This->dl_previous_kb + progress / 1024; -+ if (This->engine->callback) -+ { -+ hr = IInstallEngineCallback_OnComponentProgress(This->engine->callback, -+ This->id, INSTALLSTATUS_DOWNLOADING, This->display, NULL, progress / 1024, This->dl_size); -+ } -+ break; -+ -+ case BINDSTATUS_CACHEFILENAMEAVAILABLE: -+ This->cache_file = strdupW(status_text); -+ if (!This->cache_file) -+ { -+ ERR("Failed to allocate memory for cache file\n"); -+ hr = E_OUTOFMEMORY; -+ } -+ break; -+ -+ case BINDSTATUS_CONNECTING: -+ case BINDSTATUS_SENDINGREQUEST: -+ case BINDSTATUS_MIMETYPEAVAILABLE: -+ case BINDSTATUS_FINDINGRESOURCE: -+ break; -+ -+ default: -+ FIXME("Unsupported status %u\n", status); -+ } -+ -+ return hr; -+} -+ -+static HRESULT WINAPI downloadcb_OnStopBinding(IBindStatusCallback *iface, HRESULT hresult, LPCWSTR szError) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ -+ TRACE("(%p)->(%08x %s)\n", This, hresult, debugstr_w(szError)); -+ -+ if (FAILED(hresult)) -+ { -+ This->hr = hresult; -+ goto done; -+ } -+ -+ if (!This->cache_file) -+ { -+ This->hr = E_FAIL; -+ goto done; -+ } -+ -+ if (CopyFileW(This->cache_file, This->file_name, FALSE)) -+ This->hr = S_OK; -+ else -+ { -+ ERR("CopyFile failed: %u\n", GetLastError()); -+ This->hr = E_FAIL; -+ } -+ -+done: -+ SetEvent(This->event_done); -+ return S_OK; -+} -+ -+static HRESULT WINAPI downloadcb_GetBindInfo(IBindStatusCallback *iface, -+ DWORD *grfBINDF, BINDINFO *pbindinfo) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ -+ TRACE("(%p)->(%p %p)\n", This, grfBINDF, pbindinfo); -+ -+ *grfBINDF = BINDF_PULLDATA | BINDF_NEEDFILE; -+ return S_OK; -+} -+ -+static HRESULT WINAPI downloadcb_OnDataAvailable(IBindStatusCallback *iface, -+ DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ -+ TRACE("(%p)->(%08x %u %p %p)\n", This, grfBSCF, dwSize, pformatetc, pstgmed); -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI downloadcb_OnObjectAvailable(IBindStatusCallback *iface, -+ REFIID riid, IUnknown *punk) -+{ -+ struct downloadcb *This = impl_from_IBindStatusCallback(iface); -+ -+ FIXME("(%p)->(%s %p): stub\n", This, debugstr_guid(riid), punk); -+ -+ return E_NOTIMPL; -+} -+ -+static const IBindStatusCallbackVtbl BindStatusCallbackVtbl = -+{ -+ downloadcb_QueryInterface, -+ downloadcb_AddRef, -+ downloadcb_Release, -+ downloadcb_OnStartBinding, -+ downloadcb_GetPriority, -+ downloadcb_OnLowResource, -+ downloadcb_OnProgress, -+ downloadcb_OnStopBinding, -+ downloadcb_GetBindInfo, -+ downloadcb_OnDataAvailable, -+ downloadcb_OnObjectAvailable -+}; -+ -+static HRESULT downloadcb_create(InstallEngine *engine, HANDLE event, char *file_name, char *id, -+ char *display, DWORD dl_size, struct downloadcb **callback) -+{ -+ struct downloadcb *cb; -+ -+ cb = heap_alloc_zero(sizeof(*cb)); -+ if (!cb) return E_OUTOFMEMORY; -+ -+ cb->IBindStatusCallback_iface.lpVtbl = &BindStatusCallbackVtbl; -+ cb->ref = 1; -+ cb->hr = E_FAIL; -+ cb->id = id; -+ cb->display = display; -+ cb->engine = engine; -+ cb->dl_size = dl_size; -+ cb->dl_previous_kb = engine->thread.downloaded_kb; -+ cb->event_done = event; -+ cb->file_name = strAtoW(file_name); -+ if (!cb->file_name) -+ { -+ heap_free(cb); -+ return E_OUTOFMEMORY; -+ } -+ -+ IInstallEngine2_AddRef(&engine->IInstallEngine2_iface); -+ -+ *callback = cb; -+ return S_OK; -+} -+ - static HRESULT WINAPI InstallEngine_QueryInterface(IInstallEngine2 *iface, REFIID riid, void **ppv) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -@@ -59,13 +355,16 @@ static HRESULT WINAPI InstallEngine_QueryInterface(IInstallEngine2 *iface, REFII - }else if(IsEqualGUID(&IID_IInstallEngine2, riid)) { - TRACE("(%p)->(IID_IInstallEngine2 %p)\n", This, ppv); - *ppv = &This->IInstallEngine2_iface; -+ }else if(IsEqualGUID(&IID_IInstallEngineTiming, riid)) { -+ TRACE("(%p)->(IID_IInstallEngineTiming %p)\n", This, ppv); -+ *ppv = &This->IInstallEngineTiming_iface; - }else { -- TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); -+ FIXME("(%p)->(%s %p) not found\n", This, debugstr_guid(riid), ppv); - *ppv = NULL; - return E_NOINTERFACE; - } - -- IUnknown_AddRef((IUnknown*)*ppv); -+ IUnknown_AddRef((IUnknown *)*ppv); - return S_OK; - } - -@@ -86,181 +385,726 @@ static ULONG WINAPI InstallEngine_Release(IInstallEngine2 *iface) - - TRACE("(%p) ref=%d\n", This, ref); - -- if(!ref) -+ if (!ref) -+ { -+ if (This->icif) -+ ICifFile_Release(This->icif); -+ -+ heap_free(This->baseurl); -+ heap_free(This->downloaddir); - heap_free(This); -+ } - - return ref; - } - -+static void set_status(InstallEngine *This, DWORD status) -+{ -+ This->status = status; -+ -+ if (This->callback) -+ IInstallEngineCallback_OnEngineStatusChange(This->callback, status, 0); -+} -+ -+static HRESULT calc_sizes(IEnumCifComponents *enum_comp, DWORD operation, DWORD *size_download, DWORD *size_install) -+{ -+ ICifComponent *comp; -+ DWORD download = 0; -+ DWORD install = 0; -+ HRESULT hr; -+ -+ /* FIXME: what about inactive dependencies and how does -+ * INSTALLOPTIONS_FORCEDEPENDENCIES play into this ?*/ -+ -+ hr = IEnumCifComponents_Reset(enum_comp); -+ if (FAILED(hr)) return hr; -+ -+ while (SUCCEEDED(IEnumCifComponents_Next(enum_comp, &comp))) -+ { -+ if (ICifComponent_GetInstallQueueState(comp) != ActionInstall) -+ continue; -+ -+ /* FIXME: handle install options and find out the default options*/ -+ if (operation == OP_DOWNLOAD && ICifComponent_IsComponentDownloaded(comp) == S_FALSE) -+ download = ICifComponent_GetDownloadSize(comp); -+ /* -+ if (operation == OP_INSTALL && ICifComponent_IsComponentInstalled(comp) == S_FALSE) -+ install = ICifComponent_GetInstalledSize(comp); -+ */ -+ } -+ -+ *size_download = download; -+ *size_install = install; -+ -+ return S_OK; -+} -+ -+static HRESULT get_next_component(IEnumCifComponents *enum_comp, DWORD operation, ICifComponent **ret_comp) -+{ -+ ICifComponent *comp; -+ HRESULT hr; -+ -+ hr = IEnumCifComponents_Reset(enum_comp); -+ if (FAILED(hr)) return hr; -+ -+ while (SUCCEEDED(IEnumCifComponents_Next(enum_comp, &comp))) -+ { -+ if (ICifComponent_GetInstallQueueState(comp) != ActionInstall) -+ continue; -+ -+ /* FIXME: handle install options and find out the default options*/ -+ if (operation == OP_DOWNLOAD && ICifComponent_IsComponentDownloaded(comp) != S_FALSE) -+ continue; -+ if (operation == OP_INSTALL && ICifComponent_IsComponentInstalled(comp) != S_FALSE) -+ continue; -+ -+ *ret_comp = comp; -+ return S_OK; -+ } -+ -+ return S_FALSE; -+} -+ -+static HRESULT get_url(ICifComponent *comp, int index, char **url, DWORD *flags) -+{ -+ char *url_temp = NULL; -+ int size = MAX_PATH / 2; -+ HRESULT hr; -+ -+ /* FIXME: should we add an internal get function to prevent this ugly code ? */ -+ -+ /* check if there is an url with such an index */ -+ hr = ICifComponent_GetUrl(comp, index, NULL, 0, flags); -+ if (FAILED(hr)) -+ { -+ *url = NULL; -+ *flags = 0; -+ return S_OK; -+ } -+ -+ do -+ { -+ size *= 2; -+ heap_free(url_temp); -+ url_temp = heap_alloc(size); -+ if (!url_temp) return E_OUTOFMEMORY; -+ -+ hr = ICifComponent_GetUrl(comp, index, url_temp, size, flags); -+ if (FAILED(hr)) -+ { -+ heap_free(url_temp); -+ return hr; -+ } -+ } -+ while (strlen(url_temp) == size-1); -+ -+ *url = url_temp; -+ return S_OK; -+} -+ -+static char *combine_url(char *baseurl, char *url) -+{ -+ int len_base = strlen(baseurl); -+ int len_url = strlen(url); -+ char *combined; -+ -+ combined = heap_alloc(len_base + len_url + 2); -+ if (!combined) return NULL; -+ -+ strcpy(combined, baseurl); -+ if (len_base && combined[len_base-1] != '/') -+ strcat(combined, "/"); -+ strcat(combined, url); -+ -+ return combined; -+} -+ -+static HRESULT generate_moniker(char *baseurl, char *url, DWORD flags, IMoniker **moniker) -+{ -+ WCHAR *urlW; -+ HRESULT hr; -+ -+ if (flags & URLF_RELATIVEURL) -+ { -+ char *combined; -+ if (!baseurl) -+ return E_FAIL; -+ -+ combined = combine_url(baseurl, url); -+ if (!combined) return E_OUTOFMEMORY; -+ -+ urlW = strAtoW(combined); -+ heap_free(combined); -+ if (!urlW) return E_OUTOFMEMORY; -+ } -+ else -+ { -+ urlW = strAtoW(url); -+ if (!urlW) return E_OUTOFMEMORY; -+ } -+ -+ hr = CreateURLMoniker(NULL, urlW, moniker); -+ heap_free(urlW); -+ return hr; -+} -+ -+static char *merge_path(char *path1, char *path2) -+{ -+ int len = strlen(path1) + strlen(path2) + 2; -+ char *combined = heap_alloc(len); -+ -+ if (!combined) return NULL; -+ strcpy(combined, path1); -+ strcat(combined, "\\"); -+ strcat(combined, path2); -+ -+ return combined; -+} -+ -+static HRESULT download_url(InstallEngine *This, char *id, char *display, char *url, DWORD flags, DWORD dl_size) -+{ -+ struct downloadcb *callback = NULL; -+ char *filename = NULL; -+ IUnknown *unk = NULL; -+ IMoniker *mon = NULL; -+ IBindCtx *bindctx = NULL; -+ HANDLE event = NULL; -+ HRESULT hr; -+ -+ if (!This->downloaddir) -+ { -+ WARN("No download directory set\n"); -+ return E_FAIL; -+ } -+ -+ hr = generate_moniker(This->baseurl, url, flags, &mon); -+ if (FAILED(hr)) -+ { -+ FIXME("Failed to create moniker\n"); -+ return hr; -+ } -+ -+ event = CreateEventW(NULL, TRUE, FALSE, NULL); -+ if (!event) -+ { -+ IMoniker_Release(mon); -+ return E_FAIL; -+ } -+ -+ filename = strrchr(url, '/'); -+ if (!filename) filename = url; -+ -+ filename = merge_path(This->downloaddir, filename); -+ if (!filename) -+ { -+ hr = E_OUTOFMEMORY; -+ goto error; -+ } -+ -+ hr = downloadcb_create(This, event, filename, id, display, dl_size, &callback); -+ if (FAILED(hr)) goto error; -+ -+ hr = CreateAsyncBindCtx(0, &callback->IBindStatusCallback_iface, NULL, &bindctx); -+ if(FAILED(hr)) goto error; -+ -+ hr = IMoniker_BindToStorage(mon, bindctx, NULL, &IID_IUnknown, (void**)&unk); -+ if (FAILED(hr)) goto error; -+ if (unk) IUnknown_Release(unk); -+ -+ heap_free(filename); -+ IMoniker_Release(mon); -+ IBindCtx_Release(bindctx); -+ -+ WaitForSingleObject(event, INFINITE); -+ hr = callback->hr; -+ -+ CloseHandle(event); -+ IBindStatusCallback_Release(&callback->IBindStatusCallback_iface); -+ return hr; -+ -+error: -+ if (mon) IMoniker_Release(mon); -+ if (event) CloseHandle(event); -+ if (callback) IBindStatusCallback_Release(&callback->IBindStatusCallback_iface); -+ if (bindctx) IBindCtx_Release(bindctx); -+ if (filename) heap_free(filename); -+ return hr; -+} -+ -+static HRESULT process_component_dependencies(InstallEngine *This, ICifComponent *comp) -+{ -+ char id[MAX_ID_LENGTH+1], type; -+ DWORD ver, build; -+ HRESULT hr; -+ int i; -+ -+ for (i = 0;; i++) -+ { -+ hr = ICifComponent_GetDependency(comp, i, id, sizeof(id), &type, &ver, &build); -+ if (SUCCEEDED(hr)) -+ FIXME("Can't handle dependencies yet: %s\n", debugstr_a(id)); -+ else -+ break; -+ } -+ -+ return S_OK; -+} -+ -+static HRESULT process_component(InstallEngine *This, ICifComponent *comp) -+{ -+ DWORD size_dl, size_install, phase; -+ char display[MAX_DISPLAYNAME_LENGTH+1]; -+ char id[MAX_ID_LENGTH+1]; -+ HRESULT hr; -+ int i; -+ -+ hr = ICifComponent_GetID(comp, id, sizeof(id)); -+ if (FAILED(hr)) return hr; -+ -+ TRACE("processing component %s\n", debugstr_a(id)); -+ -+ hr = ICifComponent_GetDescription(comp, display, sizeof(display)); -+ if (FAILED(hr)) return hr; -+ -+ size_dl = (This->thread.operation == OP_DOWNLOAD) ? ICifComponent_GetDownloadSize(comp) : 0; -+ size_install = 0; /* (This->thread.operation == OP_INSTALL) ? ICifComponent_GetInstalledSize(comp) : 0; */ -+ -+ if (This->callback) -+ { -+ IInstallEngineCallback_OnStartComponent(This->callback, id, size_dl, size_install, display); -+ IInstallEngineCallback_OnComponentProgress(This->callback, id, INSTALLSTATUS_INITIALIZING, display, NULL, 0, 0); -+ phase = INSTALLSTATUS_INITIALIZING; -+ } -+ -+ hr = process_component_dependencies(This, comp); -+ if (FAILED(hr)) return hr; -+ -+ if (This->thread.operation == OP_DOWNLOAD) -+ { -+ for (i = 0;; i++) -+ { -+ DWORD flags; -+ char *url; -+ -+ phase = INSTALLSTATUS_DOWNLOADING; -+ -+ hr = get_url(comp, i, &url, &flags); -+ if (FAILED(hr)) goto done; -+ if (!url) break; -+ -+ TRACE("processing url %s\n", debugstr_a(url)); -+ -+ hr = download_url(This, id, display, url, flags, size_dl); -+ heap_free(url); -+ if (FAILED(hr)) -+ { -+ DWORD retry = 0; -+ -+ if (This->callback) -+ IInstallEngineCallback_OnEngineProblem(This->callback, ENGINEPROBLEM_DOWNLOADFAIL, &retry); -+ if (!retry) goto done; -+ -+ i--; -+ continue; -+ } -+ -+ phase = INSTALLSTATUS_CHECKINGTRUST; -+ /* FIXME: check trust */ -+ IInstallEngineCallback_OnComponentProgress(This->callback, id, INSTALLSTATUS_CHECKINGTRUST, display, NULL, 0, 0); -+ } -+ -+ component_set_downloaded(comp, TRUE); -+ phase = INSTALLSTATUS_DOWNLOADFINISHED; -+ } -+ else -+ FIXME("Installation not yet implemented\n"); -+ -+done: -+ IInstallEngineCallback_OnStopComponent(This->callback, id, hr, phase, display, 0); -+ return hr; -+} -+ -+DWORD WINAPI thread_installation(LPVOID param) -+{ -+ InstallEngine *This = param; -+ ICifComponent *comp; -+ HRESULT hr; -+ -+ if (This->callback) -+ IInstallEngineCallback_OnStartInstall(This->callback, This->thread.download_size, This->thread.install_size); -+ -+ for (;;) -+ { -+ hr = get_next_component(This->thread.enum_comp, This->thread.operation, &comp); -+ if (FAILED(hr)) break; -+ if (hr == S_FALSE) -+ { -+ hr = S_OK; -+ break; -+ } -+ -+ hr = process_component(This, comp); -+ if (FAILED(hr)) break; -+ } -+ -+ if (This->callback) -+ IInstallEngineCallback_OnStopInstall(This->callback, hr, NULL, 0); -+ -+ IEnumCifComponents_Release(This->thread.enum_comp); -+ IInstallEngine2_Release(&This->IInstallEngine2_iface); -+ -+ set_status(This, ENGINESTATUS_READY); -+ return 0; -+} -+ -+static HRESULT start_installation(InstallEngine *This, DWORD operation, DWORD jobflags) -+{ -+ HANDLE thread; -+ HRESULT hr; -+ -+ This->thread.operation = operation; -+ This->thread.jobflags = jobflags; -+ This->thread.downloaded_kb = 0; -+ This->thread.download_start = 0; -+ -+ /* Windows sends the OnStartInstall event from a different thread, -+ * but OnStartInstall already contains the required download and install size. -+ * The only way to signal an error from the thread is to send an OnStopComponent / -+ * OnStopInstall signal which can only occur after OnStartInstall. We need to -+ * precompute the sizes here to be able inform the application about errors while -+ * calculating the required sizes. */ -+ -+ hr = ICifFile_EnumComponents(This->icif, &This->thread.enum_comp, 0, NULL); -+ if (FAILED(hr)) return hr; -+ -+ hr = calc_sizes(This->thread.enum_comp, operation, &This->thread.download_size, &This->thread.install_size); -+ if (FAILED(hr)) goto error; -+ -+ IInstallEngine2_AddRef(&This->IInstallEngine2_iface); -+ -+ thread = CreateThread(NULL, 0, thread_installation, This, 0, NULL); -+ if (!thread) -+ { -+ IInstallEngine2_Release(&This->IInstallEngine2_iface); -+ hr = E_FAIL; -+ goto error; -+ } -+ -+ CloseHandle(thread); -+ return S_OK; -+ -+error: -+ IEnumCifComponents_Release(This->thread.enum_comp); -+ return hr; -+} -+ - static HRESULT WINAPI InstallEngine_GetEngineStatus(IInstallEngine2 *iface, DWORD *status) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%p)\n", This, status); -- return E_NOTIMPL; -+ -+ TRACE("(%p)->(%p)\n", This, status); -+ -+ if (!status) -+ return E_FAIL; -+ -+ *status = This->status; -+ return S_OK; - } - - static HRESULT WINAPI InstallEngine_SetCifFile(IInstallEngine2 *iface, const char *cab_name, const char *cif_name) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s %s)\n", This, debugstr_a(cab_name), debugstr_a(cif_name)); -+ -+ FIXME("(%p)->(%s %s): stub\n", This, debugstr_a(cab_name), debugstr_a(cif_name)); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_DownloadComponents(IInstallEngine2 *iface, DWORD flags) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%x)\n", This, flags); -- return E_NOTIMPL; -+ -+ TRACE("(%p)->(%x)\n", This, flags); -+ -+ /* The interface is not really threadsafe on windows, but we can at least prevent multiple installations */ -+ if (InterlockedCompareExchange((LONG *)&This->status, ENGINESTATUS_INSTALLING, ENGINESTATUS_READY) != ENGINESTATUS_READY) -+ return E_FAIL; -+ -+ if (This->callback) -+ IInstallEngineCallback_OnEngineStatusChange(This->callback, ENGINESTATUS_INSTALLING, 0); -+ -+ return start_installation(This, OP_DOWNLOAD, flags); - } - - static HRESULT WINAPI InstallEngine_InstallComponents(IInstallEngine2 *iface, DWORD flags) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%x)\n", This, flags); -+ -+ FIXME("(%p)->(%x): stub\n", This, flags); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_EnumInstallIDs(IInstallEngine2 *iface, UINT index, char **id) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%d %p)\n", This, index, id); -+ -+ FIXME("(%p)->(%u %p): stub\n", This, index, id); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_EnumDownloadIDs(IInstallEngine2 *iface, UINT index, char **id) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%d %p)\n", This, index, id); -- return E_NOTIMPL; -+ IEnumCifComponents *enum_components; -+ ICifComponent *comp; -+ HRESULT hr; -+ -+ TRACE("(%p)->(%u %p)\n", This, index, id); -+ -+ if (!This->icif || !id) -+ return E_FAIL; -+ -+ hr = ICifFile_EnumComponents(This->icif, &enum_components, 0, NULL); -+ if (FAILED(hr)) return hr; -+ -+ for (;;) -+ { -+ hr = IEnumCifComponents_Next(enum_components, &comp); -+ if (FAILED(hr)) goto done; -+ -+ if (ICifComponent_GetInstallQueueState(comp) != ActionInstall) -+ continue; -+ -+ if (ICifComponent_IsComponentDownloaded(comp) != S_FALSE) -+ continue; -+ -+ if (index == 0) -+ { -+ char *id_src = component_get_id(comp); -+ *id = CoTaskMemAlloc(strlen(id_src) + 1); -+ -+ if (*id) -+ strcpy(*id, id_src); -+ else -+ hr = E_OUTOFMEMORY; -+ goto done; -+ } -+ -+ index--; -+ } -+ -+done: -+ IEnumCifComponents_Release(enum_components); -+ return hr; - } - - static HRESULT WINAPI InstallEngine_IsComponentInstalled(IInstallEngine2 *iface, const char *id, DWORD *status) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s %p)\n", This, debugstr_a(id), status); -+ -+ FIXME("(%p)->(%s %p): stub\n", This, debugstr_a(id), status); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_RegisterInstallEngineCallback(IInstallEngine2 *iface, IInstallEngineCallback *callback) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%p)\n", This, callback); -- return E_NOTIMPL; -+ -+ TRACE("(%p)->(%p)\n", This, callback); -+ -+ This->callback = callback; -+ return S_OK; - } - - static HRESULT WINAPI InstallEngine_UnregisterInstallEngineCallback(IInstallEngine2 *iface) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)\n", This); -- return E_NOTIMPL; -+ -+ TRACE("(%p)\n", This); -+ -+ This->callback = NULL; -+ return S_OK; - } - - static HRESULT WINAPI InstallEngine_SetAction(IInstallEngine2 *iface, const char *id, DWORD action, DWORD priority) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s %d %d)\n", This, debugstr_a(id), action, priority); -- return E_NOTIMPL; -+ ICifComponent *comp; -+ HRESULT hr; -+ -+ TRACE("(%p)->(%s %u %u)\n", This, debugstr_a(id), action, priority); -+ -+ if (!This->icif) -+ return E_FAIL; /* FIXME: check error code */ -+ -+ hr = ICifFile_FindComponent(This->icif, id, &comp); -+ if (FAILED(hr)) return hr; -+ -+ hr = ICifComponent_SetInstallQueueState(comp, action); -+ if (FAILED(hr)) return hr; -+ -+ hr = ICifComponent_SetCurrentPriority(comp, priority); -+ return hr; - } - - static HRESULT WINAPI InstallEngine_GetSizes(IInstallEngine2 *iface, const char *id, COMPONENT_SIZES *sizes) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s %p)\n", This, debugstr_a(id), sizes); -+ -+ FIXME("(%p)->(%s %p): stub\n", This, debugstr_a(id), sizes); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_LaunchExtraCommand(IInstallEngine2 *iface, const char *inf_name, const char *section) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s %s)\n", This, debugstr_a(inf_name), debugstr_a(section)); -+ -+ FIXME("(%p)->(%s %s): stub\n", This, debugstr_a(inf_name), debugstr_a(section)); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_GetDisplayName(IInstallEngine2 *iface, const char *id, const char *name) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s %s)\n", This, debugstr_a(id), debugstr_a(name)); -+ -+ FIXME("(%p)->(%s %s): stub\n", This, debugstr_a(id), debugstr_a(name)); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_SetBaseUrl(IInstallEngine2 *iface, const char *base_name) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s)\n", This, debugstr_a(base_name)); -- return E_NOTIMPL; -+ -+ TRACE("(%p)->(%s)\n", This, debugstr_a(base_name)); -+ -+ if (This->baseurl) -+ heap_free(This->baseurl); -+ -+ This->baseurl = strdupA(base_name); -+ return This->baseurl ? S_OK : E_OUTOFMEMORY; - } - - static HRESULT WINAPI InstallEngine_SetDownloadDir(IInstallEngine2 *iface, const char *download_dir) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s)\n", This, debugstr_a(download_dir)); -- return E_NOTIMPL; -+ -+ TRACE("(%p)->(%s)\n", This, debugstr_a(download_dir)); -+ -+ if (This->downloaddir) -+ heap_free(This->downloaddir); -+ -+ This->downloaddir = strdupA(download_dir); -+ return This->downloaddir ? S_OK : E_OUTOFMEMORY; - } - - static HRESULT WINAPI InstallEngine_SetInstallDrive(IInstallEngine2 *iface, char drive) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%c)\n", This, drive); -+ -+ FIXME("(%p)->(%c): stub\n", This, drive); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_SetInstallOptions(IInstallEngine2 *iface, DWORD flags) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%x)\n", This, flags); -+ -+ FIXME("(%p)->(%x): stub\n", This, flags); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_SetHWND(IInstallEngine2 *iface, HWND hwnd) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%p)\n", This, hwnd); -+ -+ FIXME("(%p)->(%p): stub\n", This, hwnd); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_SetIStream(IInstallEngine2 *iface, IStream *stream) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%p)\n", This, stream); -+ -+ FIXME("(%p)->(%p): stub\n", This, stream); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_Abort(IInstallEngine2 *iface, DWORD flags) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%x)\n", This, flags); -+ -+ FIXME("(%p)->(%x): stub\n", This, flags); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_Suspend(IInstallEngine2 *iface) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)\n", This); -+ -+ FIXME("(%p): stub\n", This); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine_Resume(IInstallEngine2 *iface) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)\n", This); -+ -+ FIXME("(%p): stub\n", This); -+ - return E_NOTIMPL; - } - - static HRESULT WINAPI InstallEngine2_SetLocalCif(IInstallEngine2 *iface, const char *cif) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%s)\n", This, debugstr_a(cif)); -- return E_NOTIMPL; -+ HRESULT hr; -+ -+ TRACE("(%p)->(%s)\n", This, debugstr_a(cif)); -+ -+ if (This->icif) -+ ICifFile_Release(This->icif); -+ -+ set_status(This, ENGINESTATUS_LOADING); -+ -+ hr = GetICifFileFromFile(&This->icif, cif); -+ if (SUCCEEDED(hr)) -+ set_status(This, ENGINESTATUS_READY); -+ else -+ { -+ This->icif = NULL; -+ set_status(This, ENGINESTATUS_NOTREADY); -+ } -+ return hr; - } - - static HRESULT WINAPI InstallEngine2_GetICifFile(IInstallEngine2 *iface, ICifFile **cif_file) - { - InstallEngine *This = impl_from_IInstallEngine2(iface); -- FIXME("(%p)->(%p)\n", This, cif_file); -- return E_NOTIMPL; -+ -+ TRACE("(%p)->(%p)\n", This, cif_file); -+ -+ if (!This->icif || !cif_file) -+ return E_FAIL; -+ -+ ICifFile_AddRef(This->icif); -+ *cif_file = This->icif; -+ return S_OK; - } - --static const IInstallEngine2Vtbl InstallEngine2Vtbl = { -+static const IInstallEngine2Vtbl InstallEngine2Vtbl = -+{ - InstallEngine_QueryInterface, - InstallEngine_AddRef, - InstallEngine_Release, -@@ -290,6 +1134,70 @@ static const IInstallEngine2Vtbl InstallEngine2Vtbl = { - InstallEngine2_GetICifFile - }; - -+static HRESULT WINAPI InstallEngineTiming_QueryInterface(IInstallEngineTiming *iface, REFIID riid, void **ppv) -+{ -+ InstallEngine *This = impl_from_IInstallEngineTiming(iface); -+ return IInstallEngine2_QueryInterface(&This->IInstallEngine2_iface, riid, ppv); -+} -+ -+static ULONG WINAPI InstallEngineTiming_AddRef(IInstallEngineTiming *iface) -+{ -+ InstallEngine *This = impl_from_IInstallEngineTiming(iface); -+ return IInstallEngine2_AddRef(&This->IInstallEngine2_iface); -+} -+ -+static ULONG WINAPI InstallEngineTiming_Release(IInstallEngineTiming *iface) -+{ -+ InstallEngine *This = impl_from_IInstallEngineTiming(iface); -+ return IInstallEngine2_Release(&This->IInstallEngine2_iface); -+} -+ -+static HRESULT WINAPI InstallEngineTiming_GetRates(IInstallEngineTiming *iface, DWORD *download, DWORD *install) -+{ -+ InstallEngine *This = impl_from_IInstallEngineTiming(iface); -+ -+ FIXME("(%p)->(%p, %p): stub\n", This, download, install); -+ -+ *download = 0; -+ *install = 0; -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI InstallEngineTiming_GetInstallProgress(IInstallEngineTiming *iface, INSTALLPROGRESS *progress) -+{ -+ InstallEngine *This = impl_from_IInstallEngineTiming(iface); -+ ULONGLONG elapsed; -+ static int once; -+ -+ if (!once) -+ FIXME("(%p)->(%p): semi-stub\n", This, progress); -+ else -+ TRACE("(%p)->(%p): semi-stub\n", This, progress); -+ -+ progress->dwDownloadKBRemaining = max(This->thread.download_size, This->thread.downloaded_kb) - This->thread.downloaded_kb; -+ -+ elapsed = GetTickCount64() - This->thread.download_start; -+ if (This->thread.download_start && This->thread.downloaded_kb && elapsed > 100) -+ progress->dwDownloadSecsRemaining = (progress->dwDownloadKBRemaining * elapsed) / (This->thread.downloaded_kb * 1000); -+ else -+ progress->dwDownloadSecsRemaining = -1; -+ -+ progress->dwInstallKBRemaining = 0; -+ progress->dwInstallSecsRemaining = -1; -+ -+ return S_OK; -+} -+ -+static const IInstallEngineTimingVtbl InstallEngineTimingVtbl = -+{ -+ InstallEngineTiming_QueryInterface, -+ InstallEngineTiming_AddRef, -+ InstallEngineTiming_Release, -+ InstallEngineTiming_GetRates, -+ InstallEngineTiming_GetInstallProgress, -+}; -+ - static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv) - { - *ppv = NULL; -@@ -334,12 +1242,14 @@ static HRESULT WINAPI InstallEngineCF_CreateInstance(IClassFactory *iface, IUnkn - - TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv); - -- engine = heap_alloc(sizeof(*engine)); -+ engine = heap_alloc_zero(sizeof(*engine)); - if(!engine) - return E_OUTOFMEMORY; - - engine->IInstallEngine2_iface.lpVtbl = &InstallEngine2Vtbl; -+ engine->IInstallEngineTiming_iface.lpVtbl = &InstallEngineTimingVtbl; - engine->ref = 1; -+ engine->status = ENGINESTATUS_NOTREADY; - - hres = IInstallEngine2_QueryInterface(&engine->IInstallEngine2_iface, riid, ppv); - IInstallEngine2_Release(&engine->IInstallEngine2_iface); -diff --git a/dlls/inseng/inseng_private.h b/dlls/inseng/inseng_private.h -new file mode 100644 -index 00000000000..55d3899808a ---- /dev/null -+++ b/dlls/inseng/inseng_private.h -@@ -0,0 +1,79 @@ -+/* -+ * Copyright 2016 Michael Müller -+ * -+ * 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 "winbase.h" -+#include "winuser.h" -+#include "ole2.h" -+#include "rpcproxy.h" -+#include "inseng.h" -+#include "wine/heap.h" -+ -+ -+static inline char *strdupA(const char *src) -+{ -+ char *dest = heap_alloc(strlen(src) + 1); -+ if (dest) strcpy(dest, src); -+ return dest; -+} -+ -+static inline WCHAR *strdupW(const WCHAR *src) -+{ -+ WCHAR *dest; -+ if (!src) return NULL; -+ dest = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(src) + 1) * sizeof(WCHAR)); -+ if (dest) lstrcpyW(dest, src); -+ return dest; -+} -+ -+static inline LPWSTR strAtoW(const char *str) -+{ -+ LPWSTR ret = NULL; -+ -+ if (str) -+ { -+ DWORD len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 ); -+ if ((ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) -+ MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len); -+ } -+ -+ return ret; -+} -+ -+struct inf_value; -+struct inf_section; -+struct inf_file; -+ -+HRESULT inf_load(const char *path, struct inf_file **inf_file) DECLSPEC_HIDDEN; -+void inf_free(struct inf_file *inf) DECLSPEC_HIDDEN; -+ -+BOOL inf_next_section(struct inf_file *inf, struct inf_section **sec) DECLSPEC_HIDDEN; -+struct inf_section *inf_get_section(struct inf_file *inf, const char *name) DECLSPEC_HIDDEN; -+char *inf_section_get_name(struct inf_section *section) DECLSPEC_HIDDEN; -+BOOL inf_section_next_value(struct inf_section *sec, struct inf_value **value) DECLSPEC_HIDDEN; -+ -+struct inf_value *inf_get_value(struct inf_section *sec, const char *key) DECLSPEC_HIDDEN; -+char *inf_value_get_key(struct inf_value *value) DECLSPEC_HIDDEN; -+char *inf_value_get_value(struct inf_value *value) DECLSPEC_HIDDEN; -+ -+char *trim(char *str, char **last_chr, BOOL strip_quotes) DECLSPEC_HIDDEN; -+ -+void component_set_actual_download_size(ICifComponent *iface, DWORD size) DECLSPEC_HIDDEN; -+void component_set_downloaded(ICifComponent *iface, BOOL value) DECLSPEC_HIDDEN; -+void component_set_installed(ICifComponent *iface, BOOL value) DECLSPEC_HIDDEN; -+ char *component_get_id(ICifComponent *iface) DECLSPEC_HIDDEN; -diff --git a/include/inseng.idl b/include/inseng.idl -index 8a3f4c4d270..82927418a99 100644 ---- a/include/inseng.idl -+++ b/include/inseng.idl -@@ -1,5 +1,6 @@ - /* - * Copyright 2015 Jacek Caban for CodeWeavers -+ * Copyright 2016 Michael Müller - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public -@@ -26,15 +27,231 @@ cpp_quote("#endif") - - interface IStream; - --/* FIXME: Add full declarations. */ --interface ICifComponent; --interface IEnumCifComponents; --interface ICifGroup; --interface IEnumCifGroups; --interface ICifMode; --interface IEnumCifModes; -+cpp_quote("#define MAX_ID_LENGTH 48") -+cpp_quote("#define MAX_DISPLAYNAME_LENGTH 128") - --typedef struct { -+cpp_quote("#define URLF_DEFAULT 0x0") -+cpp_quote("#define URLF_EXTRACT 0x1") -+cpp_quote("#define URLF_RELATIVEURL 0x2") -+cpp_quote("#define URLF_DELETE_AFTER_EXTRACT 0x4") -+ -+cpp_quote("#define ENGINESTATUS_NOTREADY 0x0") -+cpp_quote("#define ENGINESTATUS_LOADING 0x1") -+cpp_quote("#define ENGINESTATUS_INSTALLING 0x2") -+cpp_quote("#define ENGINESTATUS_READY 0x3") -+ -+cpp_quote("#define SETACTION_NONE 0x0") -+cpp_quote("#define SETACTION_INSTALL 0x1") -+ -+cpp_quote("#define INSTALLOPTIONS_NOCACHE 0x01") -+cpp_quote("#define INSTALLOPTIONS_DOWNLOAD 0x02") -+cpp_quote("#define INSTALLOPTIONS_INSTALL 0x04") -+cpp_quote("#define INSTALLOPTIONS_DONTALLOWXPLATFORM 0x08") -+cpp_quote("#define INSTALLOPTIONS_FORCEDEPENDENCIES 0x10") -+ -+cpp_quote("#define EXECUTEJOB_SILENT 0x01") -+cpp_quote("#define EXECUTEJOB_DELETE_JOB 0x02") -+cpp_quote("#define EXECUTEJOB_VERIFYFILES 0x08") -+cpp_quote("#define EXECUTEJOB_IGNORETRUST 0x10") -+cpp_quote("#define EXECUTEJOB_IGNOREDOWNLOADERROR 0x20") -+cpp_quote("#define EXECUTEJOB_DONTALLOWCANCEL 0x40") -+ -+cpp_quote("#define ENGINEPROBLEM_DOWNLOADFAIL 0x1") -+ -+cpp_quote("#define PLATFORM_WIN95 0x01") -+cpp_quote("#define PLATFORM_WIN98 0x02") -+cpp_quote("#define PLATFORM_NT4 0x04") -+cpp_quote("#define PLATFORM_NT5 0x08") -+cpp_quote("#define PLATFORM_NT4ALPHA 0x10") -+cpp_quote("#define PLATFORM_NT5ALPHA 0x20") -+cpp_quote("#define PLATFORM_MILLEN 0x40") -+cpp_quote("#define PLATFORM_ALL (PLATFORM_WIN95 | PLATFORM_WIN98 | PLATFORM_NT4 | PLATFORM_NT5 | PLATFORM_NT4ALPHA | PLATFORM_NT5ALPHA | PLATFORM_MILLEN)") -+ -+enum InstallStatus -+{ -+ INSTALLSTATUS_INITIALIZING, -+ INSTALLSTATUS_DEPENDENCY, -+ INSTALLSTATUS_DOWNLOADING, -+ INSTALLSTATUS_COPYING, -+ INSTALLSTATUS_RETRYING, -+ INSTALLSTATUS_CHECKINGTRUST, -+ INSTALLSTATUS_EXTRACTING, -+ INSTALLSTATUS_RUNNING, -+ INSTALLSTATUS_FINISHED, -+ INSTALLSTATUS_DOWNLOADFINISHED, -+}; -+ -+enum ComponentAction -+{ -+ ActionNone, -+ ActionInstall, -+ ActionUninstall, -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface ICifComponent -+{ -+ HRESULT GetID(char *id, DWORD size); -+ HRESULT GetGUID(char *guid, DWORD size); -+ HRESULT GetDescription(char *desc, DWORD size); -+ HRESULT GetDetails(char *details, DWORD size); -+ HRESULT GetUrl(UINT index, char *url, DWORD size, DWORD *flags); -+ HRESULT GetFileExtractList(UINT index, char *extract, DWORD size); -+ HRESULT GetUrlCheckRange(UINT index, DWORD *min, DWORD *max); -+ HRESULT GetCommand(UINT index, char *cmd, DWORD cmd_size, char *switches, DWORD switch_size, DWORD *type); -+ HRESULT GetVersion(DWORD *version, DWORD *build); -+ HRESULT GetLocale(char *pszLocale, DWORD size); -+ HRESULT GetUninstallKey(char *key, DWORD size); -+ HRESULT GetInstalledSize(DWORD *win, DWORD *app); -+ DWORD GetDownloadSize(); -+ DWORD GetExtractSize(); -+ HRESULT GetSuccessKey(char *key, DWORD size); -+ HRESULT GetProgressKeys(char *progress, DWORD progress_size, char *cancel, DWORD cancel_size); -+ HRESULT IsActiveSetupAware(); -+ HRESULT IsRebootRequired(); -+ HRESULT RequiresAdminRights(); -+ DWORD GetPriority(); -+ HRESULT GetDependency(UINT index, char *id, DWORD buf, char *type, DWORD *ver, DWORD *build); -+ DWORD GetPlatform(); -+ HRESULT GetMode(UINT index, char *mode, DWORD size); -+ HRESULT GetGroup(char *id, DWORD size); -+ HRESULT IsUIVisible(); -+ HRESULT GetPatchID(char *id, DWORD size); -+ HRESULT GetDetVersion(char *dll, DWORD dll_size, char *entry, DWORD entry_size); -+ HRESULT GetTreatAsOneComponents(UINT index, char *id, DWORD buf); -+ HRESULT GetCustomData(char *key, char *data, DWORD size); -+ DWORD IsComponentInstalled(); -+ HRESULT IsComponentDownloaded(); -+ DWORD IsThisVersionInstalled(DWORD version, DWORD build, DWORD *ret_version, DWORD *ret_build); -+ DWORD GetInstallQueueState(); -+ HRESULT SetInstallQueueState(DWORD state); -+ DWORD GetActualDownloadSize(); -+ DWORD GetCurrentPriority(); -+ HRESULT SetCurrentPriority(DWORD priority); -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface ICifRWComponent : ICifComponent -+{ -+ HRESULT SetGUID(const char *guid); -+ HRESULT SetDescription(const char *desc); -+ HRESULT SetUrl(UINT index, const char *url, DWORD url_flags); -+ HRESULT SetCommand(UINT index, const char *cmd, const char *switches, DWORD type); -+ HRESULT SetVersion(const char *version); -+ HRESULT SetUninstallKey(const char *key); -+ HRESULT SetInstalledSize(DWORD win, DWORD app); -+ HRESULT SetDownloadSize(DWORD size); -+ HRESULT SetExtractSize(DWORD size); -+ HRESULT DeleteDependency(const char *id, char type); -+ HRESULT AddDependency(const char *id, char type); -+ HRESULT SetUIVisible(BOOL visible); -+ HRESULT SetGroup(const char *id); -+ HRESULT SetPlatform(DWORD platform); -+ HRESULT SetPriority(DWORD priority); -+ HRESULT SetReboot(BOOL reboot); -+ HRESULT DeleteFromModes(const char *mode); -+ HRESULT AddToMode(const char *mode); -+ HRESULT SetModes(const char *mode); -+ HRESULT CopyComponent(const char *ciffile); -+ HRESULT AddToTreatAsOne(const char *compid); -+ HRESULT SetDetails(const char *desc); -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface IEnumCifComponents : IUnknown -+{ -+ HRESULT Next(ICifComponent **); -+ HRESULT Reset(); -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface ICifGroup -+{ -+ HRESULT GetID(char *id, DWORD size); -+ HRESULT GetDescription(char *desc, DWORD size); -+ DWORD GetPriority(); -+ -+ HRESULT EnumComponents(IEnumCifComponents **, DWORD filter, void *pv); -+ DWORD GetCurrentPriority(); -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface ICifRWGroup : ICifGroup -+{ -+ HRESULT SetDescription(const char *desc); -+ HRESULT SetPriority(DWORD priority); -+ HRESULT SetDetails(const char *details); -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface IEnumCifGroups : IUnknown -+{ -+ HRESULT Next(ICifGroup **); -+ HRESULT Reset(); -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface ICifMode -+{ -+ HRESULT GetID(char *id, DWORD size); -+ HRESULT GetDescription(char *desc, DWORD size); -+ HRESULT GetDetails(char *details, DWORD size); -+ -+ HRESULT EnumComponents(IEnumCifComponents **, DWORD filter, void *pv); -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface ICifRWMode : ICifMode -+{ -+ HRESULT SetDescription(const char *desc); -+ HRESULT SetDetails(const char *details); -+}; -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface IEnumCifModes : IUnknown -+{ -+ HRESULT Next(ICifMode **); -+ HRESULT Reset(); -+}; -+ -+typedef struct -+{ - DWORD cbSize; - DWORD dwInstallSize; - DWORD dwWinDriveSize; -@@ -49,6 +266,15 @@ typedef struct { - DWORD dwTotalDownloadSize; - } COMPONENT_SIZES; - -+typedef struct -+{ -+ DWORD cbSize; -+ DWORD dwDownloadKBRemaining; -+ DWORD dwInstallKBRemaining; -+ DWORD dwDownloadSecsRemaining; -+ DWORD dwInstallSecsRemaining; -+} INSTALLPROGRESS; -+ - [ - uuid(6e449688-c509-11cf-aafa-00aa00b6015c), - local -@@ -62,7 +288,24 @@ interface ICifFile : IUnknown - HRESULT EnumModes(IEnumCifModes **cuf_modes, DWORD filter, void *pv); - HRESULT FindMode(const char *id, ICifMode **p); - HRESULT GetDescription(char *desc, DWORD size); -- HRESULT GetDetDlls(char **dlls, DWORD size); -+ HRESULT GetDetDlls(char *dlls, DWORD size); -+} -+ -+[ -+ object, -+ local, -+ pointer_default(unique) -+] -+interface ICifRWFile : ICifFile -+{ -+ HRESULT SetDescription(const char *desc); -+ HRESULT CreateComponent(const char *id, ICifRWComponent **p); -+ HRESULT CreateGroup(const char *id, ICifRWGroup **p); -+ HRESULT CreateMode(const char *id, ICifRWMode **p); -+ HRESULT DeleteComponent(const char *id); -+ HRESULT DeleteGroup(const char *id); -+ HRESULT DeleteMode(const char *id); -+ HRESULT Flush(); - } - - [ -@@ -78,7 +321,7 @@ interface IInstallEngineCallback : IUnknown - const char *msg_string, ULONG progress, ULONG max); - HRESULT OnStopComponent(const char *id, HRESULT error, DWORD phrase, const char *string, DWORD status); - HRESULT OnStopInstall(HRESULT error, const char *error_string, DWORD status); -- HRESULT OnEngineProblem(DWORD problem, LPDWORD action); -+ HRESULT OnEngineProblem(DWORD problem, DWORD *action); - } - - [ -@@ -121,6 +364,16 @@ interface IInstallEngine2 : IInstallEngine - HRESULT GetICifFile(ICifFile **cif_file); - } - -+[ -+ uuid(6e449687-c509-11cf-aafa-00aa00b6015c), -+ local -+] -+interface IInstallEngineTiming : IUnknown -+{ -+ HRESULT GetRates(DWORD *download, DWORD *install); -+ HRESULT GetInstallProgress(INSTALLPROGRESS *progress); -+} -+ - [ - helpstring("Microsoft Active Setup Engine"), - threading(apartment), -@@ -134,3 +387,6 @@ coclass InstallEngine { } - uuid(bfc880f1-7484-11d0-8309-00aa00b6015c) - ] - coclass DownloadSiteMgr { } -+ -+cpp_quote("HRESULT WINAPI GetICifFileFromFile(ICifFile **, const char *);") -+cpp_quote("HRESULT WINAPI GetICifRWFileFromFile(ICifRWFile **, const char *);") --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/inseng-Implementation/definition b/patches/wine-hotfixes/staging-7.0/inseng-Implementation/definition deleted file mode 100644 index 8758f4ee4..000000000 --- a/patches/wine-hotfixes/staging-7.0/inseng-Implementation/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [39456] Implement CIF reader and download functionality in inseng.dll diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch b/patches/wine-hotfixes/staging-7.0/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch deleted file mode 100644 index 00a4e5ce9..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 5b1520dd617c454ac8e482260b6b437f6f98d185 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Mon, 3 Apr 2017 01:06:26 +0200 -Subject: [PATCH] ntdll: Add dummy apiset to PEB. - ---- - dlls/ntdll/loader.c | 2 ++ - include/Makefile.in | 1 + - include/apiset.h | 37 +++++++++++++++++++++++++++++++++++++ - include/winternl.h | 3 ++- - 4 files changed, 42 insertions(+), 1 deletion(-) - create mode 100644 include/apiset.h - -diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c -index 7a714a5aa6d..62d1b38f4c0 100644 ---- a/dlls/ntdll/loader.c -+++ b/dlls/ntdll/loader.c -@@ -164,6 +164,7 @@ static PEB_LDR_DATA ldr = - - static RTL_BITMAP tls_bitmap; - static RTL_BITMAP tls_expansion_bitmap; -+static API_SET_NAMESPACE_ARRAY apiset_map; - - static WINE_MODREF *cached_modref; - static WINE_MODREF *current_modref; -@@ -3626,6 +3627,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR - - peb->LdrData = &ldr; - peb->FastPebLock = &peb_lock; -+ peb->ApiSetMap = &apiset_map; - peb->TlsBitmap = &tls_bitmap; - peb->TlsExpansionBitmap = &tls_expansion_bitmap; - peb->LoaderLock = &loader_section; -diff --git a/include/Makefile.in b/include/Makefile.in -index 9133e5c6315..f56a60fae5e 100644 ---- a/include/Makefile.in -+++ b/include/Makefile.in -@@ -15,6 +15,7 @@ SOURCES = \ - amstream.idl \ - amva.h \ - amvideo.idl \ -+ apiset.h \ - appcompatapi.h \ - appmgmt.h \ - appmodel.h \ -diff --git a/include/apiset.h b/include/apiset.h -new file mode 100644 -index 00000000000..6801cd5f509 ---- /dev/null -+++ b/include/apiset.h -@@ -0,0 +1,37 @@ -+/* -+ * Copyright (C) 2017 Michael Müller -+ * -+ * 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 _API_SET_H_ -+#define _API_SET_H_ -+ -+#include -+ -+typedef struct _API_SET_NAMESPACE_ENTRY -+{ -+ ULONG NameOffset; -+ ULONG NameLength; -+ ULONG DataOffset; -+} API_SET_NAMESPACE_ENTRY, *PAPI_SET_NAMESPACE_ENTRY; -+ -+typedef struct _API_SET_NAMESPACE_ARRAY -+{ -+ ULONG Version; -+ ULONG Count; -+ API_SET_NAMESPACE_ENTRY Array[1]; -+} API_SET_NAMESPACE_ARRAY, *PAPI_SET_NAMESPACE_ARRAY; -+ -+#endif -diff --git a/include/winternl.h b/include/winternl.h -index 298ebbc2d36..163b7737e00 100644 ---- a/include/winternl.h -+++ b/include/winternl.h -@@ -23,6 +23,7 @@ - - #include - #include -+#include - - #ifdef __cplusplus - extern "C" { -@@ -321,7 +322,7 @@ typedef struct _PEB - PVOID KernelCallbackTable; /* 02c/058 */ - ULONG Reserved; /* 030/060 */ - ULONG AtlThunkSListPtr32; /* 034/064 */ -- PVOID /*PPEB_FREE_BLOCK*/ FreeList; /* 038/068 */ -+ PAPI_SET_NAMESPACE_ARRAY ApiSetMap; /* 038/068 */ - ULONG TlsExpansionCounter; /* 03c/070 */ - PRTL_BITMAP TlsBitmap; /* 040/078 */ - ULONG TlsBitmapBits[2]; /* 044/080 */ --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-ApiSetMap/definition b/patches/wine-hotfixes/staging-7.0/ntdll-ApiSetMap/definition deleted file mode 100644 index 042ee383c..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-ApiSetMap/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [44658] Add dummy apiset to PEB struct diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0002-ntdll-Add-inline-versions-of-RtlEnterCriticalSection.patch b/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0002-ntdll-Add-inline-versions-of-RtlEnterCriticalSection.patch deleted file mode 100644 index 9c7eb8687..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0002-ntdll-Add-inline-versions-of-RtlEnterCriticalSection.patch +++ /dev/null @@ -1,65 +0,0 @@ -From af5cd4a865337f9e37ad3e8548e325fcb0f51d54 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 5 Aug 2017 03:38:38 +0200 -Subject: [PATCH] ntdll: Add inline versions of RtlEnterCriticalSection / - RtlLeaveCriticalSections. - ---- - dlls/ntdll/ntdll_misc.h | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index 34af6b780cf..27de37d5b88 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -26,6 +26,7 @@ - #include "winnt.h" - #include "winternl.h" - #include "unixlib.h" -+#include "wine/debug.h" - #include "wine/asm.h" - - #define DECLARE_CRITICAL_SECTION(cs) \ -@@ -88,6 +89,39 @@ extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN; - extern int CDECL NTDLL__vsnprintf( char *str, SIZE_T len, const char *format, va_list args ) DECLSPEC_HIDDEN; - extern int CDECL NTDLL__vsnwprintf( WCHAR *str, SIZE_T len, const WCHAR *format, va_list args ) DECLSPEC_HIDDEN; - -+/* inline version of RtlEnterCriticalSection */ -+static inline void enter_critical_section( RTL_CRITICAL_SECTION *crit ) -+{ -+ if (InterlockedIncrement( &crit->LockCount )) -+ { -+ if (crit->OwningThread == ULongToHandle(GetCurrentThreadId())) -+ { -+ crit->RecursionCount++; -+ return; -+ } -+ RtlpWaitForCriticalSection( crit ); -+ } -+ crit->OwningThread = ULongToHandle(GetCurrentThreadId()); -+ crit->RecursionCount = 1; -+} -+ -+/* inline version of RtlLeaveCriticalSection */ -+static inline void leave_critical_section( RTL_CRITICAL_SECTION *crit ) -+{ -+ WINE_DECLARE_DEBUG_CHANNEL(ntdll); -+ if (--crit->RecursionCount) -+ { -+ if (crit->RecursionCount > 0) InterlockedDecrement( &crit->LockCount ); -+ else ERR_(ntdll)( "section %p is not acquired\n", crit ); -+ } -+ else -+ { -+ crit->OwningThread = 0; -+ if (InterlockedDecrement( &crit->LockCount ) >= 0) -+ RtlpUnWaitCriticalSection( crit ); -+ } -+} -+ - struct dllredirect_data - { - ULONG size; --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0003-ntdll-Use-fast-CS-functions-for-heap-locking.patch b/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0003-ntdll-Use-fast-CS-functions-for-heap-locking.patch deleted file mode 100644 index c1e1aff72..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0003-ntdll-Use-fast-CS-functions-for-heap-locking.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 50e78099e8c5fbd74131e339b8e48488e1581c74 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 5 Aug 2017 03:39:23 +0200 -Subject: [PATCH] ntdll: Use fast CS functions for heap locking. - ---- - dlls/ntdll/heap.c | 50 +++++++++++++++++++++++------------------------ - 1 file changed, 25 insertions(+), 25 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index af2a489b727..178f81006d0 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index 32def2eb072..6b2e8978f1e 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -454,9 +454,9 @@ static HEAP *HEAP_GetPtr( - } - if (!(heapPtr->flags & HEAP_VALIDATE_ALL)) return heapPtr; - -- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - ret = HEAP_IsRealArena( heapPtr, heapPtr->flags, NULL, NOISY ); -- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - - if (ret) return heapPtr; - if (TRACE_ON(heap)) -@@ -1658,9 +1658,9 @@ void * WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE heap, ULONG flags, SIZE_ - if (!(status = HEAP_lfh_allocate( heap, flags, size, &ptr ))) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - status = HEAP_std_allocate( heap, flags, size, &ptr ); -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -1758,9 +1758,9 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE heap, ULONG flags, void *pt - if (!(status = HEAP_lfh_free( heap, flags, ptr ))) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - status = HEAP_std_free( heap, flags, ptr ); -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -1832,9 +1832,9 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - if (!(status = HEAP_lfh_reallocate( heap, flags, ptr, size, &ret ))) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - status = HEAP_std_reallocate( heap, flags, ptr, size, &ret ); -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -1986,7 +1986,7 @@ BOOLEAN WINAPI RtlLockHeap( HANDLE heap ) - { - HEAP *heapPtr = HEAP_GetPtr( heap ); - if (!heapPtr) return FALSE; -- RtlEnterCriticalSection( &heapPtr->critSection ); -+ enter_critical_section( &heapPtr->critSection ); - return TRUE; - } - -@@ -2007,7 +2007,7 @@ BOOLEAN WINAPI RtlUnlockHeap( HANDLE heap ) - { - HEAP *heapPtr = HEAP_GetPtr( heap ); - if (!heapPtr) return FALSE; -- RtlLeaveCriticalSection( &heapPtr->critSection ); -+ leave_critical_section( &heapPtr->critSection ); - return TRUE; - } - -@@ -2050,9 +2050,9 @@ SIZE_T WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, const void *ptr ) - if (!(status = HEAP_lfh_get_allocated_size( heap, flags, ptr, &size ))) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - status = HEAP_std_get_allocated_size( heap, flags, ptr, &size ); -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -2105,9 +2105,9 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, LPCVOID ptr ) - if (!HEAP_lfh_validate( heapPtr, flags, ptr )) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - if (!HEAP_IsRealArena( heapPtr, flags, ptr, QUIET )) status = STATUS_INVALID_PARAMETER; -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -2134,7 +2134,7 @@ NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr ) - - if (!heapPtr || !entry) return STATUS_INVALID_PARAMETER; - -- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - - /* FIXME: enumerate large blocks too */ - -@@ -2239,7 +2239,7 @@ NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr ) - if (TRACE_ON(heap)) HEAP_DumpEntry(entry); - - HW_end: -- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - return ret; - } - --- -2.17.1 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0004-ntdll-Use-fast-CS-functions-for-threadpool-locking.patch b/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0004-ntdll-Use-fast-CS-functions-for-threadpool-locking.patch deleted file mode 100644 index 566dd3c79..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-CriticalSection/0004-ntdll-Use-fast-CS-functions-for-threadpool-locking.patch +++ /dev/null @@ -1,396 +0,0 @@ -From 217794090443a96e712ffe3970e4a70ded2277dc Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 5 Aug 2017 03:39:37 +0200 -Subject: [PATCH] ntdll: Use fast CS functions for threadpool locking. - ---- - dlls/ntdll/threadpool.c | 90 ++++++++++++++++++++--------------------- - 1 file changed, 45 insertions(+), 45 deletions(-) - -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index ca323919d05..581d503b6a4 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -1053,7 +1053,7 @@ static void CALLBACK timerqueue_thread_proc( void *param ) - - TRACE( "starting timer queue thread\n" ); - -- RtlEnterCriticalSection( &timerqueue.cs ); -+ enter_critical_section( &timerqueue.cs ); - for (;;) - { - NtQuerySystemTime( &now ); -@@ -1126,7 +1126,7 @@ static void CALLBACK timerqueue_thread_proc( void *param ) - } - - timerqueue.thread_running = FALSE; -- RtlLeaveCriticalSection( &timerqueue.cs ); -+ leave_critical_section( &timerqueue.cs ); - - TRACE( "terminating timer queue thread\n" ); - RtlExitUserThread( 0 ); -@@ -1171,7 +1171,7 @@ static NTSTATUS tp_timerqueue_lock( struct threadpool_object *timer ) - timer->u.timer.period = 0; - timer->u.timer.window_length = 0; - -- RtlEnterCriticalSection( &timerqueue.cs ); -+ enter_critical_section( &timerqueue.cs ); - - /* Make sure that the timerqueue thread is running. */ - if (!timerqueue.thread_running) -@@ -1192,7 +1192,7 @@ static NTSTATUS tp_timerqueue_lock( struct threadpool_object *timer ) - timerqueue.objcount++; - } - -- RtlLeaveCriticalSection( &timerqueue.cs ); -+ leave_critical_section( &timerqueue.cs ); - return status; - } - -@@ -1205,7 +1205,7 @@ static void tp_timerqueue_unlock( struct threadpool_object *timer ) - { - assert( timer->type == TP_OBJECT_TYPE_TIMER ); - -- RtlEnterCriticalSection( &timerqueue.cs ); -+ enter_critical_section( &timerqueue.cs ); - if (timer->u.timer.timer_initialized) - { - /* If timer was pending, remove it. */ -@@ -1224,7 +1224,7 @@ static void tp_timerqueue_unlock( struct threadpool_object *timer ) - - timer->u.timer.timer_initialized = FALSE; - } -- RtlLeaveCriticalSection( &timerqueue.cs ); -+ leave_critical_section( &timerqueue.cs ); - } - - /*********************************************************************** -@@ -1242,7 +1242,7 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - - TRACE( "starting wait queue thread\n" ); - -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - for (;;) - { -@@ -1291,10 +1291,10 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - /* All wait objects have been destroyed, if no new wait objects are created - * within some amount of time, then we can shutdown this thread. */ - assert( num_handles == 0 ); -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - timeout.QuadPart = (ULONGLONG)THREADPOOL_WORKER_TIMEOUT * -10000; - status = NtWaitForMultipleObjects( 1, &bucket->update_event, TRUE, bucket->alertable, &timeout ); -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - if (status == STATUS_TIMEOUT && !bucket->objcount) - break; -@@ -1304,7 +1304,7 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - handles[num_handles] = bucket->update_event; - RtlLeaveCriticalSection( &waitqueue.cs ); - status = NtWaitForMultipleObjects( num_handles + 1, handles, TRUE, bucket->alertable, &timeout ); -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - if (status >= STATUS_WAIT_0 && status < STATUS_WAIT_0 + num_handles) - { -@@ -1388,7 +1388,7 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - if (!--waitqueue.num_buckets) - assert( list_empty( &waitqueue.buckets ) ); - -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - - TRACE( "terminating wait queue thread\n" ); - -@@ -1418,7 +1418,7 @@ static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait ) - wait->u.wait.timeout = 0; - wait->u.wait.handle = INVALID_HANDLE_VALUE; - -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - /* Try to assign to existing bucket if possible. */ - LIST_FOR_EACH_ENTRY( bucket, &waitqueue.buckets, struct waitqueue_bucket, bucket_entry ) -@@ -1475,7 +1475,7 @@ static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait ) - } - - out: -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - return status; - } - -@@ -1486,7 +1486,7 @@ static void tp_waitqueue_unlock( struct threadpool_object *wait ) - { - assert( wait->type == TP_OBJECT_TYPE_WAIT ); - -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - if (wait->u.wait.bucket) - { - struct waitqueue_bucket *bucket = wait->u.wait.bucket; -@@ -1498,7 +1498,7 @@ static void tp_waitqueue_unlock( struct threadpool_object *wait ) - - NtSetEvent( bucket->update_event, NULL ); - } -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - } - - static void CALLBACK ioqueue_thread_proc( void *param ) -@@ -1775,7 +1775,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON - pool = default_threadpool; - } - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - - /* Make sure that the threadpool has at least one thread. */ - if (!pool->num_workers) -@@ -1789,7 +1789,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON - pool->objcount++; - } - -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - - if (status != STATUS_SUCCESS) - return status; -@@ -1805,9 +1805,9 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON - */ - static void tp_threadpool_unlock( struct threadpool *pool ) - { -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - pool->objcount--; -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - tp_threadpool_release( pool ); - } - -@@ -1945,10 +1945,10 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - struct threadpool_group *group = object->group; - InterlockedIncrement( &group->refcount ); - -- RtlEnterCriticalSection( &group->cs ); -+ enter_critical_section( &group->cs ); - list_add_tail( &group->members, &object->group_entry ); - object->is_group_member = TRUE; -- RtlLeaveCriticalSection( &group->cs ); -+ leave_critical_section( &group->cs ); - } - - if (is_simple_callback) -@@ -1975,7 +1975,7 @@ static void tp_object_submit( struct threadpool_object *object, BOOL signaled ) - assert( !object->shutdown ); - assert( !pool->shutdown ); - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - - /* Start new worker threads if required. */ - if (pool->num_busy_workers >= pool->num_workers && -@@ -1998,7 +1998,7 @@ static void tp_object_submit( struct threadpool_object *object, BOOL signaled ) - RtlWakeConditionVariable( &pool->update_event ); - } - -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - } - - /*********************************************************************** -@@ -2011,7 +2011,7 @@ static void tp_object_cancel( struct threadpool_object *object ) - struct threadpool *pool = object->pool; - LONG pending_callbacks = 0; - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - if (object->num_pending_callbacks) - { - pending_callbacks = object->num_pending_callbacks; -@@ -2026,7 +2026,7 @@ static void tp_object_cancel( struct threadpool_object *object ) - object->u.io.skipped_count += object->u.io.pending_count; - object->u.io.pending_count = 0; - } -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - - while (pending_callbacks--) - tp_object_release( object ); -@@ -2055,7 +2055,7 @@ static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) - { - struct threadpool *pool = object->pool; - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - while (!object_is_finished( object, group_wait )) - { - if (group_wait) -@@ -2063,7 +2063,7 @@ static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) - else - RtlSleepConditionVariableCS( &object->finished_event, &pool->cs, NULL ); - } -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - } - - static void tp_ioqueue_unlock( struct threadpool_object *io ) -@@ -2117,13 +2117,13 @@ static BOOL tp_object_release( struct threadpool_object *object ) - { - struct threadpool_group *group = object->group; - -- RtlEnterCriticalSection( &group->cs ); -+ enter_critical_section( &group->cs ); - if (object->is_group_member) - { - list_remove( &object->group_entry ); - object->is_group_member = FALSE; - } -- RtlLeaveCriticalSection( &group->cs ); -+ leave_critical_section( &group->cs ); - - tp_group_release( group ); - } -@@ -2324,7 +2324,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - - TRACE( "starting worker thread for pool %p\n", pool ); - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - for (;;) - { - while ((ptr = threadpool_get_next_item( pool ))) -@@ -2364,7 +2364,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - } - } - pool->num_workers--; -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - - TRACE( "terminating worker thread for pool %p\n", pool ); - tp_threadpool_release( pool ); -@@ -2612,7 +2612,7 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance ) - return STATUS_SUCCESS; - - pool = object->pool; -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - - /* Start new worker threads if required. */ - if (pool->num_busy_workers >= pool->num_workers) -@@ -2627,7 +2627,7 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance ) - } - } - -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - this->may_run_long = TRUE; - return status; - } -@@ -2708,13 +2708,13 @@ VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) - return; - - pool = object->pool; -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - - object->num_associated_callbacks--; - if (object_is_finished( object, FALSE )) - RtlWakeAllConditionVariable( &object->finished_event ); - -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - this->associated = FALSE; - } - -@@ -2766,7 +2766,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p - - TRACE( "%p %u %p\n", group, cancel_pending, userdata ); - -- RtlEnterCriticalSection( &this->cs ); -+ enter_critical_section( &this->cs ); - - /* Unset group, increase references, and mark objects for shutdown */ - LIST_FOR_EACH_ENTRY_SAFE( object, next, &this->members, struct threadpool_object, group_entry ) -@@ -2792,7 +2792,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p - list_init( &members ); - list_move_tail( &members, &this->members ); - -- RtlLeaveCriticalSection( &this->cs ); -+ leave_critical_section( &this->cs ); - - /* Cancel pending callbacks if requested */ - if (cancel_pending) -@@ -2915,10 +2915,10 @@ VOID WINAPI TpSetPoolMaxThreads( TP_POOL *pool, DWORD maximum ) - - TRACE( "%p %u\n", pool, maximum ); - -- RtlEnterCriticalSection( &this->cs ); -+ enter_critical_section( &this->cs ); - this->max_workers = max( maximum, 1 ); - this->min_workers = min( this->min_workers, this->max_workers ); -- RtlLeaveCriticalSection( &this->cs ); -+ leave_critical_section( &this->cs ); - } - - /*********************************************************************** -@@ -2931,7 +2931,7 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum ) - - TRACE( "%p %u\n", pool, minimum ); - -- RtlEnterCriticalSection( &this->cs ); -+ enter_critical_section( &this->cs ); - - while (this->num_workers < minimum) - { -@@ -2946,7 +2946,7 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum ) - this->max_workers = max( this->min_workers, this->max_workers ); - } - -- RtlLeaveCriticalSection( &this->cs ); -+ leave_critical_section( &this->cs ); - return !status; - } - -@@ -2962,7 +2962,7 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO - - TRACE( "%p %p %u %u\n", timer, timeout, period, window_length ); - -- RtlEnterCriticalSection( &timerqueue.cs ); -+ enter_critical_section( &timerqueue.cs ); - - assert( this->u.timer.timer_initialized ); - this->u.timer.timer_set = timeout != NULL; -@@ -3022,7 +3022,7 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO - this->u.timer.timer_pending = TRUE; - } - -- RtlLeaveCriticalSection( &timerqueue.cs ); -+ leave_critical_section( &timerqueue.cs ); - - if (submit_timer) - tp_object_submit( this, FALSE ); -@@ -3038,7 +3038,7 @@ VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout ) - - TRACE( "%p %p %p\n", wait, handle, timeout ); - -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - assert( this->u.wait.bucket ); - this->u.wait.handle = handle; -@@ -3077,7 +3077,7 @@ VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout ) - NtSetEvent( bucket->update_event, NULL ); - } - -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - } - - /*********************************************************************** --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch b/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch deleted file mode 100644 index 86c661409..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 11107a30f5ddc2065d2b254fad2d10bc158a1ebb Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Tue, 19 Aug 2014 22:10:49 -0600 -Subject: [PATCH] ntdll: Implement retrieving DOS attributes in - [fd_]get_file_info(). - ---- - configure.ac | 12 ++++++++++++ - dlls/ntdll/unix/file.c | 39 ++++++++++++++++++++++++++++++++++++++- - 2 files changed, 50 insertions(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index d621ae6e712..3ddff238d74 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -65,6 +65,7 @@ AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use the libusb lib - AC_ARG_WITH(v4l2, AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)])) - AC_ARG_WITH(vkd3d, AS_HELP_STRING([--without-vkd3d],[do not use vkd3d (Direct3D 12 support)])) - AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) -+AC_ARG_WITH(xattr, AS_HELP_STRING([--without-xattr],[do not use xattr (security attributes support)])) - AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), - [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi]) - AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]), -@@ -642,6 +643,17 @@ AC_CHECK_HEADERS([libprocstat.h],,, - #include - #endif]) - -+if test "x$with_xattr" != "xno" -+then -+ AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) -+fi -+if test "x$with_xattr" = "xyes" -+then -+ WINE_ERROR_WITH(xattr,[test "x$HAVE_XATTR" = "x"],[xattr ${notice_platform}development files \ -+not found. Wine will be built without extended attribute support, which probably isn't what you \ -+want. You will need to install ${notice_platform}development packages of libattr at the very least.]) -+fi -+ - dnl **** Check for working dll **** - - AC_SUBST(DLLFLAGS,"") -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index e459087af76..0b6e5d3b6a7 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -98,6 +98,9 @@ - #ifdef HAVE_SYS_STATFS_H - #include - #endif -+#ifdef HAVE_ATTR_XATTR_H -+#include -+#endif - #include - #include - -@@ -355,6 +358,20 @@ NTSTATUS errno_to_status( int err ) - } - } - -+#ifndef XATTR_USER_PREFIX -+#define XATTR_USER_PREFIX "user." -+#endif -+ -+static int xattr_get( const char *path, const char *name, void *value, size_t size ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return getxattr( path, name, value, size ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ - /* get space from the current directory data buffer, allocating a new one if necessary */ - static void *get_dir_data_space( struct dir_data *data, unsigned int size ) - { -@@ -1436,6 +1453,22 @@ static BOOL append_entry( struct dir_data *data, const char *long_name, - } - - -+/* Match the Samba conventions for storing DOS file attributes */ -+#define SAMBA_XATTR_DOS_ATTRIB XATTR_USER_PREFIX "DOSATTRIB" -+/* We are only interested in some attributes, the others have corresponding Unix attributes */ -+#define XATTR_ATTRIBS_MASK (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM) -+ -+/* decode the xattr-stored DOS attributes */ -+static inline int get_file_xattr( char *hexattr, int attrlen ) -+{ -+ if (attrlen > 2 && hexattr[0] == '0' && hexattr[1] == 'x') -+ { -+ hexattr[attrlen] = 0; -+ return strtol( hexattr+2, NULL, 16 ) & XATTR_ATTRIBS_MASK; -+ } -+ return 0; -+} -+ - /* fetch the attributes of a file */ - static inline ULONG get_file_attributes( const struct stat *st ) - { -@@ -1479,7 +1512,8 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON - static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - { - char *parent_path; -- int ret; -+ char hexattr[11]; -+ int len, ret; - - *attr = 0; - ret = lstat( path, st ); -@@ -1505,6 +1539,9 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - free( parent_path ); - } - *attr |= get_file_attributes( st ); -+ len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); -+ if (len == -1) return ret; -+ *attr |= get_file_xattr( hexattr, len ); - return ret; - } - --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch b/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch deleted file mode 100644 index 1aa161614..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 06af804bd6e75332dd2be2005b443e285bc4f2dc Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Wed, 20 Aug 2014 00:08:52 -0600 -Subject: [PATCH] ntdll: Implement storing DOS attributes in - NtSetInformationFile. - ---- - dlls/ntdll/tests/file.c | 8 ++--- - dlls/ntdll/unix/file.c | 76 +++++++++++++++++++++++++++++------------ - 2 files changed, 59 insertions(+), 25 deletions(-) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 19ae5f2ac21..cb578ceee9e 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -1400,7 +1400,7 @@ static void test_file_basic_information(void) - memset(&fbi, 0, sizeof(fbi)); - res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't get attributes\n"); -- todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fbi.FileAttributes ); -+ ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM (ok in old linux without xattr)\n", fbi.FileAttributes ); - - /* Then HIDDEN */ - memset(&fbi, 0, sizeof(fbi)); -@@ -1413,7 +1413,7 @@ static void test_file_basic_information(void) - memset(&fbi, 0, sizeof(fbi)); - res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't get attributes\n"); -- todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fbi.FileAttributes ); -+ ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN (ok in old linux without xattr)\n", fbi.FileAttributes ); - - /* Check NORMAL last of all (to make sure we can clear attributes) */ - memset(&fbi, 0, sizeof(fbi)); -@@ -1470,7 +1470,7 @@ static void test_file_all_information(void) - memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); - res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); - ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res); -- todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fai_buf.fai.BasicInformation.FileAttributes ); -+ ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM (ok in old linux without xattr)\n", fai_buf.fai.BasicInformation.FileAttributes ); - - /* Then HIDDEN */ - memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); -@@ -1483,7 +1483,7 @@ static void test_file_all_information(void) - memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); - res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); - ok ( res == STATUS_SUCCESS, "can't get attributes\n"); -- todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fai_buf.fai.BasicInformation.FileAttributes ); -+ ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN (ok in old linux without xattr)\n", fai_buf.fai.BasicInformation.FileAttributes ); - - /* Check NORMAL last of all (to make sure we can clear attributes) */ - memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index a2cae9708db..9a1bd50c695 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -374,6 +374,26 @@ NTSTATUS errno_to_status( int err ) - #define XATTR_USER_PREFIX "user." - #endif - -+static int xattr_fremove( int filedes, const char *name ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return fremovexattr( filedes, name ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ -+static int xattr_fset( int filedes, const char *name, void *value, size_t size ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return fsetxattr( filedes, name, value, size, 0 ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ - static int xattr_get( const char *path, const char *name, void *value, size_t size ) - { - #if defined(HAVE_ATTR_XATTR_H) -@@ -1520,6 +1540,39 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON - } - - -+/* set the stat info and file attributes for a file (by file descriptor) */ -+NTSTATUS fd_set_file_info( int fd, ULONG attr ) -+{ -+ char hexattr[11]; -+ struct stat st; -+ -+ if (fstat( fd, &st ) == -1) return errno_to_status( errno ); -+ if (attr & FILE_ATTRIBUTE_READONLY) -+ { -+ if (S_ISDIR( st.st_mode)) -+ WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n"); -+ else -+ st.st_mode &= ~0222; /* clear write permission bits */ -+ } -+ else -+ { -+ /* add write permission only where we already have read permission */ -+ st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~start_umask); -+ } -+ if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno ); -+ attr &= ~FILE_ATTRIBUTE_NORMAL; /* do not store everything, but keep everything Samba can use */ -+ if (attr != 0) -+ { -+ int len; -+ -+ len = sprintf( hexattr, "0x%x", attr ); -+ xattr_fset( fd, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); -+ } -+ else -+ xattr_fremove( fd, SAMBA_XATTR_DOS_ATTRIB ); -+ return STATUS_SUCCESS; -+} -+ - /* get the stat info and file attributes for a file (by name) */ - static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - { -@@ -4356,7 +4409,6 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, - case FileBasicInformation: - if (len >= sizeof(FILE_BASIC_INFORMATION)) - { -- struct stat st; - const FILE_BASIC_INFORMATION *info = ptr; - LARGE_INTEGER mtime, atime; - -@@ -4686,33 +4686,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, - status = set_file_times( fd, &mtime, &atime ); - - if (status == STATUS_SUCCESS && info->FileAttributes) -- { -- if (fstat( fd, &st ) == -1) status = errno_to_status( errno ); -- else -- { -- if (info->FileAttributes & FILE_ATTRIBUTE_READONLY) -- { -- if (S_ISDIR( st.st_mode)) -- WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n"); -- else -- st.st_mode &= ~0222; /* clear write permission bits */ -- } -- else -- { -- if (is_wine_file(handle)) -- { -- TRACE("HACK: Not giving write permission to wine file!\n"); -- io->u.Status = STATUS_ACCESS_DENIED; -- } -- else -- { -- /* add write permission only where we already have read permission */ -- st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~start_umask); -- } -- } -- if (fchmod( fd, st.st_mode ) == -1) status = errno_to_status( errno ); -- } -- } -+ status = fd_set_file_info( fd, info->FileAttributes ); - - if (needs_close) close( fd ); - } --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch b/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch deleted file mode 100644 index c9dde1ab6..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 494342c8f911f827783f1aed9717d793c4e6a8c0 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Wed, 20 Aug 2014 15:28:00 -0600 -Subject: [PATCH] ntdll: Implement storing DOS attributes in NtCreateFile. - ---- - dlls/ntdll/tests/directory.c | 24 ++++++++--------- - dlls/ntdll/unix/file.c | 51 ++++++++++++++++++++++++++++++++---- - 2 files changed, 57 insertions(+), 18 deletions(-) - -diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c -index 6a423174664..fccd48f23e5 100644 ---- a/dlls/ntdll/tests/directory.c -+++ b/dlls/ntdll/tests/directory.c -@@ -55,7 +55,6 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG * - - /* The attribute sets to test */ - static struct testfile_s { -- BOOL todo; /* set if it doesn't work on wine yet */ - BOOL attr_done; /* set if attributes were tested for this file already */ - const DWORD attr; /* desired attribute */ - WCHAR name[20]; /* filename to use */ -@@ -63,16 +62,16 @@ static struct testfile_s { - const char *description; /* for error messages */ - int nfound; /* How many were found (expect 1) */ - } testfiles[] = { -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" }, -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" }, -- { 1, 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" }, -- { 1, 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" }, -- { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" }, -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, -- { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, -- { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } -+ { 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" }, -+ { 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" }, -+ { 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" }, -+ { 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" }, -+ { 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" }, -+ { 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, -+ { 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, -+ { 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, -+ { 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, -+ { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } - }; - static const int test_dir_count = ARRAY_SIZE(testfiles); - static const int max_test_dir_size = ARRAY_SIZE(testfiles) + 5; /* size of above plus some for .. etc */ -@@ -162,8 +161,7 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info) - if (namelen != len || memcmp(nameW, testfiles[i].name, len*sizeof(WCHAR))) - continue; - if (!testfiles[i].attr_done) { -- todo_wine_if (testfiles[i].todo) -- ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib); -+ ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib); - testfiles[i].attr_done = TRUE; - } - testfiles[i].nfound++; -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 9a1bd50c695..9b3735dd917 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -404,6 +404,26 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si - #endif - } - -+static int xattr_remove( const char *path, const char *name ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return removexattr( path, name ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ -+static int xattr_set( const char *path, const char *name, void *value, size_t size ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return setxattr( path, name, value, size, 0 ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ - /* get space from the current directory data buffer, allocating a new one if necessary */ - static void *get_dir_data_space( struct dir_data *data, unsigned int size ) - { -@@ -3783,6 +3803,20 @@ static NTSTATUS unmount_device( HANDLE handle ) - return status; - } - -+NTSTATUS set_file_info( const char *path, ULONG attr ) -+{ -+ char hexattr[11]; -+ int len; -+ -+ /* Note: unix mode already set when called this way */ -+ attr &= ~FILE_ATTRIBUTE_NORMAL; /* do not store everything, but keep everything Samba can use */ -+ len = sprintf( hexattr, "0x%x", attr ); -+ if (attr != 0) -+ xattr_set( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); -+ else -+ xattr_remove( path, SAMBA_XATTR_DOS_ATTRIB ); -+ return STATUS_SUCCESS; -+} - - /****************************************************************************** - * open_unix_file -@@ -3868,13 +3902,14 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - status = STATUS_SUCCESS; - } - -- if (status == STATUS_SUCCESS) -+ if (status != STATUS_SUCCESS) - { -- status = open_unix_file( handle, unix_name, access, &new_attr, attributes, -- sharing, disposition, options, ea_buffer, ea_length ); -- free( unix_name ); -+ WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status ); -+ return status; - } -- else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); -+ -+ status = open_unix_file( handle, unix_name, access, &new_attr, attributes, -+ sharing, disposition, options, ea_buffer, ea_length ); - - if (status == STATUS_SUCCESS) - { -@@ -3896,6 +3931,11 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - io->Information = FILE_OVERWRITTEN; - break; - } -+ if (io->Information == FILE_CREATED) -+ { -+ /* set any DOS extended attributes */ -+ set_file_info( unix_name, attributes ); -+ } - } - else if (status == STATUS_TOO_MANY_OPENED_FILES) - { -@@ -3904,6 +3944,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - } - - free( nt_name.Buffer ); -+ free( unix_name ); - return io->u.Status = status; - } - --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch b/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch deleted file mode 100644 index 0faf09924..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch +++ /dev/null @@ -1,97 +0,0 @@ -From c93462e9ca4529f413b82abaa76b593df9947cc6 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Mon, 6 Oct 2014 14:21:11 -0600 -Subject: [PATCH] libport: Add support for Mac OS X style extended attributes. - ---- - configure.ac | 3 +++ - dlls/ntdll/unix/file.c | 23 ++++++++++++++++++----- - 2 files changed, 21 insertions(+), 5 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 3ddff238d74..57f76f09b96 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -646,6 +646,9 @@ AC_CHECK_HEADERS([libprocstat.h],,, - if test "x$with_xattr" != "xno" - then - AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) -+ AC_CHECK_HEADERS(sys/xattr.h, [HAVE_XATTR=1] -+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[getxattr("", "", "", 0, 0, 0);]])], -+ [AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (Mac OS X)])])]) - fi - if test "x$with_xattr" = "xyes" - then -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 6f33d2c748f..d4cb708336c 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -99,7 +99,10 @@ - #include - #endif - #ifdef HAVE_ATTR_XATTR_H -+#undef XATTR_ADDITIONAL_OPTIONS - #include -+#elif defined(HAVE_SYS_XATTR_H) -+#include - #endif - #include - #include -@@ -364,7 +367,9 @@ NTSTATUS errno_to_status( int err ) - - static int xattr_fremove( int filedes, const char *name ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return fremovexattr( filedes, name, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return fremovexattr( filedes, name ); - #else - errno = ENOSYS; -@@ -374,7 +379,9 @@ static int xattr_fremove( int filedes, const char *name ) - - static int xattr_fset( int filedes, const char *name, void *value, size_t size ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return fsetxattr( filedes, name, value, size, 0, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return fsetxattr( filedes, name, value, size, 0 ); - #else - errno = ENOSYS; -@@ -384,7 +391,9 @@ static int xattr_fset( int filedes, const char *name, void *value, size_t size ) - - static int xattr_get( const char *path, const char *name, void *value, size_t size ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return getxattr( path, name, value, size, 0, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return getxattr( path, name, value, size ); - #else - errno = ENOSYS; -@@ -394,7 +403,9 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si - - static int xattr_remove( const char *path, const char *name ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return removexattr( path, name, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return removexattr( path, name ); - #else - errno = ENOSYS; -@@ -404,7 +415,9 @@ static int xattr_remove( const char *path, const char *name ) - - static int xattr_set( const char *path, const char *name, void *value, size_t size ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return setxattr( path, name, value, size, 0, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return setxattr( path, name, value, size, 0 ); - #else - errno = ENOSYS; --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch b/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch deleted file mode 100644 index c0c0ac831..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 691c8c2dfe1c14d968cf91f2356d4fca0611d579 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Mon, 6 Oct 2014 14:26:24 -0600 -Subject: [PATCH] ntdll: Add support for FreeBSD style extended attributes. - ---- - configure.ac | 2 +- - dlls/ntdll/unix/file.c | 37 +++++++++++++++++++++++++++++++++++++ - 2 files changed, 38 insertions(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 57f76f09b96..b99be0623b9 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -645,7 +645,7 @@ AC_CHECK_HEADERS([libprocstat.h],,, - - if test "x$with_xattr" != "xno" - then -- AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) -+ AC_CHECK_HEADERS(attr/xattr.h sys/extattr.h, [HAVE_XATTR=1]) - AC_CHECK_HEADERS(sys/xattr.h, [HAVE_XATTR=1] - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[getxattr("", "", "", 0, 0, 0);]])], - [AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (Mac OS X)])])]) -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index d4cb708336c..63fff5f7697 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -104,6 +104,10 @@ - #elif defined(HAVE_SYS_XATTR_H) - #include - #endif -+#ifdef HAVE_SYS_EXTATTR_H -+#undef XATTR_ADDITIONAL_OPTIONS -+#include -+#endif - #include - #include - -@@ -364,6 +368,21 @@ NTSTATUS errno_to_status( int err ) - #ifndef XATTR_USER_PREFIX - #define XATTR_USER_PREFIX "user." - #endif -+#ifndef XATTR_USER_PREFIX_LEN -+#define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1) -+#endif -+ -+#ifdef HAVE_SYS_EXTATTR_H -+static inline int xattr_valid_namespace( const char *name ) -+{ -+ if (strncmp( XATTR_USER_PREFIX, name, XATTR_USER_PREFIX_LEN ) != 0) -+ { -+ errno = EPERM; -+ return 0; -+ } -+ return 1; -+} -+#endif - - static int xattr_fremove( int filedes, const char *name ) - { -@@ -371,6 +390,9 @@ static int xattr_fremove( int filedes, const char *name ) - return fremovexattr( filedes, name, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return fremovexattr( filedes, name ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_delete_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN] ); - #else - errno = ENOSYS; - return -1; -@@ -383,6 +405,10 @@ static int xattr_fset( int filedes, const char *name, void *value, size_t size ) - return fsetxattr( filedes, name, value, size, 0, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return fsetxattr( filedes, name, value, size, 0 ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_set_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], -+ value, size ); - #else - errno = ENOSYS; - return -1; -@@ -395,6 +421,10 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si - return getxattr( path, name, value, size, 0, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return getxattr( path, name, value, size ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_get_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], -+ value, size ); - #else - errno = ENOSYS; - return -1; -@@ -407,6 +437,9 @@ static int xattr_remove( const char *path, const char *name ) - return removexattr( path, name, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return removexattr( path, name ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_delete_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN] ); - #else - errno = ENOSYS; - return -1; -@@ -419,6 +452,10 @@ static int xattr_set( const char *path, const char *name, void *value, size_t si - return setxattr( path, name, value, size, 0, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return setxattr( path, name, value, size, 0 ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_set_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], -+ value, size ); - #else - errno = ENOSYS; - return -1; --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch b/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch deleted file mode 100644 index b908a1916..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch +++ /dev/null @@ -1,80 +0,0 @@ -From a2e3bc27382f9c0c4894c6e0ab121f075e82db3e Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Wed, 20 Aug 2014 11:26:48 -0600 -Subject: [PATCH] ntdll: Perform the Unix-style hidden file check within the - unified file info grabbing routine. - ---- - dlls/ntdll/unix/file.c | 23 +++++++++-------------- - 1 file changed, 9 insertions(+), 14 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 73d4cce90ae..b790cde3f90 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -1328,15 +1328,15 @@ static BOOLEAN get_dir_case_sensitivity( const char *dir ) - * - * Check if the specified file should be hidden based on its name and the show dot files option. - */ --static BOOL is_hidden_file( const UNICODE_STRING *name ) -+static BOOL is_hidden_file( const char *name ) - { -- WCHAR *p, *end; -+ const char *p, *end; - - if (show_dot_files) return FALSE; - -- end = p = name->Buffer + name->Length/sizeof(WCHAR); -- while (p > name->Buffer && p[-1] == '\\') p--; -- while (p > name->Buffer && p[-1] != '\\') p--; -+ end = p = name + strlen( name ); -+ while (p > name && p[-1] == '\\') p--; -+ while (p > name && p[-1] != '\\') p--; - return (p < end && *p == '.'); - } - -@@ -1679,6 +1679,10 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - free( parent_path ); - } - *attr |= get_file_attributes( st ); -+ /* convert Unix-style hidden files to a DOS hidden file attribute */ -+ if (is_hidden_file( path )) -+ *attr |= FILE_ATTRIBUTE_HIDDEN; -+ /* retrieve any stored DOS attributes */ - len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); - if (len == -1) return ret; - *attr |= get_file_xattr( hexattr, len ); -@@ -2186,11 +2190,6 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I - if (class != FileNamesInformation) - { - if (st.st_dev != dir_data->id.dev) st.st_ino = 0; /* ignore inode if on a different device */ -- -- if (!show_dot_files && names->long_name[0] == '.' && names->long_name[1] && -- (names->long_name[1] != '.' || names->long_name[2])) -- attributes |= FILE_ATTRIBUTE_HIDDEN; -- - fill_file_info( &st, attributes, info, class ); - } - -@@ -4106,7 +4105,6 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, - info->AllocationSize = std.AllocationSize; - info->EndOfFile = std.EndOfFile; - info->FileAttributes = basic.FileAttributes; -- if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; - } - free( unix_name ); - } -@@ -4133,10 +4131,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC - else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) - status = STATUS_INVALID_INFO_CLASS; - else -- { - status = fill_file_info( &st, attributes, info, FileBasicInformation ); -- if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; -- } - free( unix_name ); - } - else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch b/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch deleted file mode 100644 index f87c79e88..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch +++ /dev/null @@ -1,46 +0,0 @@ -From dd02380fff84cbef2a6df7b6f82b271e0e9d732f Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Thu, 14 Jan 2016 23:09:19 +0100 -Subject: [PATCH] ntdll: Always store SAMBA_XATTR_DOS_ATTRIB when path could be - interpreted as hidden. - ---- - dlls/ntdll/unix/file.c | 13 ++++++++----- - 1 file changed, 8 insertions(+), 5 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index c6b4928bd53..3bf82b1d45d 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -1567,12 +1567,15 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - free( parent_path ); - } - *attr |= get_file_attributes( st ); -- /* convert Unix-style hidden files to a DOS hidden file attribute */ -- if (is_hidden_file( path )) -- *attr |= FILE_ATTRIBUTE_HIDDEN; - /* retrieve any stored DOS attributes */ - len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); -- if (len == -1) return ret; -+ if (len == -1) -+ { -+ /* convert Unix-style hidden files to a DOS hidden file attribute */ -+ if (is_hidden_file( path )) -+ *attr |= FILE_ATTRIBUTE_HIDDEN; -+ return ret; -+ } - *attr |= get_file_xattr( hexattr, len ); - return ret; - } -@@ -3556,7 +3559,7 @@ NTSTATUS set_file_info( const char *path, ULONG attr ) - /* Note: unix mode already set when called this way */ - attr &= ~FILE_ATTRIBUTE_NORMAL; /* do not store everything, but keep everything Samba can use */ - len = sprintf( hexattr, "0x%x", attr ); -- if (attr != 0) -+ if (attr != 0 || is_hidden_file( path )) - xattr_set( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); - else - xattr_remove( path, SAMBA_XATTR_DOS_ATTRIB ); --- -2.27.0 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/definition b/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/definition deleted file mode 100644 index 48c34b307..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-DOS_Attributes/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [9158] Support for DOS hidden/system file attributes -Fixes: [15679] cygwin symlinks not working in wine diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/0003-ntdll-tests-Add-basic-tests-for-RtlQueryPackageIdent.patch b/patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/0003-ntdll-tests-Add-basic-tests-for-RtlQueryPackageIdent.patch deleted file mode 100644 index c83abb08e..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/0003-ntdll-tests-Add-basic-tests-for-RtlQueryPackageIdent.patch +++ /dev/null @@ -1,144 +0,0 @@ -From 62e3109b6bd1b3324827063531ae0826571c751b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Sun, 17 Jan 2016 00:50:50 +0100 -Subject: [PATCH] ntdll/tests: Add basic tests for RtlQueryPackageIdentity. - ---- - dlls/ntdll/tests/Makefile.in | 2 +- - dlls/ntdll/tests/rtl.c | 80 ++++++++++++++++++++++++++++++++++++ - 2 files changed, 81 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/tests/Makefile.in b/dlls/ntdll/tests/Makefile.in -index 7e0272498fa..a2c716d11d4 100644 ---- a/dlls/ntdll/tests/Makefile.in -+++ b/dlls/ntdll/tests/Makefile.in -@@ -1,6 +1,6 @@ - EXTRADEFS = -DWINE_NO_LONG_TYPES - TESTDLL = ntdll.dll --IMPORTS = user32 advapi32 -+IMPORTS = user32 ole32 advapi32 - - C_SRCS = \ - atom.c \ -diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c -index c0168884a0a..c25a9185fad 100644 ---- a/dlls/ntdll/tests/rtl.c -+++ b/dlls/ntdll/tests/rtl.c -@@ -27,6 +27,9 @@ - #include "in6addr.h" - #include "inaddr.h" - #include "ip2string.h" -+#include "initguid.h" -+#define COBJMACROS -+#include "shobjidl.h" - - #ifndef __WINE_WINTERNL_H - -@@ -80,6 +83,9 @@ static BOOL (WINAPI *pRtlIsCriticalSectionLocked)(CRITICAL_SECTION *); - static BOOL (WINAPI *pRtlIsCriticalSectionLockedByThread)(CRITICAL_SECTION *); - static NTSTATUS (WINAPI *pRtlInitializeCriticalSectionEx)(CRITICAL_SECTION *, ULONG, ULONG); - static NTSTATUS (WINAPI *pLdrEnumerateLoadedModules)(void *, void *, void *); -+static NTSTATUS (WINAPI *pRtlQueryPackageIdentity)(HANDLE, WCHAR*, SIZE_T*, WCHAR*, SIZE_T*, BOOLEAN*); -+static NTSTATUS (WINAPI *pRtlMakeSelfRelativeSD)(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,LPDWORD); -+static NTSTATUS (WINAPI *pRtlAbsoluteToSelfRelativeSD)(PSECURITY_DESCRIPTOR,PSECURITY_DESCRIPTOR,PULONG); - static NTSTATUS (WINAPI *pLdrRegisterDllNotification)(ULONG, PLDR_DLL_NOTIFICATION_FUNCTION, void *, void **); - static NTSTATUS (WINAPI *pLdrUnregisterDllNotification)(void *); - -@@ -120,6 +126,9 @@ static void InitFunctionPtrs(void) - pRtlIsCriticalSectionLockedByThread = (void *)GetProcAddress(hntdll, "RtlIsCriticalSectionLockedByThread"); - pRtlInitializeCriticalSectionEx = (void *)GetProcAddress(hntdll, "RtlInitializeCriticalSectionEx"); - pLdrEnumerateLoadedModules = (void *)GetProcAddress(hntdll, "LdrEnumerateLoadedModules"); -+ pRtlQueryPackageIdentity = (void *)GetProcAddress(hntdll, "RtlQueryPackageIdentity"); -+ pRtlMakeSelfRelativeSD = (void *)GetProcAddress(hntdll, "RtlMakeSelfRelativeSD"); -+ pRtlAbsoluteToSelfRelativeSD = (void *)GetProcAddress(hntdll, "RtlAbsoluteToSelfRelativeSD"); - pLdrRegisterDllNotification = (void *)GetProcAddress(hntdll, "LdrRegisterDllNotification"); - pLdrUnregisterDllNotification = (void *)GetProcAddress(hntdll, "LdrUnregisterDllNotification"); - } -@@ -3682,6 +3691,76 @@ static void test_RtlDestroyHeap(void) - RtlRemoveVectoredExceptionHandler( handler ); - } - -+static void test_RtlQueryPackageIdentity(void) -+{ -+ const WCHAR programW[] = {'M','i','c','r','o','s','o','f','t','.','W','i','n','d','o','w','s','.', -+ 'P','h','o','t','o','s','_','8','w','e','k','y','b','3','d','8','b','b','w','e','!','A','p','p',0}; -+ const WCHAR fullnameW[] = {'M','i','c','r','o','s','o','f','t','.','W','i','n','d','o','w','s','.', -+ 'P','h','o','t','o','s', 0}; -+ const WCHAR appidW[] = {'A','p','p',0}; -+ IApplicationActivationManager *manager; -+ WCHAR buf1[MAX_PATH], buf2[MAX_PATH]; -+ HANDLE process, token; -+ SIZE_T size1, size2; -+ NTSTATUS status; -+ DWORD processid; -+ HRESULT hr; -+ BOOL ret; -+ -+ if (!pRtlQueryPackageIdentity) -+ { -+ win_skip("RtlQueryPackageIdentity not available\n"); -+ return; -+ } -+ -+ size1 = size2 = MAX_PATH * sizeof(WCHAR); -+ status = pRtlQueryPackageIdentity((HANDLE)~(ULONG_PTR)3, buf1, &size1, buf2, &size2, NULL); -+ ok(status == STATUS_NOT_FOUND, "expected STATUS_NOT_FOUND, got %08x\n", status); -+ -+ CoInitializeEx(0, COINIT_APARTMENTTHREADED); -+ hr = CoCreateInstance(&CLSID_ApplicationActivationManager, NULL, CLSCTX_LOCAL_SERVER, -+ &IID_IApplicationActivationManager, (void **)&manager); -+ if (FAILED(hr)) -+ { -+ todo_wine win_skip("Failed to create ApplicationActivationManager (%x)\n", hr); -+ goto done; -+ } -+ -+ hr = IApplicationActivationManager_ActivateApplication(manager, programW, NULL, -+ AO_NOERRORUI, &processid); -+ if (FAILED(hr)) -+ { -+ todo_wine win_skip("Failed to start program (%x)\n", hr); -+ IApplicationActivationManager_Release(manager); -+ goto done; -+ } -+ -+ process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, FALSE, processid); -+ ok(process != NULL, "OpenProcess failed with %u\n", GetLastError()); -+ ret = OpenProcessToken(process, TOKEN_QUERY, &token); -+ ok(ret, "OpenProcessToken failed with error %u\n", GetLastError()); -+ -+ size1 = size2 = MAX_PATH * sizeof(WCHAR); -+ status = pRtlQueryPackageIdentity(token, buf1, &size1, buf2, &size2, NULL); -+ ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status); -+ -+ ok(!memcmp(buf1, fullnameW, sizeof(fullnameW) - sizeof(WCHAR)), -+ "Expected buf1 to begin with %s, got %s\n", wine_dbgstr_w(fullnameW), wine_dbgstr_w(buf1)); -+ ok(size1 >= sizeof(WCHAR) && !(size1 % sizeof(WCHAR)), "Unexpected size1 = %lu\n", size1); -+ ok(buf1[size1 / sizeof(WCHAR) - 1] == 0, "Expected buf1[%lu] == 0\n", size1 / sizeof(WCHAR) - 1); -+ -+ ok(!lstrcmpW(buf2, appidW), "Expected buf2 to be %s, got %s\n", wine_dbgstr_w(appidW), wine_dbgstr_w(buf2)); -+ ok(size2 >= sizeof(WCHAR) && !(size2 % sizeof(WCHAR)), "Unexpected size2 = %lu\n", size2); -+ ok(buf2[size2 / sizeof(WCHAR) - 1] == 0, "Expected buf2[%lu] == 0\n", size2 / sizeof(WCHAR) - 1); -+ -+ CloseHandle(token); -+ TerminateProcess(process, 0); -+ CloseHandle(process); -+ -+done: -+ CoUninitialize(); -+} -+ - START_TEST(rtl) - { - InitFunctionPtrs(); -@@ -3721,6 +3800,7 @@ START_TEST(rtl) - test_RtlInitializeCriticalSectionEx(); - test_RtlLeaveCriticalSection(); - test_LdrEnumerateLoadedModules(); -+ test_RtlQueryPackageIdentity(); - test_RtlMakeSelfRelativeSD(); - test_LdrRegisterDllNotification(); - test_DbgPrint(); --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/definition b/patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/definition deleted file mode 100644 index 6672b6650..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-RtlQueryPackageIdentity/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: Add stub for ntdll.RtlQueryPackageIdentity diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch b/patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch deleted file mode 100644 index efe7c070b..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 6684c0f0f73c1664c923ba150e1cb663704d8991 Mon Sep 17 00:00:00 2001 -From: Alex Henrie -Date: Tue, 29 Dec 2015 00:48:02 -0700 -Subject: [PATCH] mountmgr.sys: Do a device check before returning a default - serial port name. - -Fixes https://bugs.winehq.org/show_bug.cgi?id=39793 ---- - dlls/mountmgr.sys/device.c | 2 +- - dlls/mountmgr.sys/unixlib.c | 22 ++++++++++++++++++++++ - dlls/mountmgr.sys/unixlib.h | 1 + - 3 files changed, 24 insertions(+), 1 deletion(-) - -diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c -index 8c2808bb643..57ae874b247 100644 ---- a/dlls/mountmgr.sys/device.c -+++ b/dlls/mountmgr.sys/device.c -@@ -1868,7 +1868,7 @@ static BOOL create_port_device( DRIVER_OBJECT *driver, int n, const char *unix_p - UNICODE_STRING nt_name, symlink_name, default_name; - DEVICE_OBJECT *dev_obj; - NTSTATUS status; -- struct set_dosdev_symlink_params params = { dosdevices_path, unix_path }; -+ struct set_dosdev_symlink_params params = { dosdevices_path, unix_path, driver == serial_driver }; - - /* create DOS device */ - if (MOUNTMGR_CALL( set_dosdev_symlink, ¶ms )) return FALSE; -diff --git a/dlls/mountmgr.sys/unixlib.c b/dlls/mountmgr.sys/unixlib.c -index 73735c22d13..f83f7104d82 100644 ---- a/dlls/mountmgr.sys/unixlib.c -+++ b/dlls/mountmgr.sys/unixlib.c -@@ -30,6 +30,7 @@ - #include - #include - #include -+#include - #include - - #include "unixlib.h" - -@@ -268,6 +269,27 @@ static NTSTATUS set_dosdev_symlink( void *args ) - char *path; - NTSTATUS status = STATUS_SUCCESS; - -+#ifdef linux -+ /* Serial port device files almost always exist on Linux even if the corresponding serial -+ * ports don't exist. Do a basic functionality check before advertising a serial port. */ -+ if (params->serial) -+ { -+ struct termios tios; -+ int fd; -+ -+ if ((fd = open( params->dest, O_RDONLY )) == -1) -+ return FALSE; -+ -+ if (tcgetattr( fd, &tios ) == -1) -+ { -+ close( fd ); -+ return FALSE; -+ } -+ -+ close( fd ); -+ } -+#endif -+ - if (!(path = get_dosdevices_path( params->dev ))) return STATUS_NO_MEMORY; - - if (params->dest && params->dest[0]) -diff --git a/dlls/mountmgr.sys/unixlib.h b/dlls/mountmgr.sys/unixlib.h -index 188cf93b091..31f5e8a807e 100644 ---- a/dlls/mountmgr.sys/unixlib.h -+++ b/dlls/mountmgr.sys/unixlib.h -@@ -75,6 +75,7 @@ struct set_dosdev_symlink_params - { - const char *dev; - const char *dest; -+ BOOL serial; - }; - - struct get_volume_dos_devices_params --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/definition b/patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/definition deleted file mode 100644 index 95fe42a7b..000000000 --- a/patches/wine-hotfixes/staging-7.0/ntdll-Serial_Port_Detection/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [39793] Do a device check before returning a default serial port name diff --git a/patches/wine-hotfixes/staging-7.0/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch b/patches/wine-hotfixes/staging-7.0/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch deleted file mode 100644 index 2e77c5647..000000000 --- a/patches/wine-hotfixes/staging-7.0/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch +++ /dev/null @@ -1,29 +0,0 @@ -From c70b2b402ac1ca3a923822ddd2128a09ce5de81a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Sveinar=20S=C3=B8pler?= -Date: Mon, 24 Jan 2022 16:02:35 +0100 -Subject: [PATCH] nvcuda: Make nvcuda attempt to load libcuda.so.1 - -libcuda.so is not available when running under steam runtime -container. Adding this will make nvcuda attempt to load -libcuda.so.1 which will be available inside the steam runtime. ---- - dlls/nvcuda/nvcuda.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/nvcuda/nvcuda.c b/dlls/nvcuda/nvcuda.c -index 2cb3a0e2ecf..84da77941c6 100644 ---- a/dlls/nvcuda/nvcuda.c -+++ b/dlls/nvcuda/nvcuda.c -@@ -424,7 +424,8 @@ static BOOL load_functions(void) - "/usr/local/cuda/lib/libcuda.dylib", - "/usr/local/cuda/lib/libcuda.6.0.dylib", - #else -- "libcuda.so" -+ "libcuda.so", -+ "libcuda.so.1" - #endif - }; - int i; --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/packager-DllMain/0001-packager-Prefer-native-version.patch b/patches/wine-hotfixes/staging-7.0/packager-DllMain/0001-packager-Prefer-native-version.patch deleted file mode 100644 index 6ba9b0658..000000000 --- a/patches/wine-hotfixes/staging-7.0/packager-DllMain/0001-packager-Prefer-native-version.patch +++ /dev/null @@ -1,25 +0,0 @@ -From cea29373b287ae84e28adca9834ffdbb97844ffe Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sun, 6 Aug 2017 02:50:23 +0200 -Subject: [PATCH] packager: Prefer native version. - ---- - dlls/packager/Makefile.in | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/packager/Makefile.in b/dlls/packager/Makefile.in -index f539cb6f095..faef8deb263 100644 ---- a/dlls/packager/Makefile.in -+++ b/dlls/packager/Makefile.in -@@ -2,6 +2,8 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES - MODULE = packager.dll - IMPORTS = uuid shell32 shlwapi user32 - -+EXTRADLLFLAGS = -Wb,--prefer-native -+ - C_SRCS = \ - packager_main.c - --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/packager-DllMain/definition b/patches/wine-hotfixes/staging-7.0/packager-DllMain/definition deleted file mode 100644 index 83e85b8bb..000000000 --- a/patches/wine-hotfixes/staging-7.0/packager-DllMain/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [43472] Prefer native version of packager.dll diff --git a/patches/wine-hotfixes/staging-7.0/proton-staging-syscall-emu.patch b/patches/wine-hotfixes/staging-7.0/proton-staging-syscall-emu.patch deleted file mode 100644 index af4d9100d..000000000 --- a/patches/wine-hotfixes/staging-7.0/proton-staging-syscall-emu.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 76e0c24f410417973d784705c9729041af435929 Mon Sep 17 00:00:00 2001 -From: Tk-Glitch -Date: Fri, 2 Apr 2021 06:03:28 +0200 -Subject: protonify staging syscall emu - - -diff --git a/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch b/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch -index 014d6a46..46f04635 100644 ---- a/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch -+++ b/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch -@@ -5,12 +5,13 @@ Subject: [PATCH] ntdll: Support x86_64 syscall emulation. - - --- - configure.ac | 1 + -- dlls/ntdll/unix/signal_x86_64.c | 123 ++++++++++++++++++++++++++++++++ -+ dlls/ntdll/unix/signal_x86_64.c | 118 ++++++++++++++++++++++++++++++++ -+ include/config.h.in | 3 + - tools/winebuild/import.c | 3 +- -- 3 files changed, 125 insertions(+), 2 deletions(-) -+ 5 files changed, 125 insertions(+), 1 deletion(-) - - diff --git a/configure.ac b/configure.ac --index 5a5d88f10b0..7ae43b0c593 100644 -+index 6202d68ee45..bcc37745576 100644 - --- a/configure.ac - +++ b/configure.ac - @@ -448,6 +448,7 @@ AC_CHECK_HEADERS(\ -@@ -53,13 +54,14 @@ index 06d99545913..9a46b4a50b0 100644 - #define NONAMELESSUNION - #define NONAMELESSSTRUCT - #include "ntstatus.h" --@@ -2432,6 +2441,118 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) -+@@ -2344,6 +2352,119 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) - return 0; - } - - +#ifdef HAVE_SECCOMP - +static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) - +{ -++ ULONG64 *dispatcher_address = (ULONG64 *)((char *)user_shared_data + page_size); - + ucontext_t *ctx = sigcontext; - + void ***rsp; - + -@@ -70,7 +72,7 @@ index 06d99545913..9a46b4a50b0 100644 - + *rsp -= 1; - + **rsp = (void *)(ctx->uc_mcontext.gregs[REG_RIP] + 0xb); - + --+ ctx->uc_mcontext.gregs[REG_RIP] = (ULONG64)__wine_syscall_dispatcher; -++ ctx->uc_mcontext.gregs[REG_RIP] = *dispatcher_address; - +} - +#endif - + -@@ -172,7 +174,7 @@ index 06d99545913..9a46b4a50b0 100644 - - /*********************************************************************** - * handle_interrupt --@@ -3010,6 +3131,7 @@ void signal_init_process(void) -+@@ -2816,6 +2937,7 @@ void signal_init_process(void) - if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -@@ -188,8 +190,22 @@ index 06d99545913..9a46b4a50b0 100644 - "movq 0x18(%rcx),%rdx\n\t" - "movl %eax,%ebx\n\t" - "shrl $8,%ebx\n\t" -+diff --git a/include/config.h.in b/include/config.h.in -+index cf3aaa17a5d..b602a292eea 100644 -+--- a/include/config.h.in -++++ b/include/config.h.in -+@@ -450,6 +450,9 @@ -+ /* Define to 1 if you have the header file. */ -+ #undef HAVE_LINUX_RTNETLINK_H -+ -++/* Define to 1 if you have the header file. */ -++#undef HAVE_LINUX_SECCOMP_H -++ -+ /* Define to 1 if you have the header file. */ -+ #undef HAVE_LINUX_SERIAL_H -+ - diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c --index c876d51f8e6..37f1465a139 100644 -+index 720cf0589fd..9a7537451ae 100644 - --- a/tools/winebuild/import.c - +++ b/tools/winebuild/import.c - @@ -1366,7 +1366,6 @@ static int cmp_link_name( const void *e1, const void *e2 ) diff --git a/patches/wine-hotfixes/staging-7.0/rawinput/0006-winex11.drv-Send-relative-RawMotion-events-unprocess.patch b/patches/wine-hotfixes/staging-7.0/rawinput/0006-winex11.drv-Send-relative-RawMotion-events-unprocess.patch deleted file mode 100644 index f4ad7197a..000000000 --- a/patches/wine-hotfixes/staging-7.0/rawinput/0006-winex11.drv-Send-relative-RawMotion-events-unprocess.patch +++ /dev/null @@ -1,106 +0,0 @@ -From cc3472938f76b5db50ea86f854e153fd71795b6e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Mon, 25 Oct 2021 11:48:00 +0200 -Subject: [PATCH] winex11.drv: Send relative RawMotion events unprocessed. - -This makes relative raw input independent from cursor speed, as it is -the case on Windows. Absolute raw input is already translated to -virtual desktop space, and cursor speed is meaningless in this case. - -This does not support mixed relative/absolute X/Y axis. ---- - dlls/winex11.drv/mouse.c | 24 ++++++++++++------------ - 1 file changed, 12 insertions(+), 12 deletions(-) - -diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c -index 727ba13bc31..fdf8eca93dd 100644 ---- a/dlls/winex11.drv/mouse.c -+++ b/dlls/winex11.drv/mouse.c -@@ -1872,12 +1872,12 @@ static BOOL X11DRV_XIDeviceChangedEvent( XIDeviceChangedEvent *event ) - return TRUE; - } - --static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) -+static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input, RAWINPUT *rawinput ) - { - struct x11drv_thread_data *thread_data = x11drv_thread_data(); - XIValuatorClassInfo *x = &thread_data->x_valuator, *y = &thread_data->y_valuator; -- double x_value = 0, y_value = 0, x_scale, y_scale, user_to_real_scale; -- const double *values = event->valuators.values; -+ double x_raw = 0, y_raw = 0, x_value = 0, y_value = 0, x_scale, y_scale, user_to_real_scale; -+ const double *values = event->valuators.values, *raw_values = event->raw_values; - RECT virtual_rect; - HMONITOR monitor; - POINT pt; -@@ -1908,33 +1908,35 @@ static BOOL map_raw_event_coords( XIRawEvent *event, INPUT *input ) - if (!XIMaskIsSet( event->valuators.mask, i )) continue; - if (i == x->number) - { -+ x_raw = *raw_values; - x_value = *values; - if (x->mode == XIModeRelative) x->value += x_value * x_scale; - else x->value = (x_value - x->min) * x_scale; - } - if (i == y->number) - { -+ y_raw = *raw_values; - y_value = *values; - if (y->mode == XIModeRelative) y->value += y_value * y_scale; - else y->value = (y_value - y->min) * y_scale; - } -+ raw_values++; - values++; - } - - input->u.mi.dx = round( x->value ); - input->u.mi.dy = round( y->value ); - -+ if (x->mode != XIModeAbsolute) rawinput->data.mouse.lLastX = x_raw; -+ else rawinput->data.mouse.lLastX = input->u.mi.dx; -+ if (y->mode != XIModeAbsolute) rawinput->data.mouse.lLastY = y_raw; -+ else rawinput->data.mouse.lLastY = input->u.mi.dy; -+ - TRACE( "event %f,%f value %f,%f input %d,%d\n", x_value, y_value, x->value, y->value, input->u.mi.dx, input->u.mi.dy ); - - x->value -= input->u.mi.dx; - y->value -= input->u.mi.dy; - -- if (!(input->u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE) && !input->u.mi.dx && !input->u.mi.dy) -- { -- TRACE( "accumulating motion\n" ); -- return FALSE; -- } -- - if (input->u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE) - fs_hack_point_real_to_user((POINT *)&input->u.mi.dx); - else -@@ -2027,7 +2029,7 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - input.u.mi.dwExtraInfo = 0; - input.u.mi.dx = 0; - input.u.mi.dy = 0; -- if (!map_raw_event_coords( event, &input )) return FALSE; -+ if (!map_raw_event_coords( event, &input, &rawinput )) return FALSE; - - if (!thread_data->xi2_rawinput_only) - __wine_send_input( 0, &input, NULL ); -@@ -2041,8 +2043,6 @@ static BOOL X11DRV_RawMotion( XGenericEventCookie *xev ) - rawinput.data.mouse.ulRawButtons = 0; - rawinput.data.mouse.u.usButtonData = 0; - rawinput.data.mouse.u.usButtonFlags = 0; -- rawinput.data.mouse.lLastX = input.u.mi.dx; -- rawinput.data.mouse.lLastY = input.u.mi.dy; - rawinput.data.mouse.ulExtraInformation = 0; - - input.type = INPUT_HARDWARE; -@@ -2174,7 +2174,7 @@ static BOOL X11DRV_RawTouchEvent( XGenericEventCookie *xev ) - POINT pos; - - if (!thread_data->xi2_rawinput_only) return FALSE; -- if (!map_raw_event_coords( event, &input )) return FALSE; -+ if (!map_raw_event_coords( event, &input, &rawinput )) return FALSE; - if (!(input.u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE)) return FALSE; - pos.x = input.u.mi.dx; - pos.y = input.u.mi.dy; --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/server-Signal_Thread/0001-server-Do-not-signal-thread-until-it-is-really-gone.patch b/patches/wine-hotfixes/staging-7.0/server-Signal_Thread/0001-server-Do-not-signal-thread-until-it-is-really-gone.patch deleted file mode 100644 index 26cc29b70..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-Signal_Thread/0001-server-Do-not-signal-thread-until-it-is-really-gone.patch +++ /dev/null @@ -1,114 +0,0 @@ -From f649ffcd8f68f82be173367b66f3c505ff75bcc3 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Mon, 12 Nov 2018 18:10:32 +0200 -Subject: [PATCH] server: Do not signal violently terminated threads until they - are really gone -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When a thread is terminated violently (such as by using TerminateThread) -that is not the current thread, the server sends a signal to the thread to -terminate it, but it immediately wakes up anything waiting on it. The caller -can expect WaitForSingleObject (or similar) to return when the thread is -really gone and doesn't execute anything anymore, and this is exactly what -happens on Windows. - -If that thread was altering global state, and the thread that was waiting -on it will read (or alter) the global state *after* waiting for it and -expecting it to not change (because it assumes the thread is terminated by -that point, as on Windows), the result will be a race condition, since there's -no guarantee currently that the terminated thread really stopped executing. - -Signed-off-by: Gabriel Ivăncescu ---- - server/thread.c | 32 +++++++++++++++++++++++++++++--- - server/thread.h | 1 + - 2 files changed, 30 insertions(+), 3 deletions(-) - -diff --git a/server/thread.c b/server/thread.c -index 55386192fe6..60cd4ee16a8 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -241,6 +241,7 @@ static inline void init_thread_structure( struct thread *thread ) - thread->queue_shared = NULL; - thread->input_shared_mapping = NULL; - thread->input_shared = NULL; -+ thread->exit_poll = NULL; - - thread->creation_time = current_time; - thread->exit_time = 0; -@@ -431,6 +432,7 @@ static void destroy_thread( struct object *obj ) - list_remove( &thread->entry ); - cleanup_thread( thread ); - release_object( thread->process ); -+ if (thread->exit_poll) remove_timeout_user( thread->exit_poll ); - if (thread->id) free_ptid( thread->id ); - if (thread->token) release_object( thread->token ); - } -@@ -455,7 +457,7 @@ static struct object_type *thread_get_type( struct object *obj ) - static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ) - { - struct thread *mythread = (struct thread *)obj; -- return (mythread->state == TERMINATED); -+ return mythread->state == TERMINATED && !mythread->exit_poll; - } - - static unsigned int thread_map_access( struct object *obj, unsigned int access ) -@@ -1249,6 +1251,26 @@ int thread_get_inflight_fd( struct thread *thread, int client ) - return -1; - } - -+static void check_terminated( void *arg ) -+{ -+ struct thread *thread = arg; -+ assert( thread->obj.ops == &thread_ops ); -+ assert( thread->state == TERMINATED ); -+ -+ /* don't wake up until the thread is really dead, to avoid race conditions */ -+ if (thread->unix_tid != -1 && !kill( thread->unix_tid, 0 )) -+ { -+ thread->exit_poll = add_timeout_user( -TICKS_PER_SEC / 1000, check_terminated, thread ); -+ return; -+ } -+ -+ /* grab reference since object can be destroyed while trying to wake up */ -+ grab_object( &thread->obj ); -+ thread->exit_poll = NULL; -+ wake_up( &thread->obj, 0 ); -+ release_object( &thread->obj ); -+} -+ - /* kill a thread on the spot */ - void kill_thread( struct thread *thread, int violent_death ) - { -@@ -1268,8 +1290,12 @@ void kill_thread( struct thread *thread, int violent_death ) - fsync_abandon_mutexes( thread ); - if (do_esync()) - esync_abandon_mutexes( thread ); -- wake_up( &thread->obj, 0 ); -- if (violent_death) send_thread_signal( thread, SIGQUIT ); -+ if (violent_death) -+ { -+ send_thread_signal( thread, SIGQUIT ); -+ check_terminated( thread ); -+ } -+ else wake_up( &thread->obj, 0 ); - cleanup_thread( thread ); - remove_process_thread( thread->process, thread ); - release_object( thread ); -diff --git a/server/thread.h b/server/thread.h -index 184fa92d250..077ab0929ba 100644 ---- a/server/thread.h -+++ b/server/thread.h -@@ -90,6 +90,7 @@ struct thread - struct list kernel_object; /* list of kernel object pointers */ - data_size_t desc_len; /* thread description length in bytes */ - WCHAR *desc; /* thread description string */ -+ struct timeout_user *exit_poll; /* poll if the thread/process has exited already */ - struct object *locked_completion; /* completion port wait object successfully waited by the thread */ - struct object *queue_shared_mapping; /* thread queue shared memory mapping */ - volatile struct queue_shared_memory *queue_shared; /* thread queue shared memory ptr */ --- -2.29.2 - diff --git a/patches/wine-hotfixes/staging-7.0/server-Signal_Thread/definition b/patches/wine-hotfixes/staging-7.0/server-Signal_Thread/definition deleted file mode 100644 index ef65e975d..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-Signal_Thread/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: Do not signal threads until they are really gone diff --git a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch b/patches/wine-hotfixes/staging-7.0/server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch deleted file mode 100644 index f92eeac74..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 9804dd77fd8c0ec56963306f409fea6b910bb48d Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Sun, 7 Feb 2021 22:54:19 -0600 -Subject: [PATCH] server: Create processes using a limited administrator token - by default. - -Signed-off-by: Zebediah Figura ---- - server/process.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/server/process.c b/server/process.c -index 15387a2affa..3a8bbdbfb2e 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -664,7 +664,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla - if (!parent) - { - process->handles = alloc_handle_table( process, 0 ); -- process->token = token_create_admin( TRUE, -1, TokenElevationTypeFull, default_session_id ); -+ process->token = token_create_admin( TRUE, -1, TokenElevationTypeLimited, default_session_id ); - process->affinity = ~0; - } - else --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0002-shell32-Implement-the-runas-verb.patch b/patches/wine-hotfixes/staging-7.0/server-default_integrity/0002-shell32-Implement-the-runas-verb.patch deleted file mode 100644 index 0f53ba56f..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0002-shell32-Implement-the-runas-verb.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 5b1f4126d7eed65f68fb46bec05b226d75ce63e5 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Fri, 26 Feb 2021 22:31:19 -0600 -Subject: [PATCH] shell32: Implement the "runas" verb. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Based on a patch by Michael Müller. - -Signed-off-by: Zebediah Figura ---- - dlls/shell32/shlexec.c | 26 ++++++++++++++++++++++++-- - 1 file changed, 24 insertions(+), 2 deletions(-) - -diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c -index ba393ad7794..f6e108fd6bf 100644 ---- a/dlls/shell32/shlexec.c -+++ b/dlls/shell32/shlexec.c -@@ -299,6 +299,21 @@ static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR psz - return hr; - } - -+static HANDLE get_admin_token(void) -+{ -+ TOKEN_ELEVATION_TYPE type; -+ TOKEN_LINKED_TOKEN linked; -+ DWORD size; -+ -+ if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenElevationType, &type, sizeof(type), &size) -+ || type == TokenElevationTypeFull) -+ return NULL; -+ -+ if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenLinkedToken, &linked, sizeof(linked), &size)) -+ return NULL; -+ return linked.LinkedToken; -+} -+ - /************************************************************************* - * SHELL_ExecuteW [Internal] - * -@@ -312,6 +327,7 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, - UINT gcdret = 0; - WCHAR curdir[MAX_PATH]; - DWORD dwCreationFlags; -+ HANDLE token = NULL; - - TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory)); - -@@ -333,8 +349,12 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, - dwCreationFlags = CREATE_UNICODE_ENVIRONMENT; - if (!(psei->fMask & SEE_MASK_NO_CONSOLE)) - dwCreationFlags |= CREATE_NEW_CONSOLE; -- if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env, -- NULL, &startup, &info)) -+ -+ if (psei->lpVerb && !wcsicmp(psei->lpVerb, L"runas")) -+ token = get_admin_token(); -+ -+ if (CreateProcessAsUserW(token, NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, -+ dwCreationFlags, env, NULL, &startup, &info)) - { - /* Give 30 seconds to the app to come up, if desired. Probably only needed - when starting app immediately before making a DDE connection. */ -@@ -354,6 +374,8 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, - retval = ERROR_BAD_FORMAT; - } - -+ CloseHandle(token); -+ - TRACE("returning %lu\n", retval); - - psei_out->hInstApp = (HINSTANCE)retval; --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch b/patches/wine-hotfixes/staging-7.0/server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch deleted file mode 100644 index 8b0ccf789..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch +++ /dev/null @@ -1,29 +0,0 @@ -From dc1f602da6ed3a574697fe8b5bc4590d74e344f5 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Fri, 26 Feb 2021 22:41:35 -0600 -Subject: [PATCH] wine.inf: Set the EnableLUA value to 1. - -This signifies that UAC is active. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50727 -Signed-off-by: Zebediah Figura ---- - loader/wine.inf.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 24da6f3af6b..a72279e9881 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -526,7 +526,7 @@ HKLM,%CurrentVersion%\Explorer\DriveIcons,,16 - HKLM,%CurrentVersion%\Explorer\KindMap,,16 - HKLM,%CurrentVersion%\Group Policy,,16 - HKLM,%CurrentVersion%\Installer,"InstallerLocation",,"%11%" --HKLM,%CurrentVersion%\Policies\System,"EnableLUA",0x10003,0 -+HKLM,%CurrentVersion%\Policies\System,"EnableLUA",0x10001,1 - HKLM,%CurrentVersion%\PreviewHandlers,,16 - HKLM,%CurrentVersion%\Run,,16 - HKLM,%CurrentVersion%\Setup,"BootDir",,"%30%" --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch b/patches/wine-hotfixes/staging-7.0/server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch deleted file mode 100644 index 476725ba4..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch +++ /dev/null @@ -1,68 +0,0 @@ -From f2de1c5d2fcda876276e077b61f9fba5ff3f7f12 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Sun, 16 May 2021 20:49:05 -0500 -Subject: [PATCH] msi: Create the custom action server as an elevated process. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51143 -Signed-off-by: Zebediah Figura ---- - dlls/msi/custom.c | 24 ++++++++++++++++++++++-- - 1 file changed, 22 insertions(+), 2 deletions(-) - -diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c -index fb03958eb11..874b9b92118 100644 ---- a/dlls/msi/custom.c -+++ b/dlls/msi/custom.c -@@ -574,12 +574,28 @@ UINT CDECL __wine_msi_call_dll_function(DWORD client_pid, const GUID *guid) - return r; - } - -+static HANDLE get_admin_token(void) -+{ -+ TOKEN_ELEVATION_TYPE type; -+ TOKEN_LINKED_TOKEN linked; -+ DWORD size; -+ -+ if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenElevationType, &type, sizeof(type), &size) -+ || type == TokenElevationTypeFull) -+ return NULL; -+ -+ if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenLinkedToken, &linked, sizeof(linked), &size)) -+ return NULL; -+ return linked.LinkedToken; -+} -+ - static DWORD custom_start_server(MSIPACKAGE *package, DWORD arch) - { - WCHAR path[MAX_PATH], cmdline[MAX_PATH + 23]; - PROCESS_INFORMATION pi = {0}; - STARTUPINFOW si = {0}; - WCHAR buffer[24]; -+ HANDLE token; - void *cookie; - HANDLE pipe; - -@@ -601,14 +617,18 @@ static DWORD custom_start_server(MSIPACKAGE *package, DWORD arch) - lstrcatW(path, L"\\msiexec.exe"); - swprintf(cmdline, ARRAY_SIZE(cmdline), L"%s -Embedding %d", path, GetCurrentProcessId()); - -+ token = get_admin_token(); -+ - if (is_wow64 && arch == SCS_64BIT_BINARY) - { - Wow64DisableWow64FsRedirection(&cookie); -- CreateProcessW(path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); -+ CreateProcessAsUserW(token, path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - Wow64RevertWow64FsRedirection(cookie); - } - else -- CreateProcessW(path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); -+ CreateProcessAsUserW(token, path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); -+ -+ if (token) CloseHandle(token); - - CloseHandle(pi.hThread); - --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch b/patches/wine-hotfixes/staging-7.0/server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch deleted file mode 100644 index e6ad033a9..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch +++ /dev/null @@ -1,50 +0,0 @@ -From b08427ea0575faf213100269bf5bc931ec05930b Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Fri, 21 May 2021 21:52:06 -0500 -Subject: [PATCH] ntdll: Always start the initial process through start.exe. - -Signed-off-by: Zebediah Figura ---- - dlls/ntdll/unix/env.c | 19 +++---------------- - 1 file changed, 3 insertions(+), 16 deletions(-) - -diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c -index ae1afb2797b..02af2c5ca5a 100644 ---- a/dlls/ntdll/unix/env.c -+++ b/dlls/ntdll/unix/env.c -@@ -2116,6 +2116,7 @@ static void init_peb( RTL_USER_PROCESS_PARAMETERS *params, void *module ) - */ - static RTL_USER_PROCESS_PARAMETERS *build_initial_params( void **module ) - { -+ static const char *args[] = { "start.exe", "/exec" }; - static const WCHAR valueW[] = {'1',0}; - static const WCHAR pathW[] = {'P','A','T','H'}; - RTL_USER_PROCESS_PARAMETERS *params = NULL; -@@ -2144,22 +2145,8 @@ static RTL_USER_PROCESS_PARAMETERS *build_initial_params( void **module ) - add_registry_environment( &env, &env_pos, &env_size ); - env[env_pos++] = 0; - -- status = load_main_exe( NULL, main_argv[1], curdir, &image, module ); -- if (!status) -- { -- if (main_image_info.ImageCharacteristics & IMAGE_FILE_DLL) status = STATUS_INVALID_IMAGE_FORMAT; -- if (main_image_info.Machine != current_machine) status = STATUS_INVALID_IMAGE_FORMAT; -- } -- -- if (status) /* try launching it through start.exe */ -- { -- static const char *args[] = { "start.exe", "/exec" }; -- free( image ); -- if (*module) NtUnmapViewOfSection( GetCurrentProcess(), *module ); -- load_start_exe( &image, module ); -- prepend_argv( args, 2 ); -- } -- else rebuild_argv(); -+ load_start_exe( &image, module ); -+ prepend_argv( args, 2 ); - - main_wargv = build_wargv( get_dos_path( image )); - cmdline = build_command_line( main_wargv ); --- -2.32.0 - diff --git a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch b/patches/wine-hotfixes/staging-7.0/server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch deleted file mode 100644 index 31afa206d..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch +++ /dev/null @@ -1,110 +0,0 @@ -From e695c71722c3ecf8b2666da109dfe172e50f75da Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Sun, 18 Apr 2021 17:46:35 -0500 -Subject: [PATCH] kernelbase: Elevate processes if requested in - CreateProcessInternal(). - -Signed-off-by: Zebediah Figura ---- - dlls/kernelbase/process.c | 57 +++++++++++++++++++++++++++++++++++++-- - 1 file changed, 55 insertions(+), 2 deletions(-) - -diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c -index ab89d3bcf31..270951a795e 100644 ---- a/dlls/kernelbase/process.c -+++ b/dlls/kernelbase/process.c -@@ -30,6 +30,7 @@ - #include "winnls.h" - #include "wincontypes.h" - #include "winternl.h" -+#include "winuser.h" - - #include "kernelbase.h" - #include "wine/debug.h" -@@ -413,6 +414,54 @@ BOOL WINAPI DECLSPEC_HOTPATCH CloseHandle( HANDLE handle ) - } - - -+static BOOL image_needs_elevation( const WCHAR *path ) -+{ -+ ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION run_level; -+ BOOL ret = FALSE; -+ HANDLE handle; -+ ACTCTXW ctx; -+ -+ ctx.cbSize = sizeof(ctx); -+ ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; -+ ctx.lpSource = path; -+ ctx.lpResourceName = (const WCHAR *)CREATEPROCESS_MANIFEST_RESOURCE_ID; -+ -+ if (RtlCreateActivationContext( &handle, &ctx )) return FALSE; -+ -+ if (!RtlQueryInformationActivationContext( 0, handle, NULL, RunlevelInformationInActivationContext, -+ &run_level, sizeof(run_level), NULL )) -+ { -+ TRACE( "image requested run level %#x\n", run_level.RunLevel ); -+ if (run_level.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE -+ || run_level.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN) -+ ret = TRUE; -+ } -+ RtlReleaseActivationContext( handle ); -+ -+ return ret; -+} -+ -+ -+static HANDLE get_elevated_token(void) -+{ -+ TOKEN_ELEVATION_TYPE type; -+ TOKEN_LINKED_TOKEN linked; -+ NTSTATUS status; -+ -+ if ((status = NtQueryInformationToken( GetCurrentThreadEffectiveToken(), -+ TokenElevationType, &type, sizeof(type), NULL ))) -+ return NULL; -+ -+ if (type == TokenElevationTypeFull) return NULL; -+ -+ if ((status = NtQueryInformationToken( GetCurrentThreadEffectiveToken(), -+ TokenLinkedToken, &linked, sizeof(linked), NULL ))) -+ return NULL; -+ -+ return linked.LinkedToken; -+} -+ -+ - /********************************************************************** - * CreateProcessAsUserA (kernelbase.@) - */ -@@ -548,7 +597,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - WCHAR *p, *tidy_cmdline = cmd_line; - RTL_USER_PROCESS_PARAMETERS *params = NULL; - RTL_USER_PROCESS_INFORMATION rtl_info; -- HANDLE parent = 0, debug = 0; -+ HANDLE parent = 0, debug = 0, elevated_token = NULL; - const WCHAR *append; - ULONG nt_flags = 0; - NTSTATUS status; -@@ -607,6 +656,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - if (flags & CREATE_BREAKAWAY_FROM_JOB) nt_flags |= PROCESS_CREATE_FLAGS_BREAKAWAY; - if (flags & CREATE_SUSPENDED) nt_flags |= PROCESS_CREATE_FLAGS_SUSPENDED; - -+ if (!token && image_needs_elevation( params->ImagePathName.Buffer )) -+ token = elevated_token = get_elevated_token(); -+ - status = create_nt_process( token, debug, process_attr, thread_attr, - nt_flags, params, &rtl_info, parent, handle_list, job_list ); - switch (status) -@@ -648,7 +700,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - TRACE( "started process pid %04x tid %04x\n", info->dwProcessId, info->dwThreadId ); - } - -- done: -+done: -+ if (elevated_token) NtClose( elevated_token ); - RtlDestroyProcessParameters( params ); - if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline ); - return set_ntstatus( status ); --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch b/patches/wine-hotfixes/staging-7.0/server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch deleted file mode 100644 index a0b944389..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 20e95575948faec1eca2e88967e985539a512cd5 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Sun, 18 Apr 2021 17:46:44 -0500 -Subject: [PATCH] ntdll: Elevate processes if requested in - RtlCreateUserProcess(). - -Signed-off-by: Zebediah Figura ---- - dlls/ntdll/process.c | 79 +++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 74 insertions(+), 5 deletions(-) - -diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c -index 160b1f549c9..fd437ea07d4 100644 ---- a/dlls/ntdll/process.c -+++ b/dlls/ntdll/process.c -@@ -39,6 +39,9 @@ - WINE_DEFAULT_DEBUG_CHANNEL(process); - - -+/* we don't want to include winuser.h */ -+#define CREATEPROCESS_MANIFEST_RESOURCE_ID ((ULONG_PTR)1) -+ - /****************************************************************************** - * RtlGetCurrentPeb [NTDLL.@] - * -@@ -82,6 +85,63 @@ NTSTATUS WINAPI RtlWow64EnableFsRedirectionEx( ULONG disable, ULONG *old_value ) - } - - -+static BOOL image_needs_elevation( const UNICODE_STRING *path ) -+{ -+ ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION run_level; -+ UNICODE_STRING path0; -+ BOOL ret = FALSE; -+ HANDLE handle; -+ ACTCTXW ctx; -+ -+ if (RtlDuplicateUnicodeString( 1, path, &path0 )) -+ return FALSE; -+ -+ ctx.cbSize = sizeof(ctx); -+ ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; -+ ctx.lpSource = path0.Buffer; -+ ctx.lpResourceName = (const WCHAR *)CREATEPROCESS_MANIFEST_RESOURCE_ID; -+ -+ if (RtlCreateActivationContext( &handle, &ctx )) -+ { -+ RtlFreeUnicodeString( &path0 ); -+ return FALSE; -+ } -+ -+ if (!RtlQueryInformationActivationContext( 0, handle, NULL, RunlevelInformationInActivationContext, -+ &run_level, sizeof(run_level), NULL )) -+ { -+ TRACE( "image requested run level %#x\n", run_level.RunLevel ); -+ if (run_level.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE -+ || run_level.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN) -+ ret = TRUE; -+ } -+ RtlReleaseActivationContext( handle ); -+ RtlFreeUnicodeString( &path0 ); -+ return ret; -+} -+ -+ -+static HANDLE get_elevated_token(void) -+{ -+ TOKEN_ELEVATION_TYPE type; -+ TOKEN_LINKED_TOKEN linked; -+ NTSTATUS status; -+ -+ if ((status = NtQueryInformationToken( GetCurrentThreadEffectiveToken(), -+ TokenElevationType, &type, sizeof(type), NULL ))) -+ return NULL; -+ -+ if (type == TokenElevationTypeFull) return NULL; -+ -+ -+ if ((status = NtQueryInformationToken( GetCurrentThreadEffectiveToken(), -+ TokenLinkedToken, &linked, sizeof(linked), NULL ))) -+ return NULL; -+ -+ return linked.LinkedToken; -+} -+ -+ - /********************************************************************** - * RtlWow64GetCurrentMachine (NTDLL.@) - */ -@@ -294,8 +354,15 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes, - PS_CREATE_INFO create_info; - ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[6] ) / sizeof(ULONG_PTR)]; - PS_ATTRIBUTE_LIST *attr = (PS_ATTRIBUTE_LIST *)buffer; -+ HANDLE elevated_token = NULL; -+ NTSTATUS status; - UINT pos = 0; - -+ /* It's not clear whether we should use path or ¶ms->ImagePathName here, -+ * but Roblox Player tries to pass an empty string for the latter. */ -+ if (!token && image_needs_elevation( path )) -+ token = elevated_token = get_elevated_token(); -+ - RtlNormalizeProcessParams( params ); - - attr->Attributes[pos].Attribute = PS_ATTRIBUTE_IMAGE_NAME; -@@ -342,11 +409,13 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes, - InitializeObjectAttributes( &process_attr, NULL, 0, NULL, process_descr ); - InitializeObjectAttributes( &thread_attr, NULL, 0, NULL, thread_descr ); - -- return NtCreateUserProcess( &info->Process, &info->Thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, -- &process_attr, &thread_attr, -- inherit ? PROCESS_CREATE_FLAGS_INHERIT_HANDLES : 0, -- THREAD_CREATE_FLAGS_CREATE_SUSPENDED, params, -- &create_info, attr ); -+ status = NtCreateUserProcess( &info->Process, &info->Thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, -+ &process_attr, &thread_attr, -+ inherit ? PROCESS_CREATE_FLAGS_INHERIT_HANDLES : 0, -+ THREAD_CREATE_FLAGS_CREATE_SUSPENDED, params, &create_info, attr ); -+ -+ if (elevated_token) NtClose( elevated_token ); -+ return status; - } - - /*********************************************************************** --- -2.32.0 - diff --git a/patches/wine-hotfixes/staging-7.0/server-default_integrity/definition b/patches/wine-hotfixes/staging-7.0/server-default_integrity/definition deleted file mode 100644 index 31f971cad..000000000 --- a/patches/wine-hotfixes/staging-7.0/server-default_integrity/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [40613] Multiple applications require UAC implementation to run installer/app as a normal user instead of administrator (WhatsApp Desktop, Smartflix, Squirrel Installers, OneDrive) -Fixes: [39262] DiscordSetup.exe (.NET 4.5.2 app): Squirrell installer requires being run as unelevated process ('explorer.exe' should run unelevated by default with Vista+ setting) diff --git a/patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/0001-shell32-Implement-NewMenu-with-new-folder-item.patch b/patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/0001-shell32-Implement-NewMenu-with-new-folder-item.patch deleted file mode 100644 index a057d85bc..000000000 --- a/patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/0001-shell32-Implement-NewMenu-with-new-folder-item.patch +++ /dev/null @@ -1,607 +0,0 @@ -From 9601c7ebe3adaef521073e4b5ab7728d9da3c8f7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Sun, 16 Aug 2015 17:34:22 +0200 -Subject: [PATCH] shell32: Implement NewMenu with new folder item. - -v2: -Added and Correct tests -Use IContextMenu3 for all IContextMenu* interfaces. -Use heap_alloc/free functions - -v3: -Correct header issue when compiling i386 (var_arg) ---- - dlls/shell32/Makefile.in | 1 + - dlls/shell32/shell32_classes.idl | 5 + - dlls/shell32/shell32_main.h | 1 + - dlls/shell32/shellnew.c | 497 +++++++++++++++++++++++++++++++ - dlls/shell32/shellole.c | 1 + - dlls/shell32/tests/shlview.c | 9 +- - 6 files changed, 513 insertions(+), 1 deletion(-) - create mode 100644 dlls/shell32/shellnew.c - -diff --git a/dlls/shell32/Makefile.in b/dlls/shell32/Makefile.in -index 04dd196cfe8..072d98b5fba 100644 ---- a/dlls/shell32/Makefile.in -+++ b/dlls/shell32/Makefile.in -@@ -33,6 +33,7 @@ C_SRCS = \ - shelldispatch.c \ - shellitem.c \ - shelllink.c \ -+ shellnew.c \ - shellole.c \ - shellord.c \ - shellpath.c \ -diff --git a/dlls/shell32/shell32_classes.idl b/dlls/shell32/shell32_classes.idl -index 22ef49ae5c7..699ad1a2f03 100644 ---- a/dlls/shell32/shell32_classes.idl -+++ b/dlls/shell32/shell32_classes.idl -@@ -86,6 +86,11 @@ coclass KnownFolderManager { interface IKnownFolderManager; } - uuid(4657278a-411b-11d2-839a-00c04fd918d0) - ] coclass DragDropHelper { interface IDropTargetHelper; } - -+[ -+ threading(apartment), -+ uuid(d969a300-e7ff-11d0-a93b-00a0c90f2719) -+] coclass NewMenu { interface IShellExtInit; } -+ - [ - threading(apartment), - uuid(00bb2763-6a77-11d0-a535-00c04fd7d062) -diff --git a/dlls/shell32/shell32_main.h b/dlls/shell32/shell32_main.h -index b98629298aa..d684d8759a7 100644 ---- a/dlls/shell32/shell32_main.h -+++ b/dlls/shell32/shell32_main.h -@@ -102,6 +102,7 @@ HRESULT WINAPI RecycleBin_Constructor(IUnknown * pUnkOuter, REFIID riif, LPVOID - HRESULT WINAPI QueryAssociations_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppOutput) DECLSPEC_HIDDEN; - HRESULT WINAPI ExplorerBrowser_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv) DECLSPEC_HIDDEN; - HRESULT WINAPI KnownFolderManager_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppv) DECLSPEC_HIDDEN; -+HRESULT WINAPI NewMenu_Constructor(IUnknown *outer, REFIID riid, LPVOID *ppv) DECLSPEC_HIDDEN; - HRESULT WINAPI IFileOperation_Constructor(IUnknown *outer, REFIID riid, void **out) DECLSPEC_HIDDEN; - extern HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST, LPWSTR, UINT, int*) DECLSPEC_HIDDEN; - HRESULT WINAPI CPanel_ExtractIconA(LPITEMIDLIST pidl, LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) DECLSPEC_HIDDEN; -diff --git a/dlls/shell32/shellnew.c b/dlls/shell32/shellnew.c -new file mode 100644 -index 00000000000..04d718f0f0d ---- /dev/null -+++ b/dlls/shell32/shellnew.c -@@ -0,0 +1,497 @@ -+/* -+ * Copyright 2015 Michael Müller -+ * -+ * 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 -+#define NONAMELESSUNION -+ -+#include -+ -+#include "winerror.h" -+#include "windef.h" -+#include "winbase.h" -+#include "winnls.h" -+#include "winreg.h" -+ -+#include "winuser.h" -+#include "wingdi.h" -+#include "shlobj.h" -+#include "undocshell.h" -+ -+#include "pidl.h" -+#include "shell32_main.h" -+#include "shlguid.h" -+#include "shlwapi.h" -+#include "shresdef.h" -+#include "shellfolder.h" -+ -+#include "wine/heap.h" -+#include "wine/debug.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(shell); -+ -+typedef struct -+{ -+ IShellExtInit IShellExtInit_iface; -+ IContextMenu3 IContextMenu3_iface; -+ IObjectWithSite IObjectWithSite_iface; -+ -+ LONG ref; -+ IUnknown *site; -+ LPITEMIDLIST pidl; -+ HICON icon_folder; -+ -+ UINT folder_cmd; -+} NewMenuImpl; -+ -+static inline NewMenuImpl *impl_from_IShellExtInit(IShellExtInit *iface) -+{ -+ return CONTAINING_RECORD(iface, NewMenuImpl, IShellExtInit_iface); -+} -+ -+static inline NewMenuImpl *impl_from_IContextMenu3(IContextMenu3 *iface) -+{ -+ return CONTAINING_RECORD(iface, NewMenuImpl, IContextMenu3_iface); -+} -+ -+static inline NewMenuImpl *impl_from_IObjectWithSite(IObjectWithSite *iface) -+{ -+ return CONTAINING_RECORD(iface, NewMenuImpl, IObjectWithSite_iface); -+} -+ -+static HRESULT WINAPI -+NewMenu_ExtInit_QueryInterface(IShellExtInit *iface, REFIID riid, void **ppv) -+{ -+ NewMenuImpl *This = impl_from_IShellExtInit(iface); -+ TRACE("(%p)->(%s)\n", This, debugstr_guid(riid)); -+ -+ *ppv = NULL; -+ -+ if (IsEqualIID(riid, &IID_IUnknown) || -+ IsEqualIID(riid, &IID_IShellExtInit)) -+ { -+ *ppv = &This->IShellExtInit_iface; -+ } -+ else if (IsEqualIID(riid, &IID_IObjectWithSite)) -+ { -+ *ppv = &This->IObjectWithSite_iface; -+ } -+ else if (IsEqualIID(riid, &IID_IContextMenu) || -+ IsEqualIID(riid, &IID_IContextMenu2) || -+ IsEqualIID(riid, &IID_IContextMenu3)) -+ { -+ *ppv = &This->IContextMenu3_iface; -+ } -+ -+ if (*ppv) -+ { -+ IUnknown_AddRef((IUnknown *)*ppv); -+ TRACE("-- Interface: (%p)->(%p)\n", ppv, *ppv); -+ return S_OK; -+ } -+ -+ ERR("-- Interface: E_NOINTERFACE for %s\n", debugstr_guid(riid)); -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI -+NewMenu_ExtInit_AddRef(IShellExtInit *iface) -+{ -+ NewMenuImpl *This = impl_from_IShellExtInit(iface); -+ ULONG ref = InterlockedIncrement(&This->ref); -+ -+ TRACE("(%p), refcount=%i\n", iface, ref); -+ -+ return ref; -+} -+ -+static ULONG WINAPI -+NewMenu_ExtInit_Release(IShellExtInit *iface) -+{ -+ NewMenuImpl *This = impl_from_IShellExtInit(iface); -+ ULONG ref = InterlockedDecrement(&This->ref); -+ -+ TRACE("(%p), refcount=%i\n", iface, ref); -+ -+ if (!ref) -+ { -+ if (This->site) IUnknown_Release(This->site); -+ if (This->pidl) ILFree(This->pidl); -+ heap_free(This); -+ } -+ -+ return ref; -+} -+ -+static HRESULT WINAPI -+NewMenu_ExtInit_Initialize(IShellExtInit *iface, LPCITEMIDLIST pidl, IDataObject *obj, HKEY key) -+{ -+ NewMenuImpl *This = impl_from_IShellExtInit(iface); -+ -+ TRACE("(%p)->(%p, %p, %p)\n", This, pidl, obj, key ); -+ -+ if (!pidl) -+ return E_FAIL; -+ -+ if (This->pidl) ILFree(This->pidl); -+ This->pidl = ILClone(pidl); -+ This->icon_folder = LoadImageW(shell32_hInstance, (LPCWSTR)MAKEINTRESOURCE(IDI_SHELL_FOLDER), IMAGE_ICON, -+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); -+ -+ return S_OK; -+} -+ -+static const IShellExtInitVtbl eivt = -+{ -+ NewMenu_ExtInit_QueryInterface, -+ NewMenu_ExtInit_AddRef, -+ NewMenu_ExtInit_Release, -+ NewMenu_ExtInit_Initialize -+}; -+ -+ -+static HRESULT WINAPI -+NewMenu_ObjectWithSite_QueryInterface(IObjectWithSite *iface, REFIID riid, void **ppv) -+{ -+ NewMenuImpl *This = impl_from_IObjectWithSite(iface); -+ return NewMenu_ExtInit_QueryInterface(&This->IShellExtInit_iface, riid, ppv); -+} -+ -+static ULONG WINAPI -+NewMenu_ObjectWithSite_AddRef(IObjectWithSite *iface) -+{ -+ NewMenuImpl *This = impl_from_IObjectWithSite(iface); -+ return NewMenu_ExtInit_AddRef(&This->IShellExtInit_iface); -+} -+ -+static ULONG WINAPI -+NewMenu_ObjectWithSite_Release(IObjectWithSite *iface) -+{ -+ NewMenuImpl *This = impl_from_IObjectWithSite(iface); -+ return NewMenu_ExtInit_Release(&This->IShellExtInit_iface); -+} -+ -+static HRESULT WINAPI -+NewMenu_ObjectWithSite_GetSite(IObjectWithSite *iface, REFIID iid, void **ppv) -+{ -+ NewMenuImpl *This = impl_from_IObjectWithSite(iface); -+ -+ TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(iid), ppv); -+ -+ if (!This->site) -+ return E_FAIL; -+ -+ return IUnknown_QueryInterface(This->site, iid, ppv); -+} -+ -+static HRESULT WINAPI -+NewMenu_ObjectWithSite_SetSite(IObjectWithSite *iface, IUnknown *punk) -+{ -+ NewMenuImpl *This = impl_from_IObjectWithSite(iface); -+ -+ TRACE("(%p)->(%p)\n", This, punk); -+ -+ if (punk) -+ IUnknown_AddRef(punk); -+ -+ if (This->site) -+ IUnknown_Release(This->site); -+ -+ This->site = punk; -+ return S_OK; -+} -+ -+static const IObjectWithSiteVtbl owsvt = -+{ -+ NewMenu_ObjectWithSite_QueryInterface, -+ NewMenu_ObjectWithSite_AddRef, -+ NewMenu_ObjectWithSite_Release, -+ NewMenu_ObjectWithSite_SetSite, -+ NewMenu_ObjectWithSite_GetSite, -+}; -+ -+ -+static HRESULT WINAPI -+NewMenu_ContextMenu3_QueryInterface(IContextMenu3 *iface, REFIID riid, void **ppv) -+{ -+ NewMenuImpl *This = impl_from_IContextMenu3(iface); -+ return NewMenu_ExtInit_QueryInterface(&This->IShellExtInit_iface, riid, ppv); -+} -+ -+static ULONG WINAPI -+NewMenu_ContextMenu3_AddRef(IContextMenu3 *iface) -+{ -+ NewMenuImpl *This = impl_from_IContextMenu3(iface); -+ return NewMenu_ExtInit_AddRef(&This->IShellExtInit_iface); -+} -+ -+static ULONG WINAPI -+NewMenu_ContextMenu3_Release(IContextMenu3 *iface) -+{ -+ NewMenuImpl *This = impl_from_IContextMenu3(iface); -+ return NewMenu_ExtInit_Release(&This->IShellExtInit_iface); -+} -+ -+static HRESULT WINAPI -+NewMenu_ContextMenu3_GetCommandString(IContextMenu3 *iface, UINT_PTR cmd, UINT type, -+ UINT *reserved, LPSTR name, UINT max_len) -+{ -+ NewMenuImpl *This = impl_from_IContextMenu3(iface); -+ -+ FIXME("(%p)->(%lu %u %p %p %u): stub\n", This, cmd, type, reserved, name, max_len); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT create_folder(NewMenuImpl *This, IShellView *view) -+{ -+ IFolderView *folder_view = NULL; -+ IShellFolder *desktop = NULL; -+ IShellFolder *parent = NULL; -+ ISFHelper *helper = NULL; -+ LPITEMIDLIST pidl = NULL; -+ WCHAR nameW[MAX_PATH]; -+ HRESULT hr; -+ -+ if (view) -+ { -+ hr = IShellView_QueryInterface(view, &IID_IFolderView, (void **)&folder_view); -+ if (FAILED(hr)) return hr; -+ -+ hr = IFolderView_GetFolder(folder_view, &IID_IShellFolder, (void **)&parent); -+ if (FAILED(hr)) goto out; -+ } -+ else -+ { -+ hr = SHGetDesktopFolder(&desktop); -+ if (FAILED(hr)) goto out; -+ -+ hr = IShellFolder_BindToObject(desktop, This->pidl, NULL, &IID_IShellFolder, (void **)&parent); -+ if (FAILED(hr)) goto out; -+ } -+ -+ IShellFolder_QueryInterface(parent, &IID_ISFHelper, (void **)&helper); -+ if (FAILED(hr)) goto out; -+ -+ hr = ISFHelper_GetUniqueName(helper, nameW, MAX_PATH); -+ if (FAILED(hr)) goto out; -+ -+ hr = ISFHelper_AddFolder(helper, 0, nameW, &pidl); -+ if (FAILED(hr)) goto out; -+ -+ if (view) -+ { -+ IShellView_SelectItem(view, pidl, SVSI_DESELECTOTHERS | SVSI_EDIT | -+ SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT); -+ } -+ -+out: -+ if (pidl) SHFree(pidl); -+ if (helper) ISFHelper_Release(helper); -+ if (parent) IShellFolder_Release(parent); -+ if (desktop) IShellFolder_Release(desktop); -+ if (folder_view) IFolderView_Release(folder_view); -+ return hr; -+} -+ -+static HRESULT WINAPI -+NewMenu_ContextMenu3_InvokeCommand(IContextMenu3 *iface, LPCMINVOKECOMMANDINFO info) -+{ -+ NewMenuImpl *This = impl_from_IContextMenu3(iface); -+ IShellBrowser *browser; -+ IShellView *view = NULL; -+ HRESULT hr = E_FAIL; -+ -+ TRACE("(%p)->(%p)\n", This, info); -+ -+ /* New Folder */ -+ if (info->lpVerb == 0) -+ { -+ if ((browser = (IShellBrowser *)SendMessageA(info->hwnd, CWM_GETISHELLBROWSER, 0, 0))) -+ { -+ if (FAILED(IShellBrowser_QueryActiveShellView(browser, &view))) -+ view = NULL; -+ } -+ hr = create_folder(This, view); -+ if (view) IShellView_Release(view); -+ } -+ -+ return hr; -+} -+ -+static UINT insert_new_menu_items(NewMenuImpl *This, HMENU menu, UINT pos, UINT cmd_first, UINT cmd_last) -+{ -+ MENUITEMINFOW item; -+ WCHAR buffer[256]; -+ -+ memset(&item, 0, sizeof(item)); -+ item.cbSize = sizeof(item); -+ -+ if (cmd_first > cmd_last) -+ return cmd_first; -+ -+ /* FIXME: on windows it is only 'Folder' not 'New Folder' */ -+ if (!LoadStringW(shell32_hInstance, IDS_NEWFOLDER, buffer, sizeof(buffer) / sizeof(WCHAR))) -+ buffer[0] = 0; -+ -+ item.fMask = MIIM_ID | MIIM_BITMAP | MIIM_STRING; -+ item.dwTypeData = buffer; -+ item.cch = wcslen(buffer); -+ item.wID = cmd_first; -+ item.hbmpItem = HBMMENU_CALLBACK; -+ if (InsertMenuItemW(menu, pos, TRUE, &item)) -+ { -+ This->folder_cmd = cmd_first++; -+ pos++; -+ } -+ -+ return cmd_first; -+} -+ -+static HRESULT WINAPI -+NewMenu_ContextMenu3_QueryContextMenu(IContextMenu3 *iface, HMENU menu, UINT index, -+ UINT cmd_first, UINT cmd_last, UINT flags) -+{ -+ static WCHAR newW[] = {'N','e','w',0}; -+ NewMenuImpl *This = impl_from_IContextMenu3(iface); -+ MENUITEMINFOW item; -+ HMENU submenu; -+ UINT id; -+ -+ TRACE("(%p)->(%p, %u, %u, %u, %u)\n", This, -+ menu, index, cmd_first, cmd_last, flags ); -+ -+ if (!This->pidl) -+ return E_FAIL; -+ -+ submenu = CreateMenu(); -+ if (!submenu) return E_FAIL; -+ -+ id = insert_new_menu_items(This, submenu, 0, cmd_first, cmd_last); -+ -+ memset(&item, 0, sizeof(item)); -+ item.cbSize = sizeof(item); -+ item.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU; -+ item.fType = MFT_STRING; -+ item.wID = -1; -+ item.dwTypeData = newW; /* FIXME: load from resource file */ -+ item.cch = wcslen(newW); -+ item.fState = MFS_ENABLED; -+ item.hSubMenu = submenu; -+ -+ if (!InsertMenuItemW(menu, index, TRUE, &item)) -+ return E_FAIL; -+ -+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id); -+} -+ -+static HRESULT WINAPI -+NewMenu_ContextMenu3_HandleMenuMsg2(IContextMenu3 *iface, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *result) -+{ -+ NewMenuImpl *This = impl_from_IContextMenu3(iface); -+ -+ TRACE("(%p)->(%u, %lx, %lx, %p)\n", This, uMsg, wParam, lParam, result); -+ -+ switch (uMsg) -+ { -+ case WM_MEASUREITEM: -+ { -+ MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam; -+ if (!mis || mis->CtlType != ODT_MENU) -+ break; -+ -+ if (This->folder_cmd == mis->itemID) -+ { -+ mis->itemWidth = GetSystemMetrics(SM_CXSMICON); -+ mis->itemHeight = GetSystemMetrics(SM_CYSMICON); -+ } -+ -+ if (result) *result = TRUE; -+ break; -+ } -+ -+ case WM_DRAWITEM: -+ { -+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam; -+ HICON icon = 0; -+ UINT x, y; -+ -+ if (!dis || dis->CtlType != ODT_MENU) -+ break; -+ -+ if (This->folder_cmd == dis->itemID) -+ icon = This->icon_folder; -+ -+ if (!icon) -+ break; -+ -+ x = (dis->rcItem.right - dis->rcItem.left - GetSystemMetrics(SM_CXSMICON)) / 2; -+ y = (dis->rcItem.bottom - dis->rcItem.top - GetSystemMetrics(SM_CYSMICON)) / 2; -+ DrawStateW(dis->hDC, NULL, NULL, (LPARAM)icon, 0, x, y, 0, 0, DST_ICON | DSS_NORMAL); -+ -+ if (result) *result = TRUE; -+ break; -+ } -+ } -+ -+ return S_OK; -+} -+ -+static HRESULT WINAPI -+NewMenu_ContextMenu3_HandleMenuMsg(IContextMenu3 *iface, UINT uMsg, WPARAM wParam, LPARAM lParam) -+{ -+ return NewMenu_ContextMenu3_HandleMenuMsg2(iface, uMsg, wParam, lParam, NULL); -+} -+ -+static const IContextMenu3Vtbl cmvt3 = -+{ -+ NewMenu_ContextMenu3_QueryInterface, -+ NewMenu_ContextMenu3_AddRef, -+ NewMenu_ContextMenu3_Release, -+ NewMenu_ContextMenu3_QueryContextMenu, -+ NewMenu_ContextMenu3_InvokeCommand, -+ NewMenu_ContextMenu3_GetCommandString, -+ NewMenu_ContextMenu3_HandleMenuMsg, -+ NewMenu_ContextMenu3_HandleMenuMsg2 -+}; -+ -+HRESULT WINAPI NewMenu_Constructor(IUnknown *outer, REFIID riid, void **obj) -+{ -+ NewMenuImpl *menu; -+ HRESULT hr; -+ -+ TRACE("outer=%p riid=%s\n", outer, debugstr_guid(riid)); -+ -+ *obj = NULL; -+ -+ if (outer) -+ return CLASS_E_NOAGGREGATION; -+ -+ menu = heap_alloc_zero(sizeof(NewMenuImpl)); -+ if (!menu) return E_OUTOFMEMORY; -+ -+ menu->ref = 1; -+ menu->IShellExtInit_iface.lpVtbl = &eivt; -+ menu->IContextMenu3_iface.lpVtbl = &cmvt3; -+ menu->IObjectWithSite_iface.lpVtbl = &owsvt; -+ -+ TRACE("(%p)\n", menu); -+ -+ hr = IShellExtInit_QueryInterface(&menu->IShellExtInit_iface, riid, obj); -+ IShellExtInit_Release(&menu->IShellExtInit_iface); -+ return hr; -+} -diff --git a/dlls/shell32/shellole.c b/dlls/shell32/shellole.c -index d1f1afc3780..e521b7e8f70 100644 ---- a/dlls/shell32/shellole.c -+++ b/dlls/shell32/shellole.c -@@ -73,6 +73,7 @@ static const struct { - {&CLSID_MyComputer, ISF_MyComputer_Constructor}, - {&CLSID_MyDocuments, MyDocuments_Constructor}, - {&CLSID_NetworkPlaces, ISF_NetworkPlaces_Constructor}, -+ {&CLSID_NewMenu, NewMenu_Constructor}, - {&CLSID_Printers, Printers_Constructor}, - {&CLSID_QueryAssociations, QueryAssociations_Constructor}, - {&CLSID_RecycleBin, RecycleBin_Constructor}, -diff --git a/dlls/shell32/tests/shlview.c b/dlls/shell32/tests/shlview.c -index f5d96c8d441..dbb24d93564 100644 ---- a/dlls/shell32/tests/shlview.c -+++ b/dlls/shell32/tests/shlview.c -@@ -1479,7 +1479,6 @@ static void test_newmenu(void) - HRESULT hr; - - hr = CoCreateInstance(&CLSID_NewMenu, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk); --todo_wine - ok(hr == S_OK, "Failed to create NewMenu object, hr %#x.\n", hr); - if (hr != S_OK) - { -@@ -1491,6 +1490,14 @@ todo_wine - ok(hr == S_OK, "Failed to get IShellExtInit, hr %#x.\n", hr); - IUnknown_Release(unk2); - -+ hr = IUnknown_QueryInterface(unk, &IID_IContextMenu, (void **)&unk2); -+ ok(hr == S_OK, "Failed to get IContextMenu, hr %#x.\n", hr); -+ IUnknown_Release(unk2); -+ -+ hr = IUnknown_QueryInterface(unk, &IID_IContextMenu2, (void **)&unk2); -+ ok(hr == S_OK, "Failed to get IContextMenu2, hr %#x.\n", hr); -+ IUnknown_Release(unk2); -+ - hr = IUnknown_QueryInterface(unk, &IID_IContextMenu3, (void **)&unk2); - ok(hr == S_OK, "Failed to get IContextMenu3, hr %#x.\n", hr); - IUnknown_Release(unk2); --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/definition b/patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/definition deleted file mode 100644 index 36964efc0..000000000 --- a/patches/wine-hotfixes/staging-7.0/shell32-NewMenu_Interface/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [24812] Implement shell32 NewMenu class with new folder item diff --git a/patches/wine-hotfixes/staging-7.0/staging-esync_remove_ntdll_Junction_Points_dependency.patch b/patches/wine-hotfixes/staging-7.0/staging-esync_remove_ntdll_Junction_Points_dependency.patch deleted file mode 100644 index 22e241f09..000000000 --- a/patches/wine-hotfixes/staging-7.0/staging-esync_remove_ntdll_Junction_Points_dependency.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 64a9d9fad97ae0d3ad45ad44390fc5276845d2aa Mon Sep 17 00:00:00 2001 -From: Tk-Glitch -Date: Tue, 2 Nov 2021 12:41:27 +0100 -Subject: Allow for disabling ntdll-Junction_Points, server-File_Permissions and server-Stored_ACLs staging patchsets - -Those are dependencies for eventfd_synchronization in current staging - - -diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh -index 114e663c..b50c06f4 100755 ---- a/patches/patchinstall.sh -+++ b/patches/patchinstall.sh -@@ -1314,9 +1314,6 @@ if test "$enable_winedevice_Default_Drivers" -eq 1; then - fi - - if test "$enable_eventfd_synchronization" -eq 1; then -- if test "$enable_ntdll_Junction_Points" -gt 1; then -- abort "Patchset ntdll-Junction_Points disabled, but eventfd_synchronization depends on that." -- fi - if test "$enable_server_PeekMessage" -gt 1; then - abort "Patchset server-PeekMessage disabled, but eventfd_synchronization depends on that." - fi -@@ -1326,7 +1323,6 @@ if test "$enable_eventfd_synchronization" -eq 1; then - if test "$enable_server_Signal_Thread" -gt 1; then - abort "Patchset server-Signal_Thread disabled, but eventfd_synchronization depends on that." - fi -- enable_ntdll_Junction_Points=1 - enable_server_PeekMessage=1 - enable_server_Realtime_Priority=1 - enable_server_Signal_Thread=1 -diff --git a/patches/eventfd_synchronization/0046-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch b/patches/eventfd_synchronization/0046-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch -index 18dfad0f..f05ef0bb 100644 ---- a/patches/eventfd_synchronization/0046-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch -+++ b/patches/eventfd_synchronization/0046-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch -@@ -31,7 +31,7 @@ index 880a5037925..c6db8d13265 100644 - - static void fd_dump( struct object *obj, int verbose ); - @@ -1606,6 +1608,9 @@ static void fd_destroy( struct object *obj ) -- free( fd->unlink_name ); -+ if (fd->unix_fd != -1) close( fd->unix_fd ); - free( fd->unix_name ); - } - + - diff --git a/patches/wine-hotfixes/staging-7.0/staging-revert-user32-msgbox.patch b/patches/wine-hotfixes/staging-7.0/staging-revert-user32-msgbox.patch deleted file mode 100644 index 3f6a9a23d..000000000 --- a/patches/wine-hotfixes/staging-7.0/staging-revert-user32-msgbox.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git a/patches/user32-msgbox-Support-WM_COPY-mesg/0002-user32-msgbox-Use-a-windows-hook-to-trap-Ctrl-C.patch b/patches/user32-msgbox-Support-WM_COPY-mesg/0002-user32-msgbox-Use-a-windows-hook-to-trap-Ctrl-C.patch -index c9d8da655..ec3df53d0 100644 ---- a/patches/user32-msgbox-Support-WM_COPY-mesg/0002-user32-msgbox-Use-a-windows-hook-to-trap-Ctrl-C.patch -+++ b/patches/user32-msgbox-Support-WM_COPY-mesg/0002-user32-msgbox-Use-a-windows-hook-to-trap-Ctrl-C.patch -@@ -1,4 +1,4 @@ --From 455aefaf6f4e5b3b631722be3ad0911dbe015952 Mon Sep 17 00:00:00 2001 -+From 05f0a7d14311569807af62cc87780a67cb26194a Mon Sep 17 00:00:00 2001 - From: Alistair Leslie-Hughes - Date: Thu, 10 Jan 2019 16:17:33 +1100 - Subject: [PATCH] user32/msgbox: Use a windows hook to trap Ctrl+C -@@ -8,7 +8,7 @@ Subject: [PATCH] user32/msgbox: Use a windows hook to trap Ctrl+C - 1 file changed, 20 insertions(+) - - diff --git a/dlls/user32/msgbox.c b/dlls/user32/msgbox.c --index d47d9eaac22..db036b28b69 100644 -+index d47d9eaac22..cf00d69df69 100644 - --- a/dlls/user32/msgbox.c - +++ b/dlls/user32/msgbox.c - @@ -388,6 +388,22 @@ static void MSGBOX_CopyToClipbaord( HWND hwnd ) -@@ -28,7 +28,7 @@ index d47d9eaac22..db036b28b69 100644 - + } - + } - + --+ return CallNextHookEx(msghook_handle, nCode, wParam, lParam); -++ return NtUserCallNextHookEx(msghook_handle, nCode, wParam, lParam); - +} - + - /************************************************************************** -@@ -53,5 +53,5 @@ index d47d9eaac22..db036b28b69 100644 - case WM_COMMAND: - switch (LOWORD(wParam)) - -- --2.34.1 -+2.35.1 diff --git a/patches/wine-hotfixes/staging-7.0/staging-server-default-integrity.patch b/patches/wine-hotfixes/staging-7.0/staging-server-default-integrity.patch deleted file mode 100644 index 23dc6ead1..000000000 --- a/patches/wine-hotfixes/staging-7.0/staging-server-default-integrity.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh -index 97b65fafd..44061a2c1 100755 ---- a/patches/patchinstall.sh -+++ b/patches/patchinstall.sh -@@ -3070,13 +3070,17 @@ fi - # | should run unelevated by default with Vista+ setting) - # | - # | Modified files: --# | * dlls/msi/custom.c, dlls/shell32/shlexec.c, loader/wine.inf.in, server/process.c -+# | * dlls/kernelbase/process.c, dlls/msi/custom.c, dlls/ntdll/process.c, dlls/ntdll/unix/env.c, dlls/shell32/shlexec.c, -+# | loader/wine.inf.in, server/process.c - # | - if test "$enable_server_default_integrity" -eq 1; then - patch_apply server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch - patch_apply server-default_integrity/0002-shell32-Implement-the-runas-verb.patch - patch_apply server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch - patch_apply server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch -+ patch_apply server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch -+ patch_apply server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch -+ patch_apply server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch - fi - - # Patchset setupapi-DiskSpaceList diff --git a/patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/0001-user32-Improve-FlashWindowEx-message-and-return-valu.patch b/patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/0001-user32-Improve-FlashWindowEx-message-and-return-valu.patch deleted file mode 100644 index 6e93951ab..000000000 --- a/patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/0001-user32-Improve-FlashWindowEx-message-and-return-valu.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 6f9a7411f7e0f9db155818b15c3bb1dfba2bbbd3 Mon Sep 17 00:00:00 2001 -From: James Coonradt -Date: Tue, 19 Sep 2017 12:28:50 -0600 -Subject: user32: Improve FlashWindowEx message and return value. - ---- - dlls/user32/win.c | 5 ++--- - 2 files changed, 4 insertions(+), 5 deletions(-) - -diff --git a/dlls/user32/win.c b/dlls/user32/win.c -index 3042a560ce9..2fb33058b6c 100644 ---- a/dlls/user32/win.c -+++ b/dlls/user32/win.c -@@ -3545,13 +3545,12 @@ BOOL WINAPI FlashWindowEx( PFLASHWINFO pfinfo ) - if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE; - hwnd = wndPtr->obj.handle; /* make it a full handle */ - -- if (pfinfo->dwFlags) wparam = !(wndPtr->flags & WIN_NCACTIVATED); -- else wparam = (hwnd == GetForegroundWindow()); -+ wparam = (wndPtr->flags & WIN_NCACTIVATED) != 0; - - WIN_ReleasePtr( wndPtr ); - SendNotifyMessageW( hwnd, WM_NCACTIVATE, wparam, 0 ); - USER_Driver->pFlashWindowEx( pfinfo ); -- return wparam; -+ return (pfinfo->dwFlags & FLASHW_CAPTION) ? TRUE : wparam; - } - } - --- -2.14.1 - diff --git a/patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/definition b/patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/definition deleted file mode 100644 index 2cb723511..000000000 --- a/patches/wine-hotfixes/staging-7.0/user32-FlashWindowEx/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [43124] FlashWindowEx: WM_NCACTIVATE behavior is incorrect diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0001-include-Add-windows.networking.connectivity.idl.patch b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0001-include-Add-windows.networking.connectivity.idl.patch deleted file mode 100644 index a22ea977b..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0001-include-Add-windows.networking.connectivity.idl.patch +++ /dev/null @@ -1,400 +0,0 @@ -From a5d61672e671ca208fb51fd227566179128bc888 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Fri, 28 May 2021 12:34:37 +1000 -Subject: [PATCH] include: Add windows.networking.connectivity.idl - ---- - include/Makefile.in | 1 + - include/windows.networking.connectivity.idl | 368 ++++++++++++++++++++ - 2 files changed, 369 insertions(+) - create mode 100644 include/windows.networking.connectivity.idl - -diff --git a/include/Makefile.in b/include/Makefile.in -index a1bf9fbd594..e379070caa9 100644 ---- a/include/Makefile.in -+++ b/include/Makefile.in -@@ -790,6 +790,7 @@ SOURCES = \ - windows.media.devices.idl \ - windows.media.idl \ - windows.media.speechsynthesis.idl \ -+ windows.networking.connectivity.idl \ - windows.security.cryptography.idl \ - windows.security.exchangeactivesyncprovisioning.idl \ - windows.storage.streams.idl \ -diff --git a/include/windows.networking.connectivity.idl b/include/windows.networking.connectivity.idl -new file mode 100644 -index 00000000000..3ccefca02fa ---- /dev/null -+++ b/include/windows.networking.connectivity.idl -@@ -0,0 +1,368 @@ -+/* -+ * Copyright 2021 Alistair Leslie-Hughes -+ * -+ * 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 "inspectable.idl"; -+import "asyncinfo.idl"; -+import "eventtoken.idl"; -+import "windowscontracts.idl"; -+import "windows.foundation.idl"; -+ -+namespace Windows -+{ -+ namespace Foundation -+ { -+ interface IClosable; -+ -+ /*runtimeclass Uri;*/ -+ } -+} -+ -+namespace Windows -+{ -+ namespace Networking -+ { -+ /*typedef enum DomainNameType DomainNameType;*/ -+ -+ /*runtimeclass EndpointPair;*/ -+ -+ /*runtimeclass HostName;*/ -+ -+ /*typedef enum HostNameSortOptions HostNameSortOptions;*/ -+ } -+} -+ -+namespace Windows -+{ -+ namespace Networking -+ { -+ namespace Connectivity -+ { -+ runtimeclass ConnectionCost; -+ runtimeclass ConnectionProfile; -+ runtimeclass DataPlanStatus; -+ runtimeclass DataPlanUsage; -+ runtimeclass DataUsage; -+ runtimeclass IPInformation; -+ runtimeclass LanIdentifier; -+ runtimeclass LanIdentifierData; -+ runtimeclass NetworkAdapter; -+ runtimeclass NetworkInformation; -+ runtimeclass NetworkSecuritySettings; -+ runtimeclass ProxyConfiguration; -+ -+ typedef enum NetworkConnectivityLevel NetworkConnectivityLevel; -+ typedef enum NetworkCostType NetworkCostType; -+ typedef enum RoamingStates RoamingStates; -+ typedef enum NetworkAuthenticationType NetworkAuthenticationType; -+ typedef enum NetworkEncryptionType NetworkEncryptionType; -+ -+ declare -+ { -+ interface Windows.Foundation.Collections.IVectorView; -+ interface Windows.Foundation.Collections.IVectorView; -+ /*interface Windows.Foundation.Collections.IVectorView;*/ -+ /*interface Windows.Foundation.Collections.IVectorView;*/ -+ -+ -+ /*interface Windows.Foundation.Collections.IIterable;*/ -+ -+ /*interface Windows.Foundation.IAsyncOperation;*/ -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ enum NetworkConnectivityLevel -+ { -+ None, -+ LocalAccess, -+ ConstrainedInternetAccess, -+ InternetAccess -+ }; -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ enum NetworkCostType -+ { -+ Unknown, -+ Unrestricted, -+ Fixed, -+ Variable -+ }; -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [flags] -+ enum RoamingStates -+ { -+ None = 0x0, -+ NotRoaming = 0x1, -+ Roaming = 0x2 -+ }; -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ enum NetworkAuthenticationType -+ { -+ None, -+ Unknown, -+ Open80211, -+ SharedKey80211, -+ Wpa, -+ WpaPsk, -+ WpaNone, -+ Rsna, -+ RsnaPsk, -+ Ihv -+ }; -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ enum NetworkEncryptionType -+ { -+ None, -+ Unknown, -+ Wep, -+ Wep40, -+ Wep104, -+ Tkip, -+ Ccmp, -+ WpaUseGroup, -+ RsnUseGroup, -+ Ihv -+ }; -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [uuid(71ba143f-598e-49d0-84eb-8febaedcc195)] -+ delegate HRESULT NetworkStatusChangedEventHandler([in] IInspectable* sender); -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.ConnectionProfile)] -+ [uuid(71ba143c-598e-49d0-84eb-8febaedcc195)] -+ interface IConnectionProfile : IInspectable -+ { -+ [propget] HRESULT ProfileName([out, retval] HSTRING* value); -+ HRESULT GetNetworkConnectivityLevel([out, retval] Windows.Networking.Connectivity.NetworkConnectivityLevel* value); -+ HRESULT GetNetworkNames([out, retval] Windows.Foundation.Collections.IVectorView** value); -+ HRESULT GetConnectionCost([out, retval] Windows.Networking.Connectivity.ConnectionCost** value); -+ HRESULT GetDataPlanStatus([out, retval] Windows.Networking.Connectivity.DataPlanStatus** value); -+ [propget] HRESULT NetworkAdapter([out, retval] Windows.Networking.Connectivity.NetworkAdapter** value); -+ HRESULT GetLocalUsage([in] Windows.Foundation.DateTime start, [in] Windows.Foundation.DateTime end, -+ [out, retval] Windows.Networking.Connectivity.DataUsage** value); -+ HRESULT GetLocalUsagePerRoamingStates([in] Windows.Foundation.DateTime start, -+ [in] Windows.Foundation.DateTime end, [in] Windows.Networking.Connectivity.RoamingStates states, -+ [out, retval] Windows.Networking.Connectivity.DataUsage** value); -+ [propget] HRESULT NetworkSecuritySettings([out, retval] Windows.Networking.Connectivity.NetworkSecuritySettings** value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.LanIdentifier)] -+ [uuid(48aa53aa-1108-4546-a6cb-9a74da4b7ba0)] -+ interface ILanIdentifier : IInspectable -+ { -+ [propget] HRESULT InfrastructureId([out, retval] Windows.Networking.Connectivity.LanIdentifierData** value); -+ [propget] HRESULT PortId([out, retval] Windows.Networking.Connectivity.LanIdentifierData** value); -+ [propget] HRESULT NetworkAdapterId([out, retval] GUID* value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.LanIdentifierData)] -+ [uuid(a74e83c3-d639-45be-a36a-c4e4aeaf6d9b)] -+ interface ILanIdentifierData : IInspectable -+ { -+ [propget] HRESULT Type([out, retval] UINT32* value); -+ [propget] HRESULT Value([out,retval] /*Windows.Foundation.Collections.IVectorView** */ BYTE **value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.IPInformation)] -+ [uuid(d85145e0-138f-47d7-9b3a-36bb488cef33)] -+ interface IIPInformation : IInspectable -+ { -+ [propget] HRESULT NetworkAdapter([out, retval] Windows.Networking.Connectivity.NetworkAdapter** value); -+ [propget] HRESULT PrefixLength([out, retval] /*Windows.Foundation.IReference** */ BYTE **value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.NetworkInformation)] -+ [uuid(5074f851-950d-4165-9c15-365619481eea)] -+ interface INetworkInformationStatics : IInspectable -+ { -+ HRESULT GetConnectionProfiles([out, retval] Windows.Foundation.Collections.IVectorView** value); -+ HRESULT GetInternetConnectionProfile([out, retval] Windows.Networking.Connectivity.ConnectionProfile** value); -+ HRESULT GetLanIdentifiers([out, retval] Windows.Foundation.Collections.IVectorView** value); -+ HRESULT GetHostNames([out, retval] /*Windows.Foundation.Collections.IVectorView** */ DWORD **value); -+ HRESULT GetProxyConfigurationAsync(/*[in] Windows.Foundation.Uri* */ char* uri, -+ [out, retval] /*Windows.Foundation.IAsyncOperation** */ DWORD **value); -+ HRESULT GetSortedEndpointPairs([in] /* Windows.Foundation.Collections.IIterable* */ DWORD *endpoint, -+ [in] /*Windows.Networking.HostNameSortOptions*/ DWORD options, -+ [out, retval] /*Windows.Foundation.Collections.IVectorView** */ DWORD **value); -+ [eventadd] HRESULT NetworkStatusChanged([in] Windows.Networking.Connectivity.NetworkStatusChangedEventHandler* handler, -+ [out, retval] EventRegistrationToken* eventCookie); -+ [eventremove] HRESULT NetworkStatusChanged([in] EventRegistrationToken cookie); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.ConnectionCost)] -+ [uuid(bad7d829-3416-4b10-a202-bac0b075bdae)] -+ interface IConnectionCost : IInspectable -+ { -+ [propget] HRESULT NetworkCostType([out, retval] Windows.Networking.Connectivity.NetworkCostType* value); -+ [propget] HRESULT Roaming([out, retval] boolean* value); -+ [propget] HRESULT OverDataLimit([out, retval] boolean* value); -+ [propget] HRESULT ApproachingDataLimit([out, retval] boolean* value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.DataUsage)] -+ [uuid(c1431dd3-b146-4d39-b959-0c69b096c512)] -+ interface IDataUsage : IInspectable -+ { -+ [propget] HRESULT BytesSent([out, retval] UINT64* value); -+ [propget] HRESULT BytesReceived([out, retval] UINT64* value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.NetworkAdapter)] -+ [uuid(3b542e03-5388-496c-a8a3-affd39aec2e6)] -+ interface INetworkAdapter : IInspectable -+ { -+ [propget] HRESULT OutboundMaxBitsPerSecond([out, retval] UINT64* value); -+ [propget] HRESULT InboundMaxBitsPerSecond([out ,retval] UINT64* value); -+ [propget] HRESULT IanaInterfaceType([out, retval] UINT32* value); -+ [propget] HRESULT NetworkItem([out, retval] /*Windows.Networking.Connectivity.NetworkItem** */ DWORD **value); -+ [propget] HRESULT NetworkAdapterId([out, retval] GUID* value); -+ HRESULT GetConnectedProfileAsync([out, retval] /*Windows.Foundation.IAsyncOperation** */ DWORD **value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.NetworkSecuritySettings)] -+ [uuid(7CA07E8D-917B-4B5F-B84D-28F7A5AC5402)] -+ interface INetworkSecuritySettings : IInspectable -+ { -+ [propget] HRESULT NetworkAuthenticationType([out, retval] Windows.Networking.Connectivity.NetworkAuthenticationType* value); -+ [propget] HRESULT NetworkEncryptionType([out, retval] Windows.Networking.Connectivity.NetworkEncryptionType* value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.DataPlanUsage)] -+ [uuid(b921492d-3b44-47ff-b361-be59e69ed1b0)] -+ interface IDataPlanUsage : IInspectable -+ { -+ [propget] HRESULT MegabytesUsed([out] [retval] UINT32* value); -+ [propget] HRESULT LastSyncTime([out] [retval] Windows.Foundation.DateTime* value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.Connectivity.DataPlanStatus)] -+ [uuid(977a8b8c-3885-40f3-8851-42cd2bd568bb)] -+ interface IDataPlanStatus : IInspectable -+ { -+ [propget] HRESULT DataPlanUsage([out, retval] Windows.Networking.Connectivity.DataPlanUsage** value); -+ [propget] HRESULT DataLimitInMegabytes([out, retval] /*Windows.Foundation.IReference** */ UINT32 **value); -+ [propget] HRESULT InboundBitsPerSecond([out, retval] /* Windows.Foundation.IReference** */ UINT64 **value); -+ [propget] HRESULT OutboundBitsPerSecond([out, retval] /* Windows.Foundation.IReference** */ UINT64 **value); -+ [propget] HRESULT NextBillingCycle([out, retval] /* Windows.Foundation.IReference** */ UINT64 **value); -+ [propget] HRESULT MaxTransferSizeInMegabytes([out, retval] /*Windows.Foundation.IReference** */ UINT32 **value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass DataPlanStatus -+ { -+ [default] interface Windows.Networking.Connectivity.IDataPlanStatus; -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass DataUsage -+ { -+ [default] interface Windows.Networking.Connectivity.IDataUsage; -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass NetworkAdapter -+ { -+ [default] interface Windows.Networking.Connectivity.INetworkAdapter; -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass DataPlanUsage -+ { -+ [default] interface Windows.Networking.Connectivity.IDataPlanUsage; -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ [static(Windows.Networking.Connectivity.INetworkInformationStatics, Windows.Foundation.UniversalApiContract, 1.0)] -+ /*[static(Windows.Networking.Connectivity.INetworkInformationStatics2, Windows.Foundation.UniversalApiContract, 1.0)]*/ -+ runtimeclass NetworkInformation -+ { -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass IPInformation -+ { -+ [default] interface Windows.Networking.Connectivity.IIPInformation; -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass NetworkSecuritySettings -+ { -+ [default] interface Windows.Networking.Connectivity.INetworkSecuritySettings; -+ } -+ -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass ConnectionProfile -+ { -+ [default] interface Windows.Networking.Connectivity.IConnectionProfile; -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] interface Windows.Networking.Connectivity.IConnectionProfile2; -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] interface Windows.Networking.Connectivity.IConnectionProfile3; -+ [contract(Windows.Foundation.UniversalApiContract, 5.0)] interface Windows.Networking.Connectivity.IConnectionProfile4; -+ [contract(Windows.Foundation.UniversalApiContract, 7.0)] interface Windows.Networking.Connectivity.IConnectionProfile5; -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass ConnectionCost -+ { -+ [default] interface Windows.Networking.Connectivity.IConnectionCost; -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] interface Windows.Networking.Connectivity.IConnectionCost2; -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass LanIdentifier -+ { -+ [default] interface Windows.Networking.Connectivity.ILanIdentifier; -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ runtimeclass LanIdentifierData -+ { -+ [default] interface Windows.Networking.Connectivity.ILanIdentifierData; -+ } -+ -+ } -+ } -+} --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0002-include-Add-windows.networking.idl.patch b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0002-include-Add-windows.networking.idl.patch deleted file mode 100644 index e5445054f..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0002-include-Add-windows.networking.idl.patch +++ /dev/null @@ -1,120 +0,0 @@ -From e98050400335c07a044c28774c802647ff075af5 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Tue, 1 Jun 2021 10:26:28 +1000 -Subject: [PATCH] include: Add windows.networking.idl - ---- - include/Makefile.in | 1 + - include/windows.networking.idl | 87 ++++++++++++++++++++++++++++++++++ - 2 files changed, 88 insertions(+) - create mode 100644 include/windows.networking.idl - -diff --git a/include/Makefile.in b/include/Makefile.in -index e379070caa9..043f1436216 100644 ---- a/include/Makefile.in -+++ b/include/Makefile.in -@@ -786,6 +786,7 @@ SOURCES = \ - windows.media.devices.idl \ - windows.media.idl \ - windows.media.speechsynthesis.idl \ -+ windows.networking.idl \ - windows.networking.connectivity.idl \ - windows.security.cryptography.idl \ - windows.security.exchangeactivesyncprovisioning.idl \ -diff --git a/include/windows.networking.idl b/include/windows.networking.idl -new file mode 100644 -index 00000000000..160cd78e540 ---- /dev/null -+++ b/include/windows.networking.idl -@@ -0,0 +1,87 @@ -+/* -+ * Copyright 2021 Alistair Leslie-Hughes -+ * -+ * 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 "inspectable.idl"; -+import "asyncinfo.idl"; -+import "eventtoken.idl"; -+import "windowscontracts.idl"; -+import "windows.foundation.idl"; -+import "windows.networking.connectivity.idl"; -+ -+namespace Windows -+{ -+ namespace Networking -+ { -+ typedef enum HostNameType HostNameType; -+ -+ runtimeclass HostName; -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ enum HostNameType -+ { -+ DomainName, -+ Ipv4, -+ Ipv6, -+ Bluetooth -+ }; -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.HostName)] -+ [uuid(bf8ecaad-ed96-49a7-9084-d416cae88dcb)] -+ interface IHostName : IInspectable -+ { -+ [propget] HRESULT IPInformation([out, retval] Windows.Networking.Connectivity.IPInformation** value); -+ [propget] HRESULT RawName([out, retval] HSTRING* value); -+ [propget] HRESULT DisplayName([out, retval] HSTRING* value); -+ [propget] HRESULT CanonicalName([out, retval] HSTRING* value); -+ [propget] HRESULT Type([out, retval] Windows.Networking.HostNameType* value); -+ HRESULT IsEqual([in] Windows.Networking.HostName* hostName, [out, retval] boolean* equal); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.HostName)] -+ [uuid(458c23ed-712f-4576-adf1-c20b2c643558)] -+ interface IHostNameFactory : IInspectable -+ { -+ HRESULT CreateHostName([in] HSTRING hostname, [out, retval] Windows.Networking.HostName** value); -+ } -+ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [exclusiveto(Windows.Networking.HostName)] -+ [uuid(f68cd4bf-a388-4e8b-91ea-54dd6dd901c0)] -+ interface IHostNameStatics : IInspectable -+ { -+ HRESULT Compare([in] HSTRING value1, [in] HSTRING value2, [out, retval] INT32* result); -+ } -+ -+ /*[activatable(Windows.Networking.IHostNameFactory, Windows.Foundation.UniversalApiContract, 1.0)]*/ -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] -+ [marshaling_behavior(agile)] -+ [static(Windows.Networking.IHostNameStatics, Windows.Foundation.UniversalApiContract, 1.0)] -+ [threading(both)] -+ runtimeclass HostName -+ { -+ [default] interface Windows.Networking.IHostName; -+ [contract(Windows.Foundation.UniversalApiContract, 1.0)] interface Windows.Foundation.IStringable; -+ } -+ } -+} -\ No newline at end of file --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0003-windows.networking.connectivity-Add-stub-dll.patch b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0003-windows.networking.connectivity-Add-stub-dll.patch deleted file mode 100644 index c1475f039..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0003-windows.networking.connectivity-Add-stub-dll.patch +++ /dev/null @@ -1,97 +0,0 @@ -From a446063a84d5b48ac4c8aa05abca98da8a386467 Mon Sep 17 00:00:00 2001 -From: Esdras Tarsis -Date: Wed, 2 Sep 2020 23:41:19 -0300 -Subject: [PATCH 3/8] windows.networking.connectivity: Add stub dll. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46534 -Signed-off-by: Esdras Tarsis ---- - configure.ac | 1 + - .../Makefile.in | 7 ++++ - .../windows.networking.connectivity.spec | 3 ++ - .../windows.networking.connectivity_main.c | 35 +++++++++++++++++++ - 4 files changed, 46 insertions(+) - create mode 100644 dlls/windows.networking.connectivity/Makefile.in - create mode 100644 dlls/windows.networking.connectivity/windows.networking.connectivity.spec - create mode 100644 dlls/windows.networking.connectivity/windows.networking.connectivity_main.c - -diff --git a/configure.ac b/configure.ac -index 7ea0d824cee..e8d0d8a9023 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3775,6 +3775,7 @@ WINE_CONFIG_MAKEFILE(dlls/windows.media.devices) - WINE_CONFIG_MAKEFILE(dlls/windows.media.speech) - WINE_CONFIG_MAKEFILE(dlls/windows.media.speech/tests) - WINE_CONFIG_MAKEFILE(dlls/windows.networking) -+WINE_CONFIG_MAKEFILE(dlls/windows.networking.connectivity) - WINE_CONFIG_MAKEFILE(dlls/windowscodecs) - WINE_CONFIG_MAKEFILE(dlls/windowscodecs/tests) - WINE_CONFIG_MAKEFILE(dlls/windowscodecsext) -diff --git a/dlls/windows.networking.connectivity/Makefile.in b/dlls/windows.networking.connectivity/Makefile.in -new file mode 100644 -index 00000000000..6fc24a72feb ---- /dev/null -+++ b/dlls/windows.networking.connectivity/Makefile.in -@@ -0,0 +1,7 @@ -+MODULE = windows.networking.connectivity -+IMPORTS = combase uuid -+ -+EXTRADLLFLAGS = -mno-cygwin -+ -+C_SRCS = \ -+ windows.networking.connectivity_main.c -diff --git a/dlls/windows.networking.connectivity/windows.networking.connectivity.spec b/dlls/windows.networking.connectivity/windows.networking.connectivity.spec -new file mode 100644 -index 00000000000..4b286869e02 ---- /dev/null -+++ b/dlls/windows.networking.connectivity/windows.networking.connectivity.spec -@@ -0,0 +1,3 @@ -+@ stdcall -private DllCanUnloadNow() -+@ stdcall -private DllGetActivationFactory(ptr ptr) -+@ stdcall -private DllGetClassObject(ptr ptr ptr) -\ No newline at end of file -diff --git a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -new file mode 100644 -index 00000000000..96ff0ea5af2 ---- /dev/null -+++ b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -@@ -0,0 +1,35 @@ -+#include -+ -+#define COBJMACROS -+#include "windef.h" -+#include "winbase.h" -+#include "winstring.h" -+#include "wine/debug.h" -+ -+#include "objbase.h" -+#include "initguid.h" -+ -+#include "activation.h" -+ -+WINE_DEFAULT_DEBUG_CHANNEL(network); -+ -+static const char *debugstr_hstring(HSTRING hstr) -+{ -+ const WCHAR *str; -+ UINT32 len; -+ if (hstr && !((ULONG_PTR)hstr >> 16)) return "(invalid)"; -+ str = WindowsGetStringRawBuffer(hstr, &len); -+ return wine_dbgstr_wn(str, len); -+} -+ -+HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, LPVOID *object) -+{ -+ FIXME("clsid %s, riid %s, object %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), object); -+ return CLASS_E_CLASSNOTAVAILABLE; -+} -+ -+HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory) -+{ -+ FIXME("classid %s, factory %p stub!\n", debugstr_hstring(classid), factory); -+ return E_NOINTERFACE; -+} -\ No newline at end of file --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0004-windows.networking.connectivity-Implement-IActivatio.patch b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0004-windows.networking.connectivity-Implement-IActivatio.patch deleted file mode 100644 index 9ac057ea2..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0004-windows.networking.connectivity-Implement-IActivatio.patch +++ /dev/null @@ -1,136 +0,0 @@ -From 587e8baeef029940518223d13b754b4e6c0352cd Mon Sep 17 00:00:00 2001 -From: Esdras Tarsis -Date: Wed, 2 Sep 2020 23:53:28 -0300 -Subject: [PATCH 4/8] windows.networking.connectivity: Implement - IActivationFactory stubs. - -v2: -Add Proper QueryInterface -Fixed Initial Reference Count value. ---- - .../windows.networking.connectivity_main.c | 104 +++++++++++++++++- - 1 file changed, 101 insertions(+), 3 deletions(-) - -diff --git a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -index 96ff0ea5af2..2463cc2c93c 100644 ---- a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -+++ b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -@@ -22,6 +22,102 @@ static const char *debugstr_hstring(HSTRING hstr) - return wine_dbgstr_wn(str, len); - } - -+struct windows_networking_connectivity -+{ -+ IActivationFactory IActivationFactory_iface; -+ LONG refcount; -+}; -+ -+static inline struct windows_networking_connectivity *impl_from_IActivationFactory(IActivationFactory *iface) -+{ -+ return CONTAINING_RECORD(iface, struct windows_networking_connectivity, IActivationFactory_iface); -+} -+ -+static HRESULT STDMETHODCALLTYPE windows_networking_connectivity_QueryInterface( -+ IActivationFactory *iface, REFIID iid, void **object) -+{ -+ TRACE("iface %p, iid %s, object %p stub!\n", iface, debugstr_guid(iid), object); -+ -+ if (IsEqualGUID(iid, &IID_IUnknown) || -+ IsEqualGUID(iid, &IID_IInspectable) || -+ IsEqualGUID(iid, &IID_IAgileObject) || -+ IsEqualGUID(iid, &IID_IActivationFactory)) -+ { -+ IUnknown_AddRef(iface); -+ *object = &impl->INetworkInformationStatics_iface; -+ return S_OK; -+ } -+ -+ FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); -+ *object = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG STDMETHODCALLTYPE windows_networking_connectivity_AddRef( -+ IActivationFactory *iface) -+{ -+ struct windows_networking_connectivity *impl = impl_from_IActivationFactory(iface); -+ ULONG rc = InterlockedIncrement(&impl->refcount); -+ TRACE("%p increasing refcount to %u.\n", impl, rc); -+ return rc; -+} -+ -+static ULONG STDMETHODCALLTYPE windows_networking_connectivity_Release( -+ IActivationFactory *iface) -+{ -+ struct windows_networking_connectivity *impl = impl_from_IActivationFactory(iface); -+ ULONG rc = InterlockedDecrement(&impl->refcount); -+ TRACE("%p decreasing refcount to %u.\n", impl, rc); -+ return rc; -+} -+ -+static HRESULT STDMETHODCALLTYPE windows_networking_connectivity_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 STDMETHODCALLTYPE windows_networking_connectivity_GetRuntimeClassName( -+ IActivationFactory *iface, HSTRING *class_name) -+{ -+ FIXME("iface %p, class_name %p stub!\n", iface, class_name); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE windows_networking_connectivity_GetTrustLevel( -+ IActivationFactory *iface, TrustLevel *trust_level) -+{ -+ FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE windows_networking_connectivity_ActivateInstance( -+ IActivationFactory *iface, IInspectable **instance) -+{ -+ FIXME("iface %p, instance %p stub!\n", iface, instance); -+ return E_NOTIMPL; -+} -+ -+static const struct IActivationFactoryVtbl activation_factory_vtbl = -+{ -+ windows_networking_connectivity_QueryInterface, -+ windows_networking_connectivity_AddRef, -+ windows_networking_connectivity_Release, -+ /* IInspectable methods */ -+ windows_networking_connectivity_GetIids, -+ windows_networking_connectivity_GetRuntimeClassName, -+ windows_networking_connectivity_GetTrustLevel, -+ /* IActivationFactory methods */ -+ windows_networking_connectivity_ActivateInstance, -+}; -+ -+static struct windows_networking_connectivity windows_networking_connectivity = -+{ -+ {&activation_factory_vtbl}, -+ 1 -+}; -+ - HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, LPVOID *object) - { - FIXME("clsid %s, riid %s, object %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), object); -@@ -30,6 +126,8 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, LPVOID *object) - - HRESULT WINAPI DllGetActivationFactory(HSTRING classid, IActivationFactory **factory) - { -- FIXME("classid %s, factory %p stub!\n", debugstr_hstring(classid), factory); -- return E_NOINTERFACE; --} -\ No newline at end of file -+ TRACE("classid %s, factory %p.\n", debugstr_hstring(classid), factory); -+ *factory = &windows_networking_connectivity.IActivationFactory_iface; -+ IUnknown_AddRef(*factory); -+ return S_OK; -+} --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0005-windows.networking.connectivity-Implement-INetworkIn.patch b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0005-windows.networking.connectivity-Implement-INetworkIn.patch deleted file mode 100644 index b7f03889a..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0005-windows.networking.connectivity-Implement-INetworkIn.patch +++ /dev/null @@ -1,301 +0,0 @@ -From bb14d124f11785e8abd8abdbc0a15854d88848ce Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Tue, 1 Jun 2021 11:10:25 +1000 -Subject: [PATCH 5/8] windows.networking.connectivity: Implement - INetworkInformationStatics stubs. - -v2: -Fixed QueryInterfaces - -Based off patch by Esdras Tarsis. ---- - .../windows.networking.connectivity_main.c | 242 ++++++++++++++++++ - 1 file changed, 242 insertions(+) - -diff --git a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -index 2463cc2c93c..b96e6c4f0a4 100644 ---- a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -+++ b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -@@ -10,6 +10,9 @@ - #include "initguid.h" - - #include "activation.h" -+#define WIDL_using_Windows_Networking_Connectivity -+#define WIDL_using_Windows_Foundation_Collections -+#include "windows.networking.connectivity.h" - - WINE_DEFAULT_DEBUG_CHANNEL(network); - -@@ -25,6 +28,8 @@ static const char *debugstr_hstring(HSTRING hstr) - struct windows_networking_connectivity - { - IActivationFactory IActivationFactory_iface; -+ INetworkInformationStatics INetworkInformationStatics_iface; -+ IVectorView_ConnectionProfile IVectorView_iface; - LONG refcount; - }; - -@@ -33,9 +38,237 @@ static inline struct windows_networking_connectivity *impl_from_IActivationFacto - return CONTAINING_RECORD(iface, struct windows_networking_connectivity, IActivationFactory_iface); - } - -+static inline struct windows_networking_connectivity *impl_from_INetworkInformationStatics(INetworkInformationStatics *iface) -+{ -+ return CONTAINING_RECORD(iface, struct windows_networking_connectivity, INetworkInformationStatics_iface); -+} -+ -+static inline struct windows_networking_connectivity *impl_from_IVectorView_ConnectionProfile(IVectorView_ConnectionProfile *iface) -+{ -+ return CONTAINING_RECORD(iface, struct windows_networking_connectivity, IVectorView_iface); -+} -+ -+static HRESULT STDMETHODCALLTYPE vector_view_QueryInterface(IVectorView_ConnectionProfile *iface, REFIID iid, void **object) -+{ -+ TRACE("iface %p, iid %s, object %p stub!\n", iface, debugstr_guid(iid), object); -+ IUnknown_AddRef(iface); -+ *object = iface; -+ return S_OK; -+} -+ -+static ULONG STDMETHODCALLTYPE vector_view_AddRef(IVectorView_ConnectionProfile *iface) -+{ -+ struct windows_networking_connectivity *impl = impl_from_IVectorView_ConnectionProfile(iface); -+ ULONG rc = InterlockedIncrement(&impl->refcount); -+ TRACE("%p increasing refcount to %u.\n", impl, rc); -+ return rc; -+} -+ -+static ULONG STDMETHODCALLTYPE vector_view_Release(IVectorView_ConnectionProfile *iface) -+{ -+ struct windows_networking_connectivity *impl = impl_from_IVectorView_ConnectionProfile(iface); -+ ULONG rc = InterlockedDecrement(&impl->refcount); -+ TRACE("%p decreasing refcount to %u.\n", impl, rc); -+ return rc; -+} -+ -+static HRESULT STDMETHODCALLTYPE vector_view_GetIids(IVectorView_ConnectionProfile *iface, ULONG *iid_count, IID **iids) -+{ -+ FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE vector_view_GetRuntimeClassName(IVectorView_ConnectionProfile *iface, HSTRING *class_name) -+{ -+ FIXME("iface %p, class_name %p stub!\n", iface, class_name); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE vector_view_GetTrustLevel(IVectorView_ConnectionProfile *iface, TrustLevel *trust_level) -+{ -+ FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE vector_view_GetAt(IVectorView_ConnectionProfile *iface, ULONG index, IConnectionProfile **out_value) -+{ -+ FIXME("iface %p, index %#x, out_value %p stub!\n", iface, index, out_value); -+ return S_OK; -+} -+ -+static HRESULT STDMETHODCALLTYPE vector_view_get_Size( -+ IVectorView_ConnectionProfile *iface, ULONG *out_value) -+{ -+ FIXME("iface %p, out_value %p stub!\n", iface, out_value); -+ *out_value = 0; -+ return S_OK; -+} -+ -+static HRESULT STDMETHODCALLTYPE vector_view_IndexOf( -+ IVectorView_ConnectionProfile *iface, IConnectionProfile *value, ULONG *index, BOOLEAN *out_value) -+{ -+ FIXME("iface %p, value %p, index %p, out_value %p stub!\n", iface, value, index, out_value); -+ *out_value = FALSE; -+ return S_OK; -+} -+ -+static HRESULT STDMETHODCALLTYPE vector_view_GetMany( -+ IVectorView_ConnectionProfile *iface, UINT32 start_index, UINT32 size, IConnectionProfile **items, UINT32 *out_value) -+{ -+ FIXME("iface %p, start_index %#x, items %p, out_value %p stub!\n", iface, start_index, items, out_value); -+ *out_value = 0; -+ return S_OK; -+} -+ -+static const struct IVectorView_ConnectionProfileVtbl vector_view_vtbl = -+{ -+ vector_view_QueryInterface, -+ vector_view_AddRef, -+ vector_view_Release, -+ vector_view_GetIids, -+ vector_view_GetRuntimeClassName, -+ vector_view_GetTrustLevel, -+ vector_view_GetAt, -+ vector_view_get_Size, -+ vector_view_IndexOf, -+ vector_view_GetMany -+}; -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_QueryInterface( -+ INetworkInformationStatics *iface, REFIID iid, void **object) -+{ -+ TRACE("iface %p, iid %s, object %p stub!\n", iface, debugstr_guid(iid), object); -+ -+ if (IsEqualGUID(iid, &IID_IUnknown) || -+ IsEqualGUID(iid, &IID_IInspectable) || -+ IsEqualGUID(iid, &IID_IAgileObject) || -+ IsEqualGUID(iid, &IID_INetworkInformationStatics)) -+ { -+ IUnknown_AddRef(iface); -+ *object = iface; -+ return S_OK; -+ } -+ -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); -+ *object = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG STDMETHODCALLTYPE network_information_statics_AddRef( -+ INetworkInformationStatics *iface) -+{ -+ struct windows_networking_connectivity *impl = impl_from_INetworkInformationStatics(iface); -+ ULONG rc = InterlockedIncrement(&impl->refcount); -+ TRACE("%p increasing refcount to %u.\n", impl, rc); -+ return rc; -+} -+ -+static ULONG STDMETHODCALLTYPE network_information_statics_Release( -+ INetworkInformationStatics *iface) -+{ -+ struct windows_networking_connectivity *impl = impl_from_INetworkInformationStatics(iface); -+ ULONG rc = InterlockedDecrement(&impl->refcount); -+ TRACE("%p decreasing refcount to %u.\n", impl, rc); -+ return rc; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetIids( -+ INetworkInformationStatics *iface, ULONG *iid_count, IID **iids) -+{ -+ FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetRuntimeClassName( -+ INetworkInformationStatics *iface, HSTRING *class_name) -+{ -+ FIXME("iface %p, class_name %p stub!\n", iface, class_name); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetTrustLevel( -+ INetworkInformationStatics *iface, TrustLevel *trust_level) -+{ -+ FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetConnectionProfiles(INetworkInformationStatics *iface, __FIVectorView_1_Windows__CNetworking__CConnectivity__CConnectionProfile **value) -+{ -+ struct windows_networking_connectivity *impl = impl_from_INetworkInformationStatics(iface); -+ FIXME("iface %p, %p stub!\n", iface, value); -+ *value = &impl->IVectorView_iface; -+ return S_OK; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetInternetConnectionProfile(INetworkInformationStatics *iface, IConnectionProfile **value) -+{ -+ FIXME("iface %p, %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetLanIdentifiers(INetworkInformationStatics *iface, __FIVectorView_1_Windows__CNetworking__CConnectivity__CLanIdentifier **value) -+{ -+ FIXME("iface %p, %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetHostNames(INetworkInformationStatics *iface, DWORD **value) -+{ -+ FIXME("iface %p, %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetProxyConfigurationAsync(INetworkInformationStatics *iface, char *name, DWORD **value) -+{ -+ FIXME("iface %p, %p, %p stub!\n", iface, name, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetSortedEndpointPairs(INetworkInformationStatics *iface, DWORD* destinationList, DWORD sortOptions, DWORD **value) -+{ -+ FIXME("iface %p, %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_eventadd_NetworkStatusChanged( -+ INetworkInformationStatics *iface, __x_ABI_CWindows_CNetworking_CConnectivity_CINetworkStatusChangedEventHandler *value, EventRegistrationToken* token) -+{ -+ FIXME("iface %p, value %p, token %p stub!\n", iface, value, token); -+ return S_OK; -+} -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_eventremove_NetworkStatusChanged( -+ INetworkInformationStatics *iface, EventRegistrationToken token) -+{ -+ FIXME("iface %p, token %#I64x stub!\n", iface, token.value); -+ return S_OK; -+} -+ -+static const struct INetworkInformationStaticsVtbl network_information_statics_vtbl = -+{ -+ network_information_statics_QueryInterface, -+ network_information_statics_AddRef, -+ network_information_statics_Release, -+ /* IInspectable methods */ -+ network_information_statics_GetIids, -+ network_information_statics_GetRuntimeClassName, -+ network_information_statics_GetTrustLevel, -+ /* INetworkInformationStatics methods */ -+ network_information_statics_GetConnectionProfiles, -+ network_information_statics_GetInternetConnectionProfile, -+ network_information_statics_GetLanIdentifiers, -+ network_information_statics_GetHostNames, -+ network_information_statics_GetProxyConfigurationAsync, -+ network_information_statics_GetSortedEndpointPairs, -+ network_information_statics_eventadd_NetworkStatusChanged, -+ network_information_statics_eventremove_NetworkStatusChanged, -+}; -+ - static HRESULT STDMETHODCALLTYPE windows_networking_connectivity_QueryInterface( - IActivationFactory *iface, REFIID iid, void **object) - { -+ struct windows_networking_connectivity *impl = impl_from_IActivationFactory(iface); - TRACE("iface %p, iid %s, object %p stub!\n", iface, debugstr_guid(iid), object); - - if (IsEqualGUID(iid, &IID_IUnknown) || -@@ -48,6 +281,13 @@ static HRESULT STDMETHODCALLTYPE windows_networking_connectivity_QueryInterface( - return S_OK; - } - -+ if (IsEqualGUID(iid, &IID_INetworkInformationStatics)) -+ { -+ IUnknown_AddRef(iface); -+ *object = &impl->INetworkInformationStatics_iface; -+ return S_OK; -+ } -+ - FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid)); - *object = NULL; - return E_NOINTERFACE; -@@ -115,6 +355,8 @@ static const struct IActivationFactoryVtbl activation_factory_vtbl = - static struct windows_networking_connectivity windows_networking_connectivity = - { - {&activation_factory_vtbl}, -+ {&network_information_statics_vtbl}, -+ {&vector_view_vtbl}, - 1 - }; - --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0006-windows.networking.connectivity-Registry-DLL.patch b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0006-windows.networking.connectivity-Registry-DLL.patch deleted file mode 100644 index 89236af3e..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0006-windows.networking.connectivity-Registry-DLL.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 911464a8aba1d14e5191daf47501e39f78b3c9a1 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Mon, 31 May 2021 09:45:56 +1000 -Subject: [PATCH 6/8] windows.networking.connectivity: Registry DLL - -This is a temp solution until the IDL can used for registration. ---- - .../Makefile.in | 3 +++ - .../network.rgs | 19 ++++++++++++++++++ - dlls/windows.networking.connectivity/rsrc.rc | 20 +++++++++++++++++++ - 3 files changed, 42 insertions(+) - create mode 100644 dlls/windows.networking.connectivity/network.rgs - create mode 100644 dlls/windows.networking.connectivity/rsrc.rc - -diff --git a/dlls/windows.networking.connectivity/Makefile.in b/dlls/windows.networking.connectivity/Makefile.in -index 6fc24a72feb..5785430da2c 100644 ---- a/dlls/windows.networking.connectivity/Makefile.in -+++ b/dlls/windows.networking.connectivity/Makefile.in -@@ -5,3 +5,6 @@ EXTRADLLFLAGS = -mno-cygwin - - C_SRCS = \ - windows.networking.connectivity_main.c -+ -+RC_SRCS = rsrc.rc -+ -diff --git a/dlls/windows.networking.connectivity/network.rgs b/dlls/windows.networking.connectivity/network.rgs -new file mode 100644 -index 00000000000..59d6f739a72 ---- /dev/null -+++ b/dlls/windows.networking.connectivity/network.rgs -@@ -0,0 +1,19 @@ -+HKLM -+{ -+ NoRemove Software -+ { -+ NoRemove Microsoft -+ { -+ NoRemove WindowsRuntime -+ { -+ NoRemove ActivatableClassId -+ { -+ ForceRemove Windows.Networking.Connectivity.NetworkInformation -+ { -+ val 'DllPath' = s '%MODULE%' -+ } -+ } -+ } -+ } -+ } -+} -diff --git a/dlls/windows.networking.connectivity/rsrc.rc b/dlls/windows.networking.connectivity/rsrc.rc -new file mode 100644 -index 00000000000..3ebeb3a7000 ---- /dev/null -+++ b/dlls/windows.networking.connectivity/rsrc.rc -@@ -0,0 +1,20 @@ -+/* -+ * Copyright 2021 Alistair Leslie-Hughes -+ * -+ * 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 -+ */ -+ -+/* @makedep: network.rgs */ -+1 WINE_REGISTRY network.rgs --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0007-windows.networking.connectivity-Implement-INetworkIn.patch b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0007-windows.networking.connectivity-Implement-INetworkIn.patch deleted file mode 100644 index c3454050d..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0007-windows.networking.connectivity-Implement-INetworkIn.patch +++ /dev/null @@ -1,198 +0,0 @@ -From ef41fa79b32aa3d211e1e8b64b9ace89f8fa5876 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Tue, 1 Jun 2021 13:13:57 +1000 -Subject: [PATCH 7/8] windows.networking.connectivity: Implement - INetworkInformationStatics GetInternetConnectionProfile - ---- - .../windows.networking.connectivity_main.c | 163 +++++++++++++++++- - 1 file changed, 161 insertions(+), 2 deletions(-) - -diff --git a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -index b96e6c4f0a4..ba1f5a5401d 100644 ---- a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -+++ b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -@@ -5,6 +5,7 @@ - #include "winbase.h" - #include "winstring.h" - #include "wine/debug.h" -+#include "wine/heap.h" - - #include "objbase.h" - #include "initguid.h" -@@ -201,12 +202,170 @@ static HRESULT STDMETHODCALLTYPE network_information_statics_GetConnectionProfil - return S_OK; - } - --static HRESULT STDMETHODCALLTYPE network_information_statics_GetInternetConnectionProfile(INetworkInformationStatics *iface, IConnectionProfile **value) -+struct connection_profile - { -- FIXME("iface %p, %p stub!\n", iface, value); -+ IConnectionProfile IConnectionProfile_iface; -+ LONG ref; -+}; -+ -+static inline struct connection_profile *impl_from_IConnectionProfile(IConnectionProfile *iface) -+{ -+ return CONTAINING_RECORD(iface, struct connection_profile, IConnectionProfile_iface); -+} -+ -+static HRESULT WINAPI connection_profile_QueryInterface(IConnectionProfile *iface, REFIID riid, void **object) -+{ -+ TRACE("iface %p, iid %s, object %p stub!\n", iface, debugstr_guid(riid), object); -+ -+ if (IsEqualGUID(riid, &IID_IUnknown) || -+ IsEqualGUID(riid, &IID_IInspectable) || -+ IsEqualGUID(riid, &IID_IConnectionProfile)) -+ { -+ IUnknown_AddRef(iface); -+ *object = iface; -+ return S_OK; -+ } -+ -+ WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); -+ *object = NULL; -+ return E_NOINTERFACE; -+} -+ -+static ULONG WINAPI connection_profile_AddRef(IConnectionProfile *iface) -+{ -+ struct connection_profile *impl = impl_from_IConnectionProfile(iface); -+ ULONG rc = InterlockedIncrement(&impl->ref); -+ TRACE("%p increasing refcount to %u.\n", impl, rc); -+ return rc; -+} -+ -+static ULONG WINAPI connection_profile_Release(IConnectionProfile *iface) -+{ -+ struct connection_profile *impl = impl_from_IConnectionProfile(iface); -+ ULONG rc = InterlockedIncrement(&impl->ref); -+ TRACE("%p increasing refcount to %u.\n", impl, rc); -+ return rc; -+} -+ -+static HRESULT WINAPI connection_profile_GetIids(IConnectionProfile *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 connection_profile_GetRuntimeClassName(IConnectionProfile *iface, HSTRING *class_name) -+{ -+ FIXME("iface %p, class_name %p stub!\n", iface, class_name); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_GetTrustLevel(IConnectionProfile *iface, TrustLevel *trust_level) -+{ -+ FIXME("iface %p, trust_level %p stub!\n", iface, trust_level); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_get_ProfileName(IConnectionProfile *iface, HSTRING *value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); - return E_NOTIMPL; - } - -+static HRESULT WINAPI connection_profile_GetNetworkConnectivityLevel(IConnectionProfile *iface, -+ enum __x_ABI_CWindows_CNetworking_CConnectivity_CNetworkConnectivityLevel *value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_GetNetworkNames(IConnectionProfile *iface, __FIVectorView_1_HSTRING **value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_GetConnectionCost(IConnectionProfile *iface, -+ __x_ABI_CWindows_CNetworking_CConnectivity_CIConnectionCost **value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_GetDataPlanStatus(IConnectionProfile *iface, -+ __x_ABI_CWindows_CNetworking_CConnectivity_CIDataPlanStatus **value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_get_NetworkAdapter(IConnectionProfile *iface, -+ __x_ABI_CWindows_CNetworking_CConnectivity_CINetworkAdapter **value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_GetLocalUsage(IConnectionProfile *iface, -+ struct __x_ABI_CWindows_CFoundation_CDateTime start, struct __x_ABI_CWindows_CFoundation_CDateTime end, -+ __x_ABI_CWindows_CNetworking_CConnectivity_CIDataUsage **value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_GetLocalUsagePerRoamingStates(IConnectionProfile *iface, -+ struct __x_ABI_CWindows_CFoundation_CDateTime start, struct __x_ABI_CWindows_CFoundation_CDateTime end, -+ enum __x_ABI_CWindows_CNetworking_CConnectivity_CRoamingStates states, -+ __x_ABI_CWindows_CNetworking_CConnectivity_CIDataUsage **value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI connection_profile_get_NetworkSecuritySettings(IConnectionProfile *iface, -+ __x_ABI_CWindows_CNetworking_CConnectivity_CINetworkSecuritySettings **value) -+{ -+ FIXME("iface %p, value %p stub!\n", iface, value); -+ return E_NOTIMPL; -+} -+ -+struct __x_ABI_CWindows_CNetworking_CConnectivity_CIConnectionProfileVtbl connection_vtbl = -+{ -+ connection_profile_QueryInterface, -+ connection_profile_AddRef, -+ connection_profile_Release, -+ connection_profile_GetIids, -+ connection_profile_GetRuntimeClassName, -+ connection_profile_GetTrustLevel, -+ connection_profile_get_ProfileName, -+ connection_profile_GetNetworkConnectivityLevel, -+ connection_profile_GetNetworkNames, -+ connection_profile_GetConnectionCost, -+ connection_profile_GetDataPlanStatus, -+ connection_profile_get_NetworkAdapter, -+ connection_profile_GetLocalUsage, -+ connection_profile_GetLocalUsagePerRoamingStates, -+ connection_profile_get_NetworkSecuritySettings -+}; -+ -+static HRESULT STDMETHODCALLTYPE network_information_statics_GetInternetConnectionProfile(INetworkInformationStatics *iface, IConnectionProfile **value) -+{ -+ struct windows_networking_connectivity *impl = impl_from_INetworkInformationStatics(iface); -+ struct connection_profile *profile; -+ -+ FIXME("iface %p, %p stub!\n", impl, value); -+ -+ profile = heap_alloc(sizeof(struct connection_profile)); -+ if (!profile) -+ return E_OUTOFMEMORY; -+ -+ profile->IConnectionProfile_iface.lpVtbl = &connection_vtbl; -+ profile->ref = 1; -+ -+ *value = &profile->IConnectionProfile_iface; -+ return S_OK; -+} -+ - static HRESULT STDMETHODCALLTYPE network_information_statics_GetLanIdentifiers(INetworkInformationStatics *iface, __FIVectorView_1_Windows__CNetworking__CConnectivity__CLanIdentifier **value) - { - FIXME("iface %p, %p stub!\n", iface, value); --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0008-windows.networking.connectivity-IConnectionProfile-G.patch b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0008-windows.networking.connectivity-IConnectionProfile-G.patch deleted file mode 100644 index a72b32cce..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/0008-windows.networking.connectivity-IConnectionProfile-G.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 308cffe2fdf351c360870cd96c04b3384a70bd7a Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Tue, 1 Jun 2021 13:24:16 +1000 -Subject: [PATCH 8/8] windows.networking.connectivity: IConnectionProfile - GetNetworkConnectivityLevel always return internet access - ---- - .../windows.networking.connectivity_main.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -index ba1f5a5401d..0e8f4e699f0 100644 ---- a/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -+++ b/dlls/windows.networking.connectivity/windows.networking.connectivity_main.c -@@ -274,8 +274,10 @@ static HRESULT WINAPI connection_profile_get_ProfileName(IConnectionProfile *ifa - static HRESULT WINAPI connection_profile_GetNetworkConnectivityLevel(IConnectionProfile *iface, - enum __x_ABI_CWindows_CNetworking_CConnectivity_CNetworkConnectivityLevel *value) - { -- FIXME("iface %p, value %p stub!\n", iface, value); -- return E_NOTIMPL; -+ struct connection_profile *impl = impl_from_IConnectionProfile(iface); -+ FIXME("iface %p, value %p stub!\n", impl, value); -+ *value = NetworkConnectivityLevel_InternetAccess; -+ return S_OK; - } - - static HRESULT WINAPI connection_profile_GetNetworkNames(IConnectionProfile *iface, __FIVectorView_1_HSTRING **value) --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/definition b/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/definition deleted file mode 100644 index c3764f192..000000000 --- a/patches/wine-hotfixes/staging-7.0/windows.networking.connectivity-new-dll/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [46534] Implement INetworkInformationStatics interface diff --git a/patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/0001-wineboot-Initialize-proxy-settings-registry-key.patch b/patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/0001-wineboot-Initialize-proxy-settings-registry-key.patch deleted file mode 100644 index cc057202e..000000000 --- a/patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/0001-wineboot-Initialize-proxy-settings-registry-key.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 584eecc73a8cba537b8f50932769729a29fe7d3d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Mon, 26 Dec 2016 16:37:40 +0100 -Subject: [PATCH] wineboot: Initialize proxy settings registry key. - ---- - programs/wineboot/Makefile.in | 2 +- - programs/wineboot/wineboot.c | 9 +++++++++ - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/programs/wineboot/Makefile.in b/programs/wineboot/Makefile.in -index 667f8f48702..4a1747ad047 100644 ---- a/programs/wineboot/Makefile.in -+++ b/programs/wineboot/Makefile.in -@@ -1,6 +1,6 @@ - MODULE = wineboot.exe - IMPORTS = uuid advapi32 ws2_32 kernelbase --DELAYIMPORTS = shell32 shlwapi version user32 setupapi newdev crypt32 -+DELAYIMPORTS = shell32 shlwapi version user32 setupapi newdev crypt32 wininet - - EXTRADLLFLAGS = -mconsole - -diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c -index 14943b005ef..9aab3b68e5b 100644 ---- a/programs/wineboot/wineboot.c -+++ b/programs/wineboot/wineboot.c -@@ -77,6 +77,7 @@ - #include - #include - #include -+#include - #include - #include "resource.h" - -@@ -1002,6 +1003,13 @@ static void create_volatile_environment_registry_key(void) - RegCloseKey( hkey ); - } - -+static void create_proxy_settings(void) -+{ -+ HINTERNET inet; -+ inet = InternetOpenA( "Wine", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 ); -+ if (inet) InternetCloseHandle( inet ); -+} -+ - /* Performs the rename operations dictated in %SystemRoot%\Wininit.ini. - * Returns FALSE if there was an error, or otherwise if all is ok. - */ -@@ -1812,6 +1820,7 @@ int __cdecl main( int argc, char *argv[] ) - if (init || update) update_wineprefix( update ); - - create_volatile_environment_registry_key(); -+ create_proxy_settings(); - - ProcessRunKeys( HKEY_LOCAL_MACHINE, L"RunOnce", TRUE, TRUE ); - --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/definition b/patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/definition deleted file mode 100644 index 9e38c54cb..000000000 --- a/patches/wine-hotfixes/staging-7.0/wineboot-ProxySettings/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [42024] Create ProxyEnable key on wineprefix update diff --git a/patches/wine-hotfixes/staging-7.0/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch b/patches/wine-hotfixes/staging-7.0/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch deleted file mode 100644 index 734db8878..000000000 --- a/patches/wine-hotfixes/staging-7.0/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 38af730d23f017ce256d3f2cc81e96402112ca7b Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 24 Sep 2014 21:13:59 +0200 -Subject: [PATCH] winemenubuilder: Create desktop shortcuts with absolute wine - path. - -When having multiple wine versions installed (for example regular wine and wine staging), the desktop -shortcuts will always run regular wine, even if the app was installed with wine staging. This patch -changes the behaviour to use the absolute wine path in desktop shortcuts. The patch only modifies the -behaviour on Linux, because some other distros are a bit special (FreeBSD requires a wrapper to start -wine, and so on ...). ---- - programs/winemenubuilder/Makefile.in | 1 + - programs/winemenubuilder/winemenubuilder.c | 12 ++++++++++-- - 2 files changed, 11 insertions(+), 2 deletions(-) - -diff --git a/programs/winemenubuilder/Makefile.in b/programs/winemenubuilder/Makefile.in -index 12326d1e4e2..07191b56d82 100644 ---- a/programs/winemenubuilder/Makefile.in -+++ b/programs/winemenubuilder/Makefile.in -@@ -1,5 +1,6 @@ - MODULE = winemenubuilder.exe - IMPORTS = uuid windowscodecs shell32 shlwapi ole32 user32 advapi32 -+EXTRADEFS = -DBINDIR="\"${bindir}\"" - - EXTRADLLFLAGS = -mwindows -municode - -diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c -index ab8798a88b5..31c97107802 100644 ---- a/programs/winemenubuilder/winemenubuilder.c -+++ b/programs/winemenubuilder/winemenubuilder.c -@@ -97,6 +97,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(menubuilder); - #define IS_OPTION_TRUE(ch) \ - ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') - -+/* On linux we create all menu item entries with an absolute path to wine, -+ * in order to allow using multiple wine versions at the same time. */ -+#ifdef __linux__ -+ static const char wine_path[] = BINDIR "/wine"; -+#else -+ static const char wine_path[] = "wine"; -+#endif -+ - /* link file formats */ - - #include "pshpack1.h" -@@ -1275,7 +1283,7 @@ static BOOL write_desktop_entry(const WCHAR *link, const WCHAR *location, const - fprintf(file, "env WINEPREFIX=\"%s\" ", path); - heap_free( path ); - } -- fprintf(file, "wine %s", escape(path)); -+ fprintf(file, "%s %s", wine_path, escape(path)); - if (args) fprintf(file, " %s", escape(args) ); - fputc( '\n', file ); - fprintf(file, "Type=Application\n"); -@@ -1985,7 +1993,7 @@ static BOOL write_freedesktop_association_entry(const WCHAR *desktopPath, const - if (prefix) - { - char *path = wine_get_unix_file_name( prefix ); -- fprintf(desktop, "Exec=env WINEPREFIX=\"%s\" wine start /ProgIDOpen %s %%f\n", path, escape(progId)); -+ fprintf(desktop, "Exec=env WINEPREFIX=\"%s\" %s start /ProgIDOpen %s %%f\n", path, wine_path, escape(progId)); - heap_free( path ); - } - else --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch b/patches/wine-hotfixes/staging-7.0/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch deleted file mode 100644 index 2c43aa01c..000000000 --- a/patches/wine-hotfixes/staging-7.0/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 5fe1a81fa6564f2d201bd3e225ac3bc4f41a2d2e Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Tue, 24 Jan 2017 12:37:46 +0100 -Subject: [PATCH] winex11: Fix alpha blending in X11DRV_UpdateLayeredWindow. - -Based on a patch by Dmitry Timoshkov. ---- - dlls/winex11.drv/window.c | 31 +++++++++++++++---------------- - 1 file changed, 15 insertions(+), 16 deletions(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 4dfb1bb6f76..8fb1a4a2786 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -434,14 +434,11 @@ static void sync_window_region( struct x11drv_win_data *data, HRGN win_region ) - - - /*********************************************************************** -- * sync_window_opacity -+ * set_window_opacity - */ --static void sync_window_opacity( Display *display, Window win, -- COLORREF key, BYTE alpha, DWORD flags ) -+static void set_window_opacity( Display *display, Window win, BYTE alpha ) - { -- unsigned long opacity = 0xffffffff; -- -- if (flags & LWA_ALPHA) opacity = (0xffffffff / 0xff) * alpha; -+ unsigned long opacity = (0xffffffff / 0xff) * alpha; - - if (opacity == 0xffffffff) - XDeleteProperty( display, win, x11drv_atom(_NET_WM_WINDOW_OPACITY) ); -@@ -1608,7 +1605,7 @@ static void create_whole_window( struct x11drv_win_data *data ) - - /* set the window opacity */ - if (!GetLayeredWindowAttributes( data->hwnd, &key, &alpha, &layered_flags )) layered_flags = 0; -- sync_window_opacity( data->display, data->whole_window, key, alpha, layered_flags ); -+ set_window_opacity( data->display, data->whole_window, (layered_flags & LWA_ALPHA) ? alpha : 0xff ); - - XFlush( data->display ); /* make sure the window exists before we start painting to it */ - -@@ -1740,7 +1737,7 @@ void CDECL X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) - { - data->layered = FALSE; - set_window_visual( data, &default_visual, FALSE ); -- sync_window_opacity( data->display, data->whole_window, 0, 0, 0 ); -+ set_window_opacity( data->display, data->whole_window, 0xff ); - if (data->surface) set_surface_color_key( data->surface, CLR_INVALID ); - } - done: -@@ -2668,7 +2665,7 @@ void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alph - set_window_visual( data, &default_visual, FALSE ); - - if (data->whole_window) -- sync_window_opacity( data->display, data->whole_window, key, alpha, flags ); -+ set_window_opacity( data->display, data->whole_window, (flags & LWA_ALPHA) ? alpha : 0xff ); - if (data->surface) - set_surface_color_key( data->surface, (flags & LWA_COLORKEY) ? key : CLR_INVALID ); - -@@ -2692,7 +2689,7 @@ void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alph - Window win = X11DRV_get_whole_window( hwnd ); - if (win) - { -- sync_window_opacity( gdi_display, win, key, alpha, flags ); -+ set_window_opacity( gdi_display, win, (flags & LWA_ALPHA) ? alpha : 0xff ); - if (flags & LWA_COLORKEY) - FIXME( "LWA_COLORKEY not supported on foreign process window %p\n", hwnd ); - } -@@ -2708,7 +2705,6 @@ BOOL CDECL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO - { - struct window_surface *surface; - struct x11drv_win_data *data; -- BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 }; - COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID; - char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; - BITMAPINFO *bmi = (BITMAPINFO *)buffer; -@@ -2736,6 +2732,10 @@ BOOL CDECL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO - } - else set_surface_color_key( surface, color_key ); - -+ if (data->whole_window) -+ set_window_opacity( data->display, data->whole_window, -+ (info->dwFlags & ULW_ALPHA) ? info->pblend->SourceConstantAlpha : 0xff ); -+ - if (surface) window_surface_add_ref( surface ); - mapped = data->mapped; - release_win_data( data ); -@@ -2769,16 +2769,15 @@ BOOL CDECL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO - { - IntersectRect( &rect, &rect, info->prcDirty ); - memcpy( src_bits, dst_bits, bmi->bmiHeader.biSizeImage ); -- PatBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS ); - } - src_rect = rect; - if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y ); - DPtoLP( info->hdcSrc, (POINT *)&src_rect, 2 ); - -- ret = GdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, -- info->hdcSrc, src_rect.left, src_rect.top, -- src_rect.right - src_rect.left, src_rect.bottom - src_rect.top, -- (info->dwFlags & ULW_ALPHA) ? *info->pblend : blend ); -+ ret = StretchBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, -+ info->hdcSrc, src_rect.left, src_rect.top, -+ src_rect.right - src_rect.left, src_rect.bottom - src_rect.top, -+ SRCCOPY ); - if (ret) - { - memcpy( dst_bits, src_bits, bmi->bmiHeader.biSizeImage ); --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging-7.0/winex11-UpdateLayeredWindow/definition b/patches/wine-hotfixes/staging-7.0/winex11-UpdateLayeredWindow/definition deleted file mode 100644 index fc7874a5c..000000000 --- a/patches/wine-hotfixes/staging-7.0/winex11-UpdateLayeredWindow/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [33943] Fix alpha blending in X11DRV_UpdateLayeredWindow diff --git a/patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/0001-winex11-Specify-a-default-vulkan-driver-if-one-not-f.patch b/patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/0001-winex11-Specify-a-default-vulkan-driver-if-one-not-f.patch deleted file mode 100644 index 0a0be2389..000000000 --- a/patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/0001-winex11-Specify-a-default-vulkan-driver-if-one-not-f.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 3561f512f400ca1d049ac5ce26b9cbb6aac1dc31 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Fri, 1 Jun 2018 14:03:26 +1000 -Subject: [PATCH] winex11: Specify a default vulkan driver if one not found at - build time - -We cannot specify it as a dependency since Debian Jessie has the -vulkan library in backports and not everybody will have this mapped. ---- - dlls/winex11.drv/vulkan.c | 35 ++++++++++++++--------------------- - 1 file changed, 14 insertions(+), 21 deletions(-) - -diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c -index 4f6624b3db8..6e343f47f34 100644 ---- a/dlls/winex11.drv/vulkan.c -+++ b/dlls/winex11.drv/vulkan.c -@@ -40,10 +40,12 @@ - #include "wine/vulkan_driver.h" - - WINE_DEFAULT_DEBUG_CHANNEL(vulkan); -- --#ifdef SONAME_LIBVULKAN - WINE_DECLARE_DEBUG_CHANNEL(fps); - -+#ifndef SONAME_LIBVULKAN -+#define SONAME_LIBVULKAN "" -+#endif -+ - static CRITICAL_SECTION context_section; - static CRITICAL_SECTION_DEBUG critsect_debug = - { -@@ -111,9 +113,17 @@ static void *vulkan_handle; - - static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context) - { -- if (!(vulkan_handle = dlopen(SONAME_LIBVULKAN, RTLD_NOW))) -+ const char *libvulkan_candidates[] = {SONAME_LIBVULKAN, -+ "libvulkan.so.1", -+ "libvulkan.so", -+ NULL}; -+ int i; -+ for (i=0; libvulkan_candidates[i] && !vulkan_handle; i++) -+ vulkan_handle = dlopen(libvulkan_candidates[i], RTLD_NOW); -+ -+ if (!vulkan_handle) - { -- ERR("Failed to load %s.\n", SONAME_LIBVULKAN); -+ ERR("Failed to load vulkan library\n"); - return TRUE; - } - -@@ -1068,28 +1068,3 @@ const struct vulkan_funcs *get_vulkan_driver(UINT version) - return NULL; - } - --#else /* No vulkan */ -- --const struct vulkan_funcs *get_vulkan_driver(UINT version) --{ -- ERR("Wine was built without Vulkan support.\n"); -- return NULL; --} -- --void destroy_vk_surface(HWND hwnd) --{ --} -- --void resize_vk_surfaces(HWND hwnd, Window active, int mask, XWindowChanges changes) --{ --} -- --void sync_vk_surface(HWND hwnd, BOOL known_child) --{ --} -- --void vulkan_thread_detach(void) --{ --} -- --#endif /* SONAME_LIBVULKAN */ - --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/definition b/patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/definition deleted file mode 100644 index e99592c9b..000000000 --- a/patches/wine-hotfixes/staging-7.0/winex11-Vulkan_support/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [44775] Allow vulkan support to be detected at runtime. diff --git a/patches/wine-hotfixes/staging-7.0/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch b/patches/wine-hotfixes/staging-7.0/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch deleted file mode 100644 index 56b6d956a..000000000 --- a/patches/wine-hotfixes/staging-7.0/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch +++ /dev/null @@ -1,56 +0,0 @@ -From b628604e599f96eda85be0f8677419f8f591a7c6 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Fri, 22 Nov 2013 18:54:18 +0100 -Subject: winex11: Enable/disable windows when they are (un)mapped by foreign - applications - ---- - dlls/winex11.drv/event.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index f79f40c23..04a4c3c94 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -1137,6 +1138,7 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev ) - static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) - { - struct x11drv_win_data *data; -+ BOOL is_embedded; - - x11drv_input_add_window( hwnd, event->xany.window ); - -@@ -994,7 +995,12 @@ static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) - if (hwndFocus && IsChild( hwnd, hwndFocus )) - set_input_focus( data ); - } -+ -+ is_embedded = data->embedded; - release_win_data( data ); -+ -+ if (is_embedded) -+ EnableWindow( hwnd, TRUE ); - return TRUE; - } - -@@ -1004,6 +1010,17 @@ static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) - */ - static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event ) - { -+ struct x11drv_win_data *data; -+ BOOL is_embedded; -+ -+ if (!(data = get_win_data( hwnd ))) return FALSE; -+ -+ is_embedded = data->embedded; -+ release_win_data( data ); -+ -+ if (is_embedded) -+ EnableWindow( hwnd, FALSE ); -+ - x11drv_input_remove_window( event->xany.window ); - return TRUE; - } --- -2.22.0 - diff --git a/patches/wine-hotfixes/staging-7.0/winex11-XEMBED/definition b/patches/wine-hotfixes/staging-7.0/winex11-XEMBED/definition deleted file mode 100644 index 2fe89b51c..000000000 --- a/patches/wine-hotfixes/staging-7.0/winex11-XEMBED/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: XEMBED support for embedding Wine windows inside Linux applications diff --git a/patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch b/patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch deleted file mode 100644 index 420e23bce..000000000 --- a/patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 4d2c03539d7316d75b56fd8a2c852a9013234f0c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Sun, 28 Sep 2014 21:20:52 +0200 -Subject: winex11.drv: Only warn about used contexts in wglShareLists. - ---- - dlls/opengl32/tests/opengl.c | 2 +- - dlls/winex11.drv/opengl.c | 10 ++++------ - 2 files changed, 5 insertions(+), 7 deletions(-) - -diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c -index e5e1507..5454d3a 100644 ---- a/dlls/opengl32/tests/opengl.c -+++ b/dlls/opengl32/tests/opengl.c -@@ -365,7 +365,7 @@ static void test_sharelists(HDC winhdc) - res = wglMakeCurrent(winhdc, hglrc2); - ok(res, "Make current failed\n"); - res = wglShareLists(hglrc1, hglrc2); -- todo_wine ok(res, "Sharing display lists with a destination context which has been made current failed\n"); -+ ok(res, "Sharing display lists with a destination context which has been made current failed\n"); - wglMakeCurrent(0, 0); - wglDeleteContext(hglrc2); - } -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 0f7534e..39929f2 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -1959,18 +1959,16 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de - - if (share_all_contexts == 1) return TRUE; - -- if((org->has_been_current && dest->has_been_current) || dest->has_been_current) -- { -- ERR("Could not share display lists, one of the contexts has been current already !\n"); -- return FALSE; -- } -- else if(dest->sharing) -+ if(dest->sharing) - { - ERR("Could not share display lists because hglrc2 has already shared lists before\n"); - return FALSE; - } - else - { -+ if(dest->has_been_current) -+ ERR("Recreating OpenGL context to share display lists, although the context has been current!\n"); -+ - /* Re-create the GLX context and share display lists */ - pglXDestroyContext(gdi_display, dest->ctx); - dest->ctx = create_glxcontext(gdi_display, dest, org->ctx); --- -2.8.0 - diff --git a/patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/definition b/patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/definition deleted file mode 100644 index a74ef1868..000000000 --- a/patches/wine-hotfixes/staging-7.0/winex11-wglShareLists/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [11436] Do not fail when a used context is passed to wglShareLists -Fixes: [25419] Fix broken textures in XIII Century: Death or Glory diff --git a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0001-wininet-tests-Add-more-tests-for-cookies.patch b/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0001-wininet-tests-Add-more-tests-for-cookies.patch deleted file mode 100644 index c86a9804f..000000000 --- a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0001-wininet-tests-Add-more-tests-for-cookies.patch +++ /dev/null @@ -1,145 +0,0 @@ -From 915a805cabaec3cc265f4f8ad9f0005502f8fd24 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Fri, 15 May 2015 20:37:19 +0200 -Subject: [PATCH] wininet/tests: Add more tests for cookies. - ---- - dlls/wininet/tests/http.c | 92 +++++++++++++++++++++++++++++++++++++-- - 1 file changed, 89 insertions(+), 3 deletions(-) - -diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c -index 90a38dc3a..55d51b299 100644 ---- a/dlls/wininet/tests/http.c -+++ b/dlls/wininet/tests/http.c -@@ -2068,6 +2068,14 @@ static const char largemsg[] = - "Content-Length: %I64u\r\n" - "\r\n"; - -+static const char okmsg_cookie_path[] = -+"HTTP/1.1 200 OK\r\n" -+"Date: Mon, 01 Dec 2008 13:44:34 GMT\r\n" -+"Server: winetest\r\n" -+"Content-Length: 0\r\n" -+"Set-Cookie: subcookie2=data; path=/test_cookie_set_path\r\n" -+"\r\n"; -+ - static const char notokmsg[] = - "HTTP/1.1 400 Bad Request\r\n" - "Server: winetest\r\n" -@@ -2438,6 +2446,32 @@ static DWORD CALLBACK server_thread(LPVOID param) - else - send(c, noauthmsg, sizeof noauthmsg-1, 0); - } -+ if (strstr(buffer, "/test_cookie_path1")) -+ { -+ if (strstr(buffer, "subcookie=data")) -+ send(c, okmsg, sizeof okmsg-1, 0); -+ else -+ send(c, notokmsg, sizeof notokmsg-1, 0); -+ } -+ if (strstr(buffer, "/test_cookie_path2")) -+ { -+ if (strstr(buffer, "subcookie2=data")) -+ send(c, okmsg, sizeof okmsg-1, 0); -+ else -+ send(c, notokmsg, sizeof notokmsg-1, 0); -+ } -+ if (strstr(buffer, "/test_cookie_set_path")) -+ { -+ send(c, okmsg_cookie_path, sizeof okmsg_cookie_path-1, 0); -+ } -+ if (strstr(buffer, "/test_cookie_merge")) -+ { -+ if (strstr(buffer, "subcookie=data") && -+ !strstr(buffer, "manual_cookie=test")) -+ send(c, okmsg, sizeof okmsg-1, 0); -+ else -+ send(c, notokmsg, sizeof notokmsg-1, 0); -+ } - if (strstr(buffer, "/test_host_override")) - { - if (strstr(buffer, host_header_override)) -@@ -3816,7 +3850,7 @@ static void test_cookie_header(int port) - HINTERNET ses, con, req; - DWORD size, error; - BOOL ret; -- char buffer[64]; -+ char buffer[256]; - - ses = InternetOpenA("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); - ok(ses != NULL, "InternetOpen failed\n"); -@@ -3878,7 +3912,7 @@ static void test_cookie_header(int port) - size = sizeof(buffer); - ret = HttpQueryInfoA(req, HTTP_QUERY_COOKIE | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); - ok(ret, "HttpQueryInfo failed: %lu\n", GetLastError()); -- ok(!strcmp(buffer, "cookie=not biscuit"), "got '%s' expected \'cookie=not biscuit\'\n", buffer); -+ ok(!!strstr(buffer, "cookie=not biscuit"), "got '%s' expected \'cookie=not biscuit\'\n", buffer); - - ret = HttpSendRequestA(req, NULL, 0, NULL, 0); - ok(ret, "HttpSendRequest failed: %lu\n", GetLastError()); -@@ -3855,9 +3889,61 @@ static void test_cookie_header(int port) - size = sizeof(buffer); - ret = HttpQueryInfoA(req, HTTP_QUERY_COOKIE | HTTP_QUERY_FLAG_REQUEST_HEADERS, buffer, &size, NULL); - ok(ret, "HttpQueryInfo failed: %lu\n", GetLastError()); -- ok(!strcmp(buffer, "cookie=biscuit"), "got '%s' expected \'cookie=biscuit\'\n", buffer); -+ ok(!strstr(buffer, "cookie=not biscuit"), "'%s' should not contain \'cookie=not biscuit\'\n", buffer); -+ ok(!!strstr(buffer, "cookie=biscuit"), "'%s' should contain \'cookie=biscuit\'\n", buffer); -+ -+ InternetCloseHandle(req); -+ -+ InternetSetCookieA("http://localhost/testCCCC", "subcookie", "data"); -+ -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_path1", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 200); -+ InternetCloseHandle(req); -+ -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_path1/abc", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 200); -+ InternetCloseHandle(req); -+ -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_set_path", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 200); -+ InternetCloseHandle(req); -+ -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_path2", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); - -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 400); - InternetCloseHandle(req); -+ -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_merge", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpAddRequestHeadersA(req, "Cookie: manual_cookie=test\r\n", ~0u, HTTP_ADDREQ_FLAG_ADD); -+ ok(ret, "HttpAddRequestHeaders failed: %u\n", GetLastError()); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 200); -+ InternetCloseHandle(req); -+ - InternetCloseHandle(con); - InternetCloseHandle(ses); - } --- -2.23.0 - diff --git a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0002-wininet-tests-Test-auth-credential-reusage-with-host.patch b/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0002-wininet-tests-Test-auth-credential-reusage-with-host.patch deleted file mode 100644 index 5348f2bac..000000000 --- a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0002-wininet-tests-Test-auth-credential-reusage-with-host.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 303a7d54eca11f350f200bf3747646349a84536f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Fri, 15 May 2015 21:18:37 +0200 -Subject: [PATCH] wininet/tests: Test auth credential reusage with host - override. - ---- - dlls/wininet/tests/http.c | 93 +++++++++++++++++++++++++++++++++++++++ - 1 file changed, 93 insertions(+) - -diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c -index b06bd6c04d1..59689baf87e 100644 ---- a/dlls/wininet/tests/http.c -+++ b/dlls/wininet/tests/http.c -@@ -2496,12 +2496,27 @@ static DWORD CALLBACK server_thread(LPVOID param) - { - send(c, okmsg, sizeof(okmsg)-1, 0); - } -+ - if (strstr(buffer, "HEAD /test_large_content")) - { - char msg[sizeof(largemsg) + 16]; - sprintf(msg, largemsg, content_length); - send(c, msg, strlen(msg), 0); - } -+ if (strstr(buffer, "HEAD /test_auth_host1")) -+ { -+ if (strstr(buffer, "Authorization: Basic dGVzdDE6cGFzcw==")) -+ send(c, okmsg, sizeof okmsg-1, 0); -+ else -+ send(c, noauthmsg, sizeof noauthmsg-1, 0); -+ } -+ if (strstr(buffer, "HEAD /test_auth_host2")) -+ { -+ if (strstr(buffer, "Authorization: Basic dGVzdDE6cGFzczI=")) -+ send(c, okmsg, sizeof okmsg-1, 0); -+ else -+ send(c, noauthmsg, sizeof noauthmsg-1, 0); -+ } - shutdown(c, 2); - closesocket(c); - c = -1; -@@ -3200,6 +3215,84 @@ static void test_header_override(int port) - InternetCloseHandle(req); - InternetCloseHandle(con); - InternetCloseHandle(ses); -+ -+ ses = InternetOpenA("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); -+ ok(ses != NULL, "InternetOpenA failed\n"); -+ -+ con = InternetConnectA(ses, "localhost", port, "test1", "pass", INTERNET_SERVICE_HTTP, 0, 0); -+ ok(con != NULL, "InternetConnectA failed %u\n", GetLastError()); -+ -+ req = HttpOpenRequestA( con, "HEAD", "/test_auth_host1", NULL, NULL, NULL, 0, 0); -+ ok(req != NULL, "HttpOpenRequestA failed %u\n", GetLastError()); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequestA failed %u\n", GetLastError()); -+ -+ test_status_code(req, 200); -+ -+ InternetCloseHandle(req); -+ InternetCloseHandle(con); -+ InternetCloseHandle(ses); -+ -+ ses = InternetOpenA("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); -+ ok(ses != NULL, "InternetOpenA failed\n"); -+ -+ con = InternetConnectA( ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); -+ ok(con != NULL, "InternetConnectA failed %u\n", GetLastError()); -+ -+ req = HttpOpenRequestA(con, "HEAD", "/test_auth_host1", NULL, NULL, NULL, 0, 0); -+ ok(req != NULL, "HttpOpenRequestA failed %u\n", GetLastError()); -+ -+ ret = HttpAddRequestHeadersA(req, host_header_override, ~0u, HTTP_ADDREQ_FLAG_ADD); -+ ok(ret, "HttpAddRequestHeaders failed\n"); -+ -+ ret = HttpSendRequestA( req, NULL, 0, NULL, 0 ); -+ ok( ret, "HttpSendRequestA failed %u\n", GetLastError() ); -+ -+ test_status_code(req, 200); -+ -+ InternetCloseHandle(req); -+ InternetCloseHandle(con); -+ InternetCloseHandle(ses); -+ -+ ses = InternetOpenA("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); -+ ok(ses != NULL, "InternetOpenA failed\n"); -+ -+ con = InternetConnectA(ses, "localhost", port, "test1", "pass2", INTERNET_SERVICE_HTTP, 0, 0); -+ ok(con != NULL, "InternetConnectA failed %u\n", GetLastError()); -+ -+ req = HttpOpenRequestA(con, "HEAD", "/test_auth_host2", NULL, NULL, NULL, 0, 0); -+ ok(req != NULL, "HttpOpenRequestA failed %u\n", GetLastError()); -+ -+ ret = HttpAddRequestHeadersA(req, host_header_override, ~0u, HTTP_ADDREQ_FLAG_ADD); -+ ok(ret, "HttpAddRequestHeaders failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequestA failed %u\n", GetLastError()); -+ -+ test_status_code(req, 200); -+ -+ InternetCloseHandle(req); -+ InternetCloseHandle(con); -+ InternetCloseHandle(ses); -+ -+ ses = InternetOpenA("winetest", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); -+ ok(ses != NULL, "InternetOpenA failed\n"); -+ -+ con = InternetConnectA(ses, "localhost", port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); -+ ok(con != NULL, "InternetConnectA failed %u\n", GetLastError()); -+ -+ req = HttpOpenRequestA(con, "HEAD", "/test_auth_host2", NULL, NULL, NULL, 0, 0); -+ ok(req != NULL, "HttpOpenRequestA failed %u\n", GetLastError()); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequestA failed %u\n", GetLastError()); -+ -+ test_status_code(req, 200); -+ -+ InternetCloseHandle(req); -+ InternetCloseHandle(con); -+ InternetCloseHandle(ses); - } - - static void test_connection_closing(int port) --- -2.17.1 - diff --git a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0003-wininet-tests-Check-cookie-behaviour-when-overriding.patch b/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0003-wininet-tests-Check-cookie-behaviour-when-overriding.patch deleted file mode 100644 index 68ae32270..000000000 --- a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0003-wininet-tests-Check-cookie-behaviour-when-overriding.patch +++ /dev/null @@ -1,132 +0,0 @@ -From 21ca3efb2a8a1f505f9e3f3ed2126a766d4a127f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Fri, 15 May 2015 23:09:20 +0200 -Subject: wininet/tests: Check cookie behaviour when overriding host. - ---- - dlls/wininet/tests/http.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 95 insertions(+) - -diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c -index 546e473..0121aa5 100644 ---- a/dlls/wininet/tests/http.c -+++ b/dlls/wininet/tests/http.c -@@ -2000,6 +2000,14 @@ static const char okmsg_cookie_path[] = - "Set-Cookie: subcookie2=data; path=/test_cookie_set_path\r\n" - "\r\n"; - -+static const char okmsg_cookie[] = -+"HTTP/1.1 200 OK\r\n" -+"Date: Mon, 01 Dec 2008 13:44:34 GMT\r\n" -+"Server: winetest\r\n" -+"Content-Length: 0\r\n" -+"Set-Cookie: testcookie=testvalue\r\n" -+"\r\n"; -+ - static const char notokmsg[] = - "HTTP/1.1 400 Bad Request\r\n" - "Server: winetest\r\n" -@@ -2391,6 +2399,25 @@ static DWORD CALLBACK server_thread(LPVOID param) - else - send(c, notokmsg, sizeof notokmsg-1, 0); - } -+ if (strstr(buffer, "/test_cookie_set_host_override")) -+ { -+ send(c, okmsg_cookie, sizeof okmsg_cookie-1, 0); -+ } -+ if (strstr(buffer, "/test_cookie_check_host_override")) -+ { -+ if (strstr(buffer, "Cookie:") && strstr(buffer, "testcookie=testvalue")) -+ send(c, okmsg, sizeof okmsg-1, 0); -+ else -+ send(c, notokmsg, sizeof notokmsg-1, 0); -+ } -+ if (strstr(buffer, "/test_cookie_check_different_host")) -+ { -+ if (!strstr(buffer, "foo") && -+ strstr(buffer, "cookie=biscuit")) -+ send(c, okmsg, sizeof okmsg-1, 0); -+ else -+ send(c, notokmsg, sizeof notokmsg-1, 0); -+ } - if (strstr(buffer, "/test_host_override")) - { - if (strstr(buffer, host_header_override)) -@@ -3130,6 +3157,74 @@ static void test_header_override(int port) - } - - InternetCloseHandle(req); -+ InternetSetCookieA("http://localhost", "cookie", "biscuit"); -+ req = HttpOpenRequestA(con, NULL, "/testC", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpAddRequestHeadersA(req, host_header_override, ~0u, HTTP_ADDREQ_FLAG_ADD); -+ ok(ret, "HttpAddRequestHeaders failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 200); -+ -+ InternetCloseHandle(req); -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_set_host_override", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpAddRequestHeadersA(req, host_header_override, ~0u, HTTP_ADDREQ_FLAG_ADD); -+ ok(ret, "HttpAddRequestHeaders failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 200); -+ -+ InternetCloseHandle(req); -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_check_host_override", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpAddRequestHeadersA(req, host_header_override, ~0u, HTTP_ADDREQ_FLAG_ADD); -+ ok(ret, "HttpAddRequestHeaders failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code_todo(req, 200); -+ -+ InternetCloseHandle(req); -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_check_host_override", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code_todo(req, 200); -+ -+ InternetCloseHandle(req); -+ InternetSetCookieA("http://test.local", "foo", "bar"); -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_check_different_host", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 200); -+ -+ InternetCloseHandle(req); -+ req = HttpOpenRequestA(con, NULL, "/test_cookie_check_different_host", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -+ ok(req != NULL, "HttpOpenRequest failed\n"); -+ -+ ret = HttpAddRequestHeadersA(req, host_header_override, ~0u, HTTP_ADDREQ_FLAG_ADD); -+ ok(ret, "HttpAddRequestHeaders failed\n"); -+ -+ ret = HttpSendRequestA(req, NULL, 0, NULL, 0); -+ ok(ret, "HttpSendRequest failed\n"); -+ -+ test_status_code(req, 200); -+ -+ InternetCloseHandle(req); - InternetCloseHandle(con); - InternetCloseHandle(ses); - --- -2.8.0 - diff --git a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0004-wininet-Strip-filename-if-no-path-is-set-in-cookie.patch b/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0004-wininet-Strip-filename-if-no-path-is-set-in-cookie.patch deleted file mode 100644 index 6b81fdcda..000000000 --- a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0004-wininet-Strip-filename-if-no-path-is-set-in-cookie.patch +++ /dev/null @@ -1,82 +0,0 @@ -From 20e7de7c8f73fb27f7eeffbc5de646fc27fe1bb7 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Sat, 16 May 2015 00:24:35 +0200 -Subject: [PATCH] wininet: Strip filename if no path is set in cookie. - -The order of the stored cookies doesn't match in /testC, so -be a bit less strict in the test. ---- - dlls/wininet/http.c | 11 ++++++++++- - dlls/wininet/tests/http.c | 6 +++--- - 2 files changed, 13 insertions(+), 4 deletions(-) - -diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c -index c770c312ba9..d95b39bd9ce 100644 ---- a/dlls/wininet/http.c -+++ b/dlls/wininet/http.c -@@ -654,10 +654,18 @@ static void HTTP_ProcessCookies( http_request_t *request ) - int HeaderIndex; - int numCookies = 0; - LPHTTPHEADERW setCookieHeader; -+ WCHAR *path, *tmp; - - if(request->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) - return; - -+ path = heap_strdupW(request->path); -+ if (!path) -+ return; -+ -+ tmp = wcsrchr(path, '/'); -+ if (tmp && tmp[1]) tmp[1] = 0; -+ - EnterCriticalSection( &request->headers_section ); - - while((HeaderIndex = HTTP_GetCustomHeaderIndex(request, L"Set-Cookie", numCookies++, FALSE)) != -1) -@@ -676,10 +684,11 @@ static void HTTP_ProcessCookies( http_request_t *request ) - - name = substr(setCookieHeader->lpszValue, data - setCookieHeader->lpszValue); - data++; -- set_cookie(substrz(request->server->name), substrz(request->path), name, substrz(data), INTERNET_COOKIE_HTTPONLY); -+ set_cookie(substrz(request->server->name), substrz(path), name, substrz(data), INTERNET_COOKIE_HTTPONLY); - } - - LeaveCriticalSection( &request->headers_section ); -+ heap_free(path); - } - - static void strip_spaces(LPWSTR start) -diff --git a/dlls/wininet/tests/http.c b/dlls/wininet/tests/http.c -index 510c3ac5232..b98e648c276 100644 ---- a/dlls/wininet/tests/http.c -+++ b/dlls/wininet/tests/http.c -@@ -2363,7 +2363,7 @@ static DWORD CALLBACK server_thread(LPVOID param) - } - if (strstr(buffer, "/testC")) - { -- if (strstr(buffer, "Cookie: cookie=biscuit")) -+ if (strstr(buffer, "cookie=biscuit")) - send(c, okmsg, sizeof okmsg-1, 0); - else - send(c, notokmsg, sizeof notokmsg-1, 0); -@@ -3351,7 +3351,7 @@ static void test_header_override(int port) - ret = HttpSendRequestA(req, NULL, 0, NULL, 0); - ok(ret, "HttpSendRequest failed\n"); - -- test_status_code_todo(req, 200); -+ test_status_code(req, 200); - - InternetCloseHandle(req); - req = HttpOpenRequestA(con, NULL, "/test_cookie_check_host_override", NULL, NULL, NULL, INTERNET_FLAG_KEEP_CONNECTION, 0); -@@ -3360,7 +3360,7 @@ static void test_header_override(int port) - ret = HttpSendRequestA(req, NULL, 0, NULL, 0); - ok(ret, "HttpSendRequest failed\n"); - -- test_status_code_todo(req, 200); -+ test_status_code(req, 200); - - InternetCloseHandle(req); - InternetSetCookieA("http://test.local", "foo", "bar"); --- -2.29.2 - diff --git a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0005-wininet-Replacing-header-fields-should-fail-if-they-.patch b/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0005-wininet-Replacing-header-fields-should-fail-if-they-.patch deleted file mode 100644 index 28ef49a1d..000000000 --- a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/0005-wininet-Replacing-header-fields-should-fail-if-they-.patch +++ /dev/null @@ -1,241 +0,0 @@ -From e8ad0fb2501a0ebd489534dbf7f89af209f972bc Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Sat, 16 May 2015 03:16:15 +0200 -Subject: [PATCH] wininet: Replacing header fields should fail if they do not - exist yet. - -A lot of details are not properly covered by tests yet and were -marked with FIXME comments. The implementation was written in such -a way that it behaves identical to the old code in such situations. ---- - dlls/wininet/http.c | 185 ++++++++++++++++++++++---------------------- - 1 file changed, 93 insertions(+), 92 deletions(-) - -diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c -index ec984441399..98f63a8c0a4 100644 ---- a/dlls/wininet/http.c -+++ b/dlls/wininet/http.c -@@ -6120,127 +6120,128 @@ static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer) - - static DWORD HTTP_ProcessHeader(http_request_t *request, LPCWSTR field, LPCWSTR value, DWORD dwModifier) - { -- LPHTTPHEADERW lphttpHdr = NULL; -+ LPHTTPHEADERW lphttpHdr; - INT index; - BOOL request_only = !!(dwModifier & HTTP_ADDHDR_FLAG_REQ); -- DWORD res = ERROR_HTTP_INVALID_HEADER; -+ DWORD res = ERROR_SUCCESS; - - TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier); - - EnterCriticalSection( &request->headers_section ); - -- /* REPLACE wins out over ADD */ -- if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE) -- dwModifier &= ~HTTP_ADDHDR_FLAG_ADD; -- -- if (dwModifier & HTTP_ADDHDR_FLAG_ADD) -- index = -1; -- else -- index = HTTP_GetCustomHeaderIndex(request, field, 0, request_only); -- -+ index = HTTP_GetCustomHeaderIndex(request, field, 0, request_only); - if (index >= 0) - { -- if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW) -- { -- LeaveCriticalSection( &request->headers_section ); -- return ERROR_HTTP_INVALID_HEADER; -- } - lphttpHdr = &request->custHeaders[index]; -- } -- else if (value) -- { -- HTTPHEADERW hdr; - -- hdr.lpszField = (LPWSTR)field; -- hdr.lpszValue = (LPWSTR)value; -- hdr.wFlags = hdr.wCount = 0; -+ /* replace existing header if FLAG_REPLACE is given */ -+ if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE) -+ { -+ HTTP_DeleteCustomHeader( request, index ); - -- if (dwModifier & HTTP_ADDHDR_FLAG_REQ) -- hdr.wFlags |= HDR_ISREQUEST; -+ if (value && value[0]) -+ { -+ HTTPHEADERW hdr; - -- res = HTTP_InsertCustomHeader(request, &hdr); -- LeaveCriticalSection( &request->headers_section ); -- return res; -- } -- /* no value to delete */ -- else -- { -- LeaveCriticalSection( &request->headers_section ); -- return ERROR_SUCCESS; -- } -+ hdr.lpszField = (LPWSTR)field; -+ hdr.lpszValue = (LPWSTR)value; -+ hdr.wFlags = hdr.wCount = 0; - -- if (dwModifier & HTTP_ADDHDR_FLAG_REQ) -- lphttpHdr->wFlags |= HDR_ISREQUEST; -- else -- lphttpHdr->wFlags &= ~HDR_ISREQUEST; -+ if (dwModifier & HTTP_ADDHDR_FLAG_REQ) -+ hdr.wFlags |= HDR_ISREQUEST; - -- if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE) -- { -- HTTP_DeleteCustomHeader( request, index ); -+ res = HTTP_InsertCustomHeader( request, &hdr ); -+ } -+ -+ goto out; -+ } - -- if (value && value[0]) -+ /* do not add new header if FLAG_ADD_IF_NEW is set */ -+ if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW) - { -- HTTPHEADERW hdr; -+ res = ERROR_HTTP_INVALID_HEADER; /* FIXME */ -+ goto out; -+ } - -- hdr.lpszField = (LPWSTR)field; -- hdr.lpszValue = (LPWSTR)value; -- hdr.wFlags = hdr.wCount = 0; -+ /* handle appending to existing header */ -+ if (dwModifier & COALESCEFLAGS) -+ { -+ LPWSTR lpsztmp; -+ WCHAR ch = 0; -+ INT len = 0; -+ INT origlen = lstrlenW(lphttpHdr->lpszValue); -+ INT valuelen = lstrlenW(value); - -+ /* FIXME: Should it really clear HDR_ISREQUEST? */ - if (dwModifier & HTTP_ADDHDR_FLAG_REQ) -- hdr.wFlags |= HDR_ISREQUEST; -- -- res = HTTP_InsertCustomHeader(request, &hdr); -- LeaveCriticalSection( &request->headers_section ); -- return res; -- } -+ lphttpHdr->wFlags |= HDR_ISREQUEST; -+ else -+ lphttpHdr->wFlags &= ~HDR_ISREQUEST; - -- LeaveCriticalSection( &request->headers_section ); -- return ERROR_SUCCESS; -- } -- else if (dwModifier & COALESCEFLAGS) -- { -- LPWSTR lpsztmp; -- WCHAR ch = 0; -- INT len = 0; -- INT origlen = lstrlenW(lphttpHdr->lpszValue); -- INT valuelen = lstrlenW(value); -+ if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA) -+ { -+ ch = ','; -+ lphttpHdr->wFlags |= HDR_COMMADELIMITED; -+ } -+ else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) -+ { -+ ch = ';'; -+ lphttpHdr->wFlags |= HDR_COMMADELIMITED; -+ } - -- if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA) -- { -- ch = ','; -- lphttpHdr->wFlags |= HDR_COMMADELIMITED; -- } -- else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON) -- { -- ch = ';'; -- lphttpHdr->wFlags |= HDR_COMMADELIMITED; -- } -+ len = origlen + valuelen + ((ch > 0) ? 2 : 0); - -- len = origlen + valuelen + ((ch > 0) ? 2 : 0); -+ lpsztmp = heap_realloc(lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR)); -+ if (lpsztmp) -+ { -+ lphttpHdr->lpszValue = lpsztmp; -+ /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */ -+ if (ch > 0) -+ { -+ lphttpHdr->lpszValue[origlen] = ch; -+ origlen++; -+ lphttpHdr->lpszValue[origlen] = ' '; -+ origlen++; -+ } - -- lpsztmp = heap_realloc(lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR)); -- if (lpsztmp) -- { -- lphttpHdr->lpszValue = lpsztmp; -- /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */ -- if (ch > 0) -+ memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR)); -+ lphttpHdr->lpszValue[len] = '\0'; -+ } -+ else - { -- lphttpHdr->lpszValue[origlen] = ch; -- origlen++; -- lphttpHdr->lpszValue[origlen] = ' '; -- origlen++; -+ WARN("heap_realloc (%d bytes) failed\n",len+1); -+ res = ERROR_OUTOFMEMORY; - } - -- memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR)); -- lphttpHdr->lpszValue[len] = '\0'; -- res = ERROR_SUCCESS; -- } -- else -- { -- WARN("heap_realloc (%d bytes) failed\n",len+1); -- res = ERROR_OUTOFMEMORY; -+ goto out; - } - } -+ -+ /* FIXME: What about other combinations? */ -+ if ((dwModifier & ~HTTP_ADDHDR_FLAG_REQ) == HTTP_ADDHDR_FLAG_REPLACE) -+ { -+ res = ERROR_HTTP_HEADER_NOT_FOUND; -+ goto out; -+ } -+ -+ /* FIXME: What if value == ""? */ -+ if (value) -+ { -+ HTTPHEADERW hdr; -+ -+ hdr.lpszField = (LPWSTR)field; -+ hdr.lpszValue = (LPWSTR)value; -+ hdr.wFlags = hdr.wCount = 0; -+ -+ if (dwModifier & HTTP_ADDHDR_FLAG_REQ) -+ hdr.wFlags |= HDR_ISREQUEST; -+ -+ res = HTTP_InsertCustomHeader( request, &hdr ); -+ goto out; -+ } -+ -+ /* FIXME: What if value == NULL? */ -+out: - TRACE("<-- %d\n", res); - LeaveCriticalSection( &request->headers_section ); - return res; --- -2.17.1 - diff --git a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/definition b/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/definition deleted file mode 100644 index 52d34a965..000000000 --- a/patches/wine-hotfixes/staging-7.0/wininet-Cleanup/definition +++ /dev/null @@ -1 +0,0 @@ -# Fixes: [28911] Add HTTP Host header in HttpSendRequest instead of HttpOpenRequest diff --git a/patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/0001-wintrust-Add-parameter-check-in-WTHelperGetProvCertF.patch b/patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/0001-wintrust-Add-parameter-check-in-WTHelperGetProvCertF.patch deleted file mode 100644 index daf82ec36..000000000 --- a/patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/0001-wintrust-Add-parameter-check-in-WTHelperGetProvCertF.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 563f0ccc4f47914e1e2952cc4bc5673cbb97a5ae Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Wed, 18 Apr 2018 03:55:16 +0000 -Subject: [PATCH] wintrust: Add parameter check in WTHelperGetProvCertFromChain - -Signed-off-by: Alistair Leslie-Hughes ---- - dlls/wintrust/wintrust_main.c | 2 +- - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/dlls/wintrust/wintrust_main.c b/dlls/wintrust/wintrust_main.c -index 58e3ac3..bb52282 100644 ---- a/dlls/wintrust/wintrust_main.c -+++ b/dlls/wintrust/wintrust_main.c -@@ -787,7 +787,7 @@ CRYPT_PROVIDER_CERT * WINAPI WTHelperGetProvCertFromChain( - - TRACE("(%p %ld)\n", pSgnr, idxCert); - -- if (idxCert >= pSgnr->csCertChain || !pSgnr->pasCertChain) -+ if (!pSgnr || idxCert >= pSgnr->csCertChain || !pSgnr->pasCertChain) - return NULL; - cert = &pSgnr->pasCertChain[idxCert]; - TRACE("returning %p\n", cert); --- -1.9.1 - diff --git a/patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/definition b/patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/definition deleted file mode 100644 index ff58e3995..000000000 --- a/patches/wine-hotfixes/staging-7.0/wintrust-WTHelperGetProvCertFromChain/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [44061] Check Parameter in WTHelperGetProvCertFromChain diff --git a/patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/0001-wscript-return-TRUE-for-d-and-u-stub-switches.patch b/patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/0001-wscript-return-TRUE-for-d-and-u-stub-switches.patch deleted file mode 100644 index 69bd9809a..000000000 --- a/patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/0001-wscript-return-TRUE-for-d-and-u-stub-switches.patch +++ /dev/null @@ -1,33 +0,0 @@ -From d68918425e249c5c218ee6f0c9418e2e2daf9931 Mon Sep 17 00:00:00 2001 -From: Dmitry Kislyuk -Date: Wed, 28 Apr 2021 09:47:41 -0500 -Subject: [PATCH] wscript: return TRUE for /d and /u stub switches - -Patch by Robert Wilhelm from bug: -https://bugs.winehq.org/show_bug.cgi?id=49905 - -VbsEdit is able to execute scripts with this patch applied. - -Signed-off-by: Dmitry Kislyuk ---- - programs/wscript/main.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/programs/wscript/main.c b/programs/wscript/main.c -index a7005a9289c..6d6e8935149 100644 ---- a/programs/wscript/main.c -+++ b/programs/wscript/main.c -@@ -393,6 +393,10 @@ static BOOL set_host_properties(const WCHAR *prop) - wshInteractive = VARIANT_FALSE; - else if(wcsicmp(prop, L"nologo") == 0) - WINE_FIXME("ignored %s switch\n", debugstr_w(L"nologo")); -+ else if(wcsicmp(prop, L"d") == 0) -+ WINE_FIXME("ignored %s switch\n", debugstr_w(L"d")); -+ else if(wcsicmp(prop, L"u") == 0) -+ WINE_FIXME("ignored %s switch\n", debugstr_w(L"u")); - else - { - WINE_FIXME("unsupported switch %s\n", debugstr_w(prop)); --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/definition b/patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/definition deleted file mode 100644 index 8ae3cf62d..000000000 --- a/patches/wine-hotfixes/staging-7.0/wscript-support-d-u-switches/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [49905] wscript: return TRUE for /d and /u stub switches diff --git a/patches/wine-hotfixes/staging-7.0/xactengine-initial/0001-x3daudio1_7-Create-import-library.patch b/patches/wine-hotfixes/staging-7.0/xactengine-initial/0001-x3daudio1_7-Create-import-library.patch deleted file mode 100644 index bf00b0bdf..000000000 --- a/patches/wine-hotfixes/staging-7.0/xactengine-initial/0001-x3daudio1_7-Create-import-library.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 9c11f23079351f107a3bbcd3cd274f0a5656518f Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Thu, 1 Oct 2020 18:37:06 +1000 -Subject: [PATCH] x3daudio1_7: Create import library - ---- - dlls/x3daudio1_7/Makefile.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/x3daudio1_7/Makefile.in b/dlls/x3daudio1_7/Makefile.in -index c6a8ed5102a..323d3fad60a 100644 ---- a/dlls/x3daudio1_7/Makefile.in -+++ b/dlls/x3daudio1_7/Makefile.in -@@ -1,5 +1,6 @@ - EXTRADEFS = -DX3DAUDIO1_VER=7 -DXAUDIO2_VER=7 - MODULE = x3daudio1_7.dll -+IMPORTLIB = x3daudio1_7 - PARENTSRC = ../xaudio2_7 - IMPORTS = $(FAUDIO_PE_LIBS) - EXTRAINCL = $(FAUDIO_PE_CFLAGS) --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/xactengine-initial/definition b/patches/wine-hotfixes/staging-7.0/xactengine-initial/definition deleted file mode 100644 index 2764d366c..000000000 --- a/patches/wine-hotfixes/staging-7.0/xactengine-initial/definition +++ /dev/null @@ -1,5 +0,0 @@ -Fixes: [31476] Support Bully Scholarship Edition xactengine3_1.dll. -Fixes: [38615] DSA: Drakensang Demo fails on IXACTEngine::Initialize -Fixes: [41030] Pac-Man Museum requires xactengine3_7 -Fixes: [41045] Captain Morgane requires xactengine3_4 -Fixes: [48684] BlazBlue: Calamity Trigger requires for xactengine 3.3 interface. diff --git a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch b/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch deleted file mode 100644 index 06d4b73af..000000000 --- a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 71be762c3d84b84c3d9249f80467797ce3519bb6 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 12 Sep 2020 16:31:09 +1000 -Subject: Add support for private contexts - - -diff --git a/libs/faudio/include/FACT.h b/libs/faudio/include/FACT.h -index 579b7168812..084b1e55cfe 100644 ---- a/libs/faudio/include/FACT.h -+++ b/libs/faudio/include/FACT.h -@@ -805,6 +805,18 @@ FACTAPI uint32_t FACTCue_SetOutputVoiceMatrix( - const float *pLevelMatrix /* SourceChannels * DestinationChannels */ - ); - -+FACTAPI void FACTWave_SetPrivateContext(FACTWave *pWave, void *context); -+FACTAPI void* FACTWave_GetPrivateContext(FACTWave *pWave); -+ -+FACTAPI void FACTWaveBank_SetPrivateContext(FACTWaveBank *pWaveBank, void *context); -+FACTAPI void* FACTWaveBank_GetPrivateContext(FACTWaveBank *pWaveBank); -+ -+FACTAPI void FACTSoundBank_SetPrivateContext(FACTSoundBank *pSoundBank, void *context); -+FACTAPI void* FACTSoundBank_GetPrivateContext(FACTSoundBank *pSoundBank); -+ -+FACTAPI void FACTCue_SetPrivateContext(FACTCue *pCue, void *context); -+FACTAPI void* FACTCue_GetPrivateContext(FACTCue *pCue); -+ - #ifdef __cplusplus - } - #endif /* __cplusplus */ -diff --git a/libs/faudio/src/FACT.c b/libs/faudio/src/FACT.c -index 5eca83b389f..e2e7b10058d 100644 ---- a/libs/faudio/src/FACT.c -+++ b/libs/faudio/src/FACT.c -@@ -1177,6 +1177,9 @@ uint32_t FACTSoundBank_Prepare( - (*ppCue)->notifyOnDestroy = 0; - (*ppCue)->usercontext = NULL; - -+ /* User data */ -+ (*ppCue)->privatecontext = NULL; -+ - /* Sound data */ - (*ppCue)->data = &pSoundBank->cues[nCueIndex]; - if ((*ppCue)->data->flags & 0x04) -@@ -1798,6 +1801,9 @@ uint32_t FACTWaveBank_Prepare( - (*ppWave)->pitch = 0; - (*ppWave)->loopCount = nLoopCount; - -+ /* User data */ -+ (*ppWave)->privatecontext = NULL; -+ - /* TODO: Convert dwPlayOffset to a byte offset */ - FAudio_assert(dwPlayOffset == 0); - #if 0 -@@ -2175,11 +2181,14 @@ uint32_t FACTWave_Stop(FACTWave *pWave, uint32_t dwFlags) - { - FACTNotification note; - note.type = FACTNOTIFICATIONTYPE_WAVESTOP; -+ note.wave.cueIndex = pWave->parentCue->index; -+ note.wave.pCue = pWave->parentCue; -+ note.wave.pSoundBank = pWave->parentCue->parentBank; - note.wave.pWave = pWave; -- if (pWave->parentBank->parentEngine->notifications & NOTIFY_WAVESTOP) -- { -- note.pvContext = pWave->parentBank->parentEngine->wave_context; -- } -+ note.wave.pWaveBank = pWave->parentBank; -+ -+ note.pvContext = pWave->parentBank->parentEngine->wave_context; -+ - pWave->parentBank->parentEngine->notificationCallback(¬e); - } - -@@ -3018,4 +3027,42 @@ uint32_t FACTCue_SetOutputVoiceMatrix( - return 0; - } - -+void FACTWave_SetPrivateContext(FACTWave *pWave, void *context) -+{ -+ pWave->privatecontext = context; -+} -+void* FACTWave_GetPrivateContext(FACTWave *pWave) -+{ -+ return pWave->privatecontext; -+} -+ -+FACTAPI void FACTWaveBank_SetPrivateContext(FACTWaveBank *pWaveBank, void *context) -+{ -+ pWaveBank->privatecontext = context; -+} -+ -+FACTAPI void* FACTWaveBank_GetPrivateContext(FACTWaveBank *pWaveBank) -+{ -+ return pWaveBank->privatecontext; -+} -+ -+FACTAPI void FACTSoundBank_SetPrivateContext(FACTSoundBank *pSoundBank, void *context) -+{ -+ pSoundBank->privatecontext = context; -+} -+FACTAPI void* FACTSoundBank_GetPrivateContext(FACTSoundBank *pSoundBank) -+{ -+ return pSoundBank->privatecontext; -+} -+ -+FACTAPI void FACTCue_SetPrivateContext(FACTCue *pCue, void *context) -+{ -+ pCue->privatecontext = context; -+} -+ -+FACTAPI void* FACTCue_GetPrivateContext(FACTCue *pCue) -+{ -+ return pCue->privatecontext; -+} -+ - /* vim: set noexpandtab shiftwidth=8 tabstop=8: */ -diff --git a/libs/faudio/src/FACT_internal.h b/libs/faudio/src/FACT_internal.h -index 6bf522e64c4..52d07e5f9d3 100644 ---- a/libs/faudio/src/FACT_internal.h -+++ b/libs/faudio/src/FACT_internal.h -@@ -473,6 +473,9 @@ struct FACTSoundBank - uint32_t *variationCodes; - FACTTransitionTable *transitions; - uint32_t *transitionCodes; -+ -+ /* Application data */ -+ void *privatecontext; - }; - - struct FACTWaveBank -@@ -498,6 +501,9 @@ struct FACTWaveBank - uint8_t *packetBuffer; - uint32_t packetBufferLen; - void* io; -+ -+ /* Application data */ -+ void *privatecontext; - }; - - struct FACTWave -@@ -524,6 +530,9 @@ struct FACTWave - uint16_t srcChannels; - FAudioSourceVoice *voice; - FACTWaveCallback callback; -+ -+ /* Application data */ -+ void *privatecontext; - }; - - struct FACTCue -@@ -569,6 +578,9 @@ struct FACTCue - /* Timer */ - uint32_t start; - uint32_t elapsed; -+ -+ /* Application data */ -+ void *privatecontext; - }; - - /* Internal functions */ diff --git a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch b/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch deleted file mode 100644 index 90d2fbece..000000000 --- a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch +++ /dev/null @@ -1,155 +0,0 @@ -From a5439a8a6d3706ee6c3ea13cd76deee1484083d4 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 12 Sep 2020 14:10:18 +1000 -Subject: xactengine3_7: notifications - - -diff --git a/dlls/xactengine3_7/xact_dll.c b/dlls/xactengine3_7/xact_dll.c -index 326f79f0ecd..62084f9234f 100644 ---- a/dlls/xactengine3_7/xact_dll.c -+++ b/dlls/xactengine3_7/xact_dll.c -@@ -329,6 +329,8 @@ static HRESULT WINAPI IXACT3SoundBankImpl_Prepare(IXACT3SoundBank *iface, - cue->fact_cue = fcue; - *ppCue = &cue->IXACT3Cue_iface; - -+ FACTCue_SetPrivateContext(fcue, &cue->IXACT3Cue_iface); -+ - TRACE("Created Cue: %p\n", cue); - - return S_OK; -@@ -370,6 +372,8 @@ static HRESULT WINAPI IXACT3SoundBankImpl_Play(IXACT3SoundBank *iface, - cue->IXACT3Cue_iface.lpVtbl = &XACT3Cue_Vtbl; - cue->fact_cue = fcue; - *ppCue = &cue->IXACT3Cue_iface; -+ -+ FACTCue_SetPrivateContext(fcue, &cue->IXACT3Cue_iface); - } - - return hr; -@@ -627,6 +631,8 @@ static HRESULT WINAPI IXACT3WaveBankImpl_Prepare(IXACT3WaveBank *iface, - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; - -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); -+ - TRACE("Created Wave: %p\n", wave); - - return S_OK; -@@ -668,6 +674,8 @@ static HRESULT WINAPI IXACT3WaveBankImpl_Play(IXACT3WaveBank *iface, - wave->IXACT3Wave_iface.lpVtbl = &XACT3Wave_Vtbl; - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; -+ -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); - } - - return hr; -@@ -837,6 +845,7 @@ static HRESULT WINAPI IXACT3EngineImpl_GetFinalMixFormat(IXACT3Engine *iface, - static void FACTCALL fact_notification_cb(const FACTNotification *notification) - { - XACT3EngineImpl *engine = (XACT3EngineImpl *)notification->pvContext; -+ XACT_NOTIFICATION note; - - /* Older versions of FAudio don't pass through the context */ - if (!engine) -@@ -845,7 +854,45 @@ static void FACTCALL fact_notification_cb(const FACTNotification *notification) - return; - } - -- FIXME("Unsupported callback type %d\n", notification->type); -+ note.type = notification->type; -+ note.pvContext = engine->contexts[notification->type - 1]; -+ -+ switch (notification->type) -+ { -+ case XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED: -+ note.soundBank.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -+ break; -+#if XACT3_VER >= 0x0205 -+ case XACTNOTIFICATIONTYPE_WAVEDESTROYED: -+ case XACTNOTIFICATIONTYPE_WAVELOOPED: -+ case XACTNOTIFICATIONTYPE_WAVEPLAY: -+ case XACTNOTIFICATIONTYPE_WAVEPREPARED: -+#endif -+ case XACTNOTIFICATIONTYPE_WAVESTOP: -+ note.wave.cueIndex = notification->wave.cueIndex; -+ note.wave.pCue = FACTCue_GetPrivateContext(notification->wave.pCue); -+ note.wave.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -+#if XACT3_VER >= 0x0205 -+ note.wave.pWave = FACTWave_GetPrivateContext(notification->wave.pWave); -+#endif -+ note.wave.pWaveBank = FACTWaveBank_GetPrivateContext(notification->wave.pWaveBank); -+ break; -+ -+ case XACTNOTIFICATIONTYPE_CUEPLAY: -+ case XACTNOTIFICATIONTYPE_CUEPREPARED: -+ case XACTNOTIFICATIONTYPE_CUESTOP: -+ note.cue.pCue = FACTCue_GetPrivateContext(notification->cue.pCue); -+ /* Fall through */ -+ case XACTNOTIFICATIONTYPE_CUEDESTROYED: -+ note.cue.cueIndex = notification->cue.cueIndex; -+ note.cue.pSoundBank = FACTSoundBank_GetPrivateContext(notification->cue.pSoundBank); -+ break; -+ default: -+ FIXME("Unsupported callback type %d\n", notification->type); -+ return; -+ } -+ -+ engine->notification_callback(¬e); - } - - static HRESULT WINAPI IXACT3EngineImpl_Initialize(IXACT3Engine *iface, -@@ -961,6 +1008,8 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateSoundBank(IXACT3Engine *iface, - sb->fact_soundbank = fsb; - *ppSoundBank = &sb->IXACT3SoundBank_iface; - -+ FACTSoundBank_SetPrivateContext(fsb, &sb->IXACT3SoundBank_iface); -+ - TRACE("Created SoundBank: %p\n", sb); - - return S_OK; -@@ -1037,6 +1086,8 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateInMemoryWaveBank(IXACT3Engine *ifac - - send_wavebank_notification(This, &wb->IXACT3WaveBank_iface); - -+ FACTWaveBank_SetPrivateContext(fwb, &wb->IXACT3WaveBank_iface); -+ - TRACE("Created in-memory WaveBank: %p\n", wb); - - return S_OK; -@@ -1087,6 +1138,8 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateStreamingWaveBank(IXACT3Engine *ifa - - send_wavebank_notification(This, &wb->IXACT3WaveBank_iface); - -+ FACTWaveBank_SetPrivateContext(fwb, &wb->IXACT3WaveBank_iface); -+ - TRACE("Created streaming WaveBank: %p\n", wb); - - return S_OK; -@@ -1135,6 +1188,8 @@ static HRESULT WINAPI IXACT3EngineImpl_PrepareInMemoryWave(IXACT3Engine *iface, - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; - -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); -+ - TRACE("Created Wave: %p\n", wave); - - return S_OK; -@@ -1197,6 +1252,8 @@ static HRESULT WINAPI IXACT3EngineImpl_PrepareStreamingWave(IXACT3Engine *iface, - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; - -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); -+ - TRACE("Created Wave: %p\n", wave); - - return S_OK; -@@ -1234,6 +1291,8 @@ static HRESULT WINAPI IXACT3EngineImpl_PrepareWave(IXACT3Engine *iface, - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; - -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); -+ - TRACE("Created Wave: %p\n", wave); - - return S_OK; diff --git a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch b/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch deleted file mode 100644 index c474b8b80..000000000 --- a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a8f9265b71b423e2d280645a225465750a1d4594 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Mon, 25 Oct 2021 09:48:50 +1100 -Subject: [PATCH 3/3] Send NOTIFY_CUESTOP when Stop is called - ---- - libs/faudio/src/FACT.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/libs/faudio/src/FACT.c b/libs/faudio/src/FACT.c -index cea960d6710..d9c5d7c2766 100644 ---- a/libs/faudio/src/FACT.c -+++ b/libs/faudio/src/FACT.c -@@ -2685,6 +2685,8 @@ uint32_t FACTCue_Stop(FACTCue *pCue, uint32_t dwFlags) - } - } - -+ FACT_INTERNAL_SendCueNotification(pCue, NOTIFY_CUESTOP, FACTNOTIFICATIONTYPE_CUESTOP); -+ - FAudio_PlatformUnlockMutex(pCue->parentBank->parentEngine->apiLock); - return 0; - } --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch b/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch deleted file mode 100644 index 54340ffac..000000000 --- a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch +++ /dev/null @@ -1,83 +0,0 @@ -From cb0480cc441f4f2c599f506fbac5d27552f55cdd Mon Sep 17 00:00:00 2001 -From: "Olivier F. R. Dierick" -Date: Sat, 29 Jan 2022 22:46:07 +0100 -Subject: xactengine3_7: Don't use switch with constant integers. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52478 - -diff --git a/dlls/xactengine3_7/xact_dll.c b/dlls/xactengine3_7/xact_dll.c -index 62084f9234f..83b7b760118 100644 ---- a/dlls/xactengine3_7/xact_dll.c -+++ b/dlls/xactengine3_7/xact_dll.c -@@ -857,40 +857,43 @@ static void FACTCALL fact_notification_cb(const FACTNotification *notification) - note.type = notification->type; - note.pvContext = engine->contexts[notification->type - 1]; - -- switch (notification->type) -+ if (notification->type == XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED) - { -- case XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED: -- note.soundBank.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -- break; -+ note.soundBank.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -+ } -+ else if (notification->type == XACTNOTIFICATIONTYPE_WAVESTOP - #if XACT3_VER >= 0x0205 -- case XACTNOTIFICATIONTYPE_WAVEDESTROYED: -- case XACTNOTIFICATIONTYPE_WAVELOOPED: -- case XACTNOTIFICATIONTYPE_WAVEPLAY: -- case XACTNOTIFICATIONTYPE_WAVEPREPARED: -+ || notification->type == XACTNOTIFICATIONTYPE_WAVEDESTROYED -+ || notification->type == XACTNOTIFICATIONTYPE_WAVELOOPED -+ || notification->type == XACTNOTIFICATIONTYPE_WAVEPLAY -+ || notification->type == XACTNOTIFICATIONTYPE_WAVEPREPARED) -+#else -+ ) - #endif -- case XACTNOTIFICATIONTYPE_WAVESTOP: -- note.wave.cueIndex = notification->wave.cueIndex; -- note.wave.pCue = FACTCue_GetPrivateContext(notification->wave.pCue); -- note.wave.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -+ { -+ note.wave.cueIndex = notification->wave.cueIndex; -+ note.wave.pCue = FACTCue_GetPrivateContext(notification->wave.pCue); -+ note.wave.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); - #if XACT3_VER >= 0x0205 -- note.wave.pWave = FACTWave_GetPrivateContext(notification->wave.pWave); -+ note.wave.pWave = FACTWave_GetPrivateContext(notification->wave.pWave); - #endif -- note.wave.pWaveBank = FACTWaveBank_GetPrivateContext(notification->wave.pWaveBank); -- break; -- -- case XACTNOTIFICATIONTYPE_CUEPLAY: -- case XACTNOTIFICATIONTYPE_CUEPREPARED: -- case XACTNOTIFICATIONTYPE_CUESTOP: -+ note.wave.pWaveBank = FACTWaveBank_GetPrivateContext(notification->wave.pWaveBank); -+ } -+ else if (notification->type == XACTNOTIFICATIONTYPE_CUEPLAY || -+ notification->type == XACTNOTIFICATIONTYPE_CUEPREPARED || -+ notification->type == XACTNOTIFICATIONTYPE_CUESTOP || -+ notification->type == XACTNOTIFICATIONTYPE_CUEDESTROYED) -+ { -+ if (notification->type != XACTNOTIFICATIONTYPE_CUEDESTROYED) - note.cue.pCue = FACTCue_GetPrivateContext(notification->cue.pCue); -- /* Fall through */ -- case XACTNOTIFICATIONTYPE_CUEDESTROYED: -- note.cue.cueIndex = notification->cue.cueIndex; -- note.cue.pSoundBank = FACTSoundBank_GetPrivateContext(notification->cue.pSoundBank); -- break; -- default: -- FIXME("Unsupported callback type %d\n", notification->type); -- return; -- } -+ note.cue.cueIndex = notification->cue.cueIndex; -+ note.cue.pSoundBank = FACTSoundBank_GetPrivateContext(notification->cue.pSoundBank); -+ } -+ else -+ { -+ FIXME("Unsupported callback type %d\n", notification->type); -+ return; -+ } - - engine->notification_callback(¬e); - } diff --git a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/definition b/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/definition deleted file mode 100644 index b44efb6dd..000000000 --- a/patches/wine-hotfixes/staging-7.0/xactengine3_7-callbacks/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [49678] - xactengine: Implement callback notifications. -Depends: xactengine3_7-Notification diff --git a/patches/wine-hotfixes/staging/0002-bcrypt-Add-support-for-calculating-secret-ecc-keys.patch b/patches/wine-hotfixes/staging/0002-bcrypt-Add-support-for-calculating-secret-ecc-keys.patch deleted file mode 100644 index 84d698155..000000000 --- a/patches/wine-hotfixes/staging/0002-bcrypt-Add-support-for-calculating-secret-ecc-keys.patch +++ /dev/null @@ -1,476 +0,0 @@ -From 49f3ef13b3fd177293546918b13b843704de6536 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 1 Oct 2021 13:56:55 +0200 -Subject: [PATCH] bcrypt: Add support for calculating secret ecc keys. - ---- - configure.ac | 14 ++ - dlls/bcrypt/bcrypt_internal.h | 1 + - dlls/bcrypt/bcrypt_main.c | 6 + - dlls/bcrypt/gnutls.c | 241 +++++++++++++++++++++++++++++++++- - include/bcrypt.h | 1 + - 5 files changed, 260 insertions(+), 3 deletions(-) - -diff --git a/configure.ac b/configure.ac -index e24a6f02f59..36d5f39158d 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -47,6 +47,7 @@ AC_ARG_WITH(faudio, AS_HELP_STRING([--without-faudio],[do not use FAudio (XAu - AC_ARG_WITH(float-abi, AS_HELP_STRING([--with-float-abi=abi],[specify the ABI (soft|softfp|hard) for ARM platforms])) - AC_ARG_WITH(fontconfig,AS_HELP_STRING([--without-fontconfig],[do not use fontconfig])) - AC_ARG_WITH(freetype, AS_HELP_STRING([--without-freetype],[do not use the FreeType library])) -+AC_ARG_WITH(gcrypt, AS_HELP_STRING([--without-gcrypt],[do not use libgcrypt])) - AC_ARG_WITH(gettext, AS_HELP_STRING([--without-gettext],[do not use gettext])) - AC_ARG_WITH(gettextpo, AS_HELP_STRING([--with-gettextpo],[use the GetTextPO library to rebuild po files]), - [if test "x$withval" = "xno"; then ac_cv_header_gettext_po_h=no; fi]) -@@ -2019,6 +2020,19 @@ WINE_NOTICE_WITH(vkd3d,[test "x$ac_cv_lib_soname_vkd3d" = "x"], - [vkd3d ${notice_platform}development files not found (or too old), Direct3D 12 won't be supported.]) - test "x$ac_cv_lib_soname_vkd3d" != "x" || enable_d3d12=${enable_d3d12:-no} - -+dnl **** Check for gcrypt **** -+if test "x$with_gcrypt" != "xno" -+then -+ WINE_PACKAGE_FLAGS(GCRYPT,[libgcrypt],,,, -+ [AC_CHECK_HEADERS([gcrypt.h]) -+ if test "$ac_cv_header_gcrypt_h" = "yes" -+ then -+ WINE_CHECK_SONAME(gcrypt,gcry_sexp_build,,,[$GCRYPT_LIBS]) -+ fi]) -+fi -+WINE_NOTICE_WITH(gcrypt,[test "x$ac_cv_lib_soname_gcrypt" = "x"], -+ [libgcrypt ${notice_platform}development files not found, GCRYPT won't be supported.]) -+ - dnl **** Check for gcc specific options **** - - AC_SUBST(EXTRACFLAGS,"") -diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h -index 6d8b3293d68..5569da34845 100644 ---- a/dlls/bcrypt/bcrypt_internal.h -+++ b/dlls/bcrypt/bcrypt_internal.h -@@ -131,6 +131,7 @@ enum alg_id - /* secret agreement */ - ALG_ID_DH, - ALG_ID_ECDH_P256, -+ ALG_ID_ECDH_P384, - - /* signature */ - ALG_ID_RSA_SIGN, -diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c -index d05301e9d23..0eb64365c7d 100644 ---- a/dlls/bcrypt/bcrypt_main.c -+++ b/dlls/bcrypt/bcrypt_main.c -@@ -113,6 +113,7 @@ builtin_algorithms[] = - { BCRYPT_RSA_ALGORITHM, BCRYPT_ASYMMETRIC_ENCRYPTION_INTERFACE, 0, 0, 0 }, - { BCRYPT_DH_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, - { BCRYPT_ECDH_P256_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, -+ { BCRYPT_ECDH_P384_ALGORITHM, BCRYPT_SECRET_AGREEMENT_INTERFACE, 0, 0, 0 }, - { BCRYPT_RSA_SIGN_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, - { BCRYPT_ECDSA_P256_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, - { BCRYPT_ECDSA_P384_ALGORITHM, BCRYPT_SIGNATURE_INTERFACE, 0, 0, 0 }, -@@ -1334,6 +1335,11 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP - magic = BCRYPT_ECDH_PUBLIC_P256_MAGIC; - break; - -+ case ALG_ID_ECDH_P384: -+ key_size = 48; -+ magic = BCRYPT_ECDH_PUBLIC_P384_MAGIC; -+ break; -+ - case ALG_ID_ECDSA_P256: - key_size = 32; - magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC; -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index 9c60e9a28e3..9f5e3fb788e 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -53,6 +53,10 @@ - #include - #endif - -+#ifdef HAVE_GCRYPT_H -+#include -+#endif -+ - - WINE_DEFAULT_DEBUG_CHANNEL(bcrypt); - WINE_DECLARE_DEBUG_CHANNEL(winediag); -@@ -165,6 +169,24 @@ MAKE_FUNCPTR(mpz_mod); - MAKE_FUNCPTR(mpz_powm); - MAKE_FUNCPTR(mpz_sub_ui); - #endif -+ -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+static BOOL gcrypt_available; -+static void *libgcrypt_handle; -+ -+MAKE_FUNCPTR(gcry_check_version); -+MAKE_FUNCPTR(gcry_sexp_build); -+MAKE_FUNCPTR(gcry_pk_encrypt); -+MAKE_FUNCPTR(gcry_mpi_new); -+MAKE_FUNCPTR(gcry_mpi_print); -+MAKE_FUNCPTR(gcry_sexp_release); -+MAKE_FUNCPTR(gcry_mpi_release); -+MAKE_FUNCPTR(gcry_strsource); -+MAKE_FUNCPTR(gcry_strerror); -+MAKE_FUNCPTR(gcry_sexp_find_token); -+MAKE_FUNCPTR(gcry_sexp_nth_mpi); -+#endif -+ - #undef MAKE_FUNCPTR - - static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size) -@@ -335,6 +357,36 @@ static BOOL gnutls_initialize(void) - } - #undef LOAD_FUNCPTR - #undef LOAD_FUNCPTR_STR -+#endif -+ -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+#define LOAD_FUNCPTR(f) \ -+ if (!(p##f = dlsym( libgcrypt_handle, #f ))) \ -+ { \ -+ WARN( "failed to load %s\n", #f ); \ -+ gcrypt_available = FALSE; \ -+ } -+ -+ if ((libgcrypt_handle = dlopen( SONAME_LIBGCRYPT, RTLD_NOW ))) -+ { -+ gcrypt_available = TRUE; -+ -+ LOAD_FUNCPTR(gcry_check_version); -+ LOAD_FUNCPTR(gcry_sexp_build); -+ LOAD_FUNCPTR(gcry_pk_encrypt); -+ LOAD_FUNCPTR(gcry_mpi_new); -+ LOAD_FUNCPTR(gcry_mpi_print); -+ LOAD_FUNCPTR(gcry_sexp_release); -+ LOAD_FUNCPTR(gcry_mpi_release); -+ LOAD_FUNCPTR(gcry_strsource); -+ LOAD_FUNCPTR(gcry_strerror); -+ LOAD_FUNCPTR(gcry_sexp_find_token); -+ LOAD_FUNCPTR(gcry_sexp_nth_mpi); -+ } -+ else -+ WARN("failed to load gcrypt, no support for ECC secret agreement\n"); -+ -+#undef LOAD_FUNCPTR - #endif - - if (!(pgnutls_cipher_tag = dlsym( libgnutls_handle, "gnutls_cipher_tag" ))) -@@ -478,6 +530,11 @@ static void gnutls_uninitialize(void) - dlclose( libgmp_handle ); - libgmp_handle = NULL; - #endif -+ -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+ dlclose( libgcrypt_handle ); -+ libgcrypt_handle = NULL; -+#endif - } - - struct buffer -@@ -849,6 +906,10 @@ static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, enum alg_ - magic = BCRYPT_ECDH_PUBLIC_P256_MAGIC; - size = 32; - break; -+ case ALG_ID_ECDH_P384: -+ magic = BCRYPT_ECDH_PUBLIC_P384_MAGIC; -+ size = 48; -+ break; - case ALG_ID_ECDSA_P256: - magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC; - size = 32; -@@ -864,7 +925,7 @@ static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, enum alg_ - return STATUS_INTERNAL_ERROR; - } - -- if (curve != GNUTLS_ECC_CURVE_SECP256R1) -+ if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1) - { - FIXME( "curve %u not supported\n", curve ); - free( x.data ); free( y.data ); -@@ -1217,6 +1278,11 @@ static NTSTATUS CDECL key_asymmetric_generate( struct key *key ) - bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP256R1 ); - break; - -+ case ALG_ID_ECDH_P384: -+ pk_alg = GNUTLS_PK_ECC; -+ bitlen = GNUTLS_CURVE_TO_BITS( GNUTLS_ECC_CURVE_SECP384R1 ); -+ break; -+ - case ALG_ID_DH: - return key_dh_generate( key ); - -@@ -1283,6 +1349,10 @@ static NTSTATUS CDECL key_export_ecc( struct key *key, UCHAR *buf, ULONG len, UL - magic = BCRYPT_ECDH_PRIVATE_P256_MAGIC; - size = 32; - break; -+ case ALG_ID_ECDH_P384: -+ magic = BCRYPT_ECDH_PRIVATE_P384_MAGIC; -+ size = 48; -+ break; - case ALG_ID_ECDSA_P256: - magic = BCRYPT_ECDSA_PRIVATE_P256_MAGIC; - size = 32; -@@ -1299,7 +1369,7 @@ static NTSTATUS CDECL key_export_ecc( struct key *key, UCHAR *buf, ULONG len, UL - return STATUS_INTERNAL_ERROR; - } - -- if (curve != GNUTLS_ECC_CURVE_SECP256R1) -+ if (curve != GNUTLS_ECC_CURVE_SECP256R1 && curve != GNUTLS_ECC_CURVE_SECP384R1) - { - FIXME( "curve %u not supported\n", curve ); - free( x.data ); free( y.data ); free( d.data ); -@@ -1553,6 +1623,7 @@ static NTSTATUS CDECL key_asymmetric_init( struct key *key ) - { - case ALG_ID_DH: - case ALG_ID_ECDH_P256: -+ case ALG_ID_ECDH_P384: - case ALG_ID_ECDSA_P256: - case ALG_ID_ECDSA_P384: - case ALG_ID_RSA: -@@ -2215,6 +2286,59 @@ static NTSTATUS CDECL key_asymmetric_decrypt( struct key *key, UCHAR *input, ULO - return status; - } - -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+static NTSTATUS gcrypt_extract_result_into_secret(gcry_sexp_t result, struct secret *secret) -+{ -+ NTSTATUS status = STATUS_SUCCESS; -+ gcry_mpi_t fullcoords = NULL; -+ gcry_sexp_t fragment = NULL; -+ UCHAR *tmp_buffer = NULL; -+ gcry_error_t err; -+ size_t size; -+ -+ fragment = pgcry_sexp_find_token(result, "s", 0); -+ if (!fragment) -+ { -+ status = STATUS_NO_MEMORY; -+ goto done; -+ } -+ -+ fullcoords = pgcry_sexp_nth_mpi(fragment, 1, GCRYMPI_FMT_USG); -+ if (!fullcoords) -+ { -+ status = STATUS_NO_MEMORY; -+ goto done; -+ } -+ -+ if ((err = pgcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &size, fullcoords))) -+ { -+ ERR("Error = %s/%s.\n", pgcry_strsource(err), pgcry_strerror(err)); -+ status = STATUS_INTERNAL_ERROR; -+ goto done; -+ } -+ -+ tmp_buffer = malloc(size); -+ if ((err = pgcry_mpi_print(GCRYMPI_FMT_STD, tmp_buffer, size, NULL, fullcoords))) -+ { -+ ERR("Error = %s/%s.\n", pgcry_strsource(err), pgcry_strerror(err)); -+ status = STATUS_INTERNAL_ERROR; -+ goto done; -+ } -+ -+ secret->data = malloc(size / 2); -+ memcpy(secret->data, tmp_buffer + size % 2, size / 2); -+ secret->data_len = size / 2; -+ -+done: -+ free(tmp_buffer); -+ -+ pgcry_mpi_release(fullcoords); -+ pgcry_sexp_release(fragment); -+ -+ return status; -+} -+#endif -+ - static NTSTATUS key_secret_agreement( void *args ) - { - struct key_secret_agreement_params *params = args; -@@ -2329,8 +2329,120 @@ static NTSTATUS key_secret_agreement( void *args ) - #endif - - case ALG_ID_ECDH_P256: -- FIXME("ECDH is not supported.\n"); -+ case ALG_ID_ECDH_P384: -+/* this is necessary since GNUTLS doesn't support ECDH public key encryption, maybe we can replace this when it does: -+ https://github.com/gnutls/gnutls/blob/cdc4fc288d87f91f974aa23b6e8595a53970ce00/lib/nettle/pk.c#L495 */ -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+ { -+ const char *pubkey_format; -+ DWORD key_size; -+ UCHAR *pubkey_raw; -+ gcry_sexp_t pubkey = NULL; -+ UCHAR *privkey_raw; -+ ULONG privkey_size; -+ gcry_sexp_t privkey = NULL; -+ gcry_sexp_t xchg_result = NULL; -+ gcry_error_t err; -+ NTSTATUS status = STATUS_SUCCESS; -+ -+ if (!gcrypt_available) -+ { -+ WARN("ECC secret support not available.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+ } -+ -+ if (priv_key->alg_id == ALG_ID_ECDH_P256) -+ { -+ pubkey_format = "NIST P-256"; -+ key_size = 32; -+ } -+ else if (priv_key->alg_id == ALG_ID_ECDH_P384) -+ { -+ pubkey_format = "NIST P-384"; -+ key_size = 48; -+ } -+ -+ /* copy public key into temporary buffer so we can prepend 0x04 (to indicate it is uncompressed) */ -+ pubkey_raw = malloc((key_size * 2) + 1); -+ pubkey_raw[0] = 0x04; -+ memcpy(pubkey_raw + 1, peer_key->u.a.pubkey + sizeof(BCRYPT_ECCKEY_BLOB), key_size * 2); -+ -+ err = pgcry_sexp_build(&pubkey, NULL, -+ "(key-data(public-key(ecdh(curve %s)(q %b))))", -+ pubkey_format, -+ (key_size * 2) + 1, -+ pubkey_raw); -+ -+ free(pubkey_raw); -+ -+ if (err) -+ { -+ ERR("Failed to build gcrypt public key. err %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ /* copy private key from gnutls to gcrypt */ -+ privkey_size = sizeof(BCRYPT_ECCKEY_BLOB) + key_size * 3; -+ privkey_raw = malloc(privkey_size); -+ status = key_export_ecc(priv_key, privkey_raw, privkey_size, &privkey_size); -+ -+ if (status) -+ { -+ ERR("Failed to extra gnutls private key\n"); -+ free(privkey_raw); -+ pgcry_sexp_release(pubkey); -+ return status; -+ } -+ -+ err = pgcry_sexp_build(&privkey, NULL, -+ "(data(flags raw)(value %b))", -+ key_size, -+ privkey_raw + sizeof(BCRYPT_ECCKEY_BLOB) + key_size * 2); -+ -+ free(privkey_raw); -+ -+ if (err) -+ { -+ ERR("Failed to build gcrypt private key. err %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); -+ pgcry_sexp_release(pubkey); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ err = pgcry_pk_encrypt(&xchg_result, privkey, pubkey); -+ -+ pgcry_sexp_release(privkey); -+ pgcry_sexp_release(pubkey); -+ -+ if (err) -+ { -+ ERR("Failed to perform key exchange. err %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ status = gcrypt_extract_result_into_secret(xchg_result, secret); -+ -+ pgcry_sexp_release(xchg_result); -+ -+ if (status) -+ { -+ ERR("Failed to extract secret key.\n"); -+ return status; -+ } -+ -+ if (secret->data_len != key_size) -+ { -+ ERR("got secret size %u, expected %u.\n", secret->data_len, key_size); -+ -+ free(secret->data); -+ return STATUS_INTERNAL_ERROR; -+ } -+ - break; -+ } -+#else -+ WARN("Compiled without ECC secret support.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+#endif - - default: - ERR( "unhandled algorithm %u\n", priv_key->alg_id ); -diff --git a/include/bcrypt.h b/include/bcrypt.h -index e485023abb0..fe69cee1667 100644 ---- a/include/bcrypt.h -+++ b/include/bcrypt.h -@@ -87,6 +87,7 @@ typedef LONG NTSTATUS; - #define BCRYPT_DH_ALGORITHM L"DH" - #define BCRYPT_DSA_ALGORITHM L"DSA" - #define BCRYPT_ECDH_P256_ALGORITHM L"ECDH_P256" -+#define BCRYPT_ECDH_P384_ALGORITHM L"ECDH_P384" - #define BCRYPT_ECDSA_P256_ALGORITHM L"ECDSA_P256" - #define BCRYPT_ECDSA_P384_ALGORITHM L"ECDSA_P384" - #define BCRYPT_ECDSA_P521_ALGORITHM L"ECDSA_P521" --- -2.33.0 -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index 903750f467f..fb488ba2640 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -2335,6 +2335,7 @@ static NTSTATUS key_secret_agreement( void *args ) - #if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) - { - const char *pubkey_format; -+ struct key_export_params key_export; - DWORD key_size; - UCHAR *pubkey_raw; - gcry_sexp_t pubkey = NULL; -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index 829de456113..903750f467f 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -2384,7 +2384,11 @@ static NTSTATUS key_secret_agreement( void *args ) - /* copy private key from gnutls to gcrypt */ - privkey_size = sizeof(BCRYPT_ECCKEY_BLOB) + key_size * 3; - privkey_raw = malloc(privkey_size); -- status = key_export_ecc(priv_key, privkey_raw, privkey_size, &privkey_size); -+ key_export.key = priv_key; -+ key_export.buf = privkey_raw; -+ key_export.len = privkey_size; -+ key_export.ret_len = &privkey_size; -+ status = key_export_ecc( &key_export ); - - if (status) - { -From 5bf7c820d5890f284fb6dac357ba46020678b588 Mon Sep 17 00:00:00 2001 -From: Arkadiusz Hiler -Date: Wed, 10 Nov 2021 23:54:15 +0200 -Subject: [PATCH] fixup! bcrypt: Add support for calculating secret ecc keys. - ---- - include/bcrypt.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/include/bcrypt.h b/include/bcrypt.h -index fb7d809bc40..f84ab934ec6 100644 ---- a/include/bcrypt.h -+++ b/include/bcrypt.h -@@ -165,6 +165,7 @@ static const WCHAR BCRYPT_DES_ALGORITHM[] = {'D','E','S',0}; - static const WCHAR BCRYPT_DH_ALGORITHM[] = {'D','H',0}; - static const WCHAR BCRYPT_DSA_ALGORITHM[] = {'D','S','A',0}; - static const WCHAR BCRYPT_ECDH_P256_ALGORITHM[] = {'E','C','D','H','_','P','2','5','6',0}; -+static const WCHAR BCRYPT_ECDH_P384_ALGORITHM[] = {'E','C','D','H','_','P','3','8','4',0}; - static const WCHAR BCRYPT_ECDSA_P256_ALGORITHM[] = {'E','C','D','S','A','_','P','2','5','6',0}; - static const WCHAR BCRYPT_ECDSA_P384_ALGORITHM[] = {'E','C','D','S','A','_','P','3','8','4',0}; - static const WCHAR BCRYPT_ECDSA_P521_ALGORITHM[] = {'E','C','D','S','A','_','P','5','2','1',0}; diff --git a/patches/wine-hotfixes/staging/0003-bcrypt-Add-support-for-OAEP-padded-asymmetric-key-de.patch b/patches/wine-hotfixes/staging/0003-bcrypt-Add-support-for-OAEP-padded-asymmetric-key-de.patch deleted file mode 100644 index c52a7f6b2..000000000 --- a/patches/wine-hotfixes/staging/0003-bcrypt-Add-support-for-OAEP-padded-asymmetric-key-de.patch +++ /dev/null @@ -1,319 +0,0 @@ -From a77c5b4e730814371fccf9c29ee32eec9daa2788 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Fri, 1 Oct 2021 14:34:58 +0200 -Subject: [PATCH] bcrypt: Add support for OAEP-padded asymmetric key - decryption. - -For DayZ. - -CW-Bug-Id: #18973 ---- - dlls/bcrypt/bcrypt_internal.h | 13 +++ - dlls/bcrypt/bcrypt_main.c | 38 +++++---- - dlls/bcrypt/gnutls.c | 147 ++++++++++++++++++++++++++++++++++ - include/bcrypt.h | 7 ++ - 4 files changed, 191 insertions(+), 14 deletions(-) - -diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h -index 070dac30a8d..538d063941c 100644 ---- a/dlls/bcrypt/bcrypt_internal.h -+++ b/dlls/bcrypt/bcrypt_internal.h -@@ -236,6 +236,18 @@ struct key_symmetric_get_tag_params - ULONG len; - }; - -+struct key_asymmetric_encrypt_params -+{ -+ struct key *key; -+ void *padding; -+ UCHAR *input; -+ ULONG input_len; -+ UCHAR *output; -+ ULONG output_len; -+ ULONG *ret_len; -+ ULONG flags; -+}; -+ - struct key_asymmetric_decrypt_params - { - struct key *key; -@@ -308,6 +320,7 @@ enum key_funcs - unix_key_symmetric_get_tag, - unix_key_symmetric_destroy, - unix_key_asymmetric_generate, -+ unix_key_asymmetric_encrypt, - unix_key_asymmetric_decrypt, - unix_key_asymmetric_duplicate, - unix_key_asymmetric_sign, -diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c -index d01214c0ca0..479a3414c35 100644 ---- a/dlls/bcrypt/bcrypt_main.c -+++ b/dlls/bcrypt/bcrypt_main.c -@@ -575,7 +575,7 @@ static NTSTATUS get_rsa_property( enum mode_id mode, const WCHAR *prop, UCHAR *b - { - *ret_size = sizeof(ULONG); - if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL; -- if (buf) *(ULONG *)buf = BCRYPT_SUPPORTED_PAD_PKCS1_SIG; -+ if (buf) *(ULONG *)buf = BCRYPT_SUPPORTED_PAD_PKCS1_SIG | BCRYPT_SUPPORTED_PAD_OAEP; - return STATUS_SUCCESS; - } - -@@ -1201,6 +1201,12 @@ static NTSTATUS key_symmetric_encrypt( struct key *key, UCHAR *input, ULONG inp - UCHAR *buf; - NTSTATUS status; - -+ if (flags & ~BCRYPT_BLOCK_PADDING) -+ { -+ FIXME( "flags %08x not implemented\n", flags ); -+ return STATUS_NOT_IMPLEMENTED; -+ } -+ - if (key->u.s.mode == MODE_ID_GCM) - { - BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *auth_info = padding; -@@ -1968,28 +1968,32 @@ NTSTATUS WINAPI BCryptDestroyKey( BCRYPT_KEY_HANDLE handle ) - NTSTATUS WINAPI BCryptEncrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, - ULONG iv_len, UCHAR *output, ULONG output_len, ULONG *ret_len, ULONG flags ) - { -+ struct key_asymmetric_encrypt_params params; - struct key *key = handle; -- NTSTATUS ret; - - TRACE( "%p, %p, %lu, %p, %p, %lu, %p, %lu, %p, %#lx\n", handle, input, input_len, padding, iv, iv_len, output, - output_len, ret_len, flags ); - - if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE; -- if (!key_is_symmetric( key )) -- { -- FIXME( "encryption with asymmetric keys not yet supported\n" ); -- return STATUS_NOT_IMPLEMENTED; -- } -- if (flags & ~BCRYPT_BLOCK_PADDING) -+ -+ if (key_is_symmetric( key )) - { -- FIXME( "flags %#lx not implemented\n", flags ); -- return STATUS_NOT_IMPLEMENTED; -+ NTSTATUS ret; -+ EnterCriticalSection( &key->u.s.cs ); -+ ret = key_symmetric_encrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags ); -+ LeaveCriticalSection( &key->u.s.cs ); -+ return ret; - } - -- EnterCriticalSection( &key->u.s.cs ); -- ret = key_symmetric_encrypt( key, input, input_len, padding, iv, iv_len, output, output_len, ret_len, flags ); -- LeaveCriticalSection( &key->u.s.cs ); -- return ret; -+ params.key = key; -+ params.input = input; -+ params.input_len = input_len; -+ params.output = output; -+ params.output_len = output_len; -+ params.ret_len = ret_len; -+ params.padding = padding; -+ params.flags = flags; -+ return UNIX_CALL( key_asymmetric_encrypt, ¶ms ); - } - - NTSTATUS WINAPI BCryptDecrypt( BCRYPT_KEY_HANDLE handle, UCHAR *input, ULONG input_len, void *padding, UCHAR *iv, -diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c -index 12d78fbb0d2..b843a72ad01 100644 ---- a/dlls/bcrypt/gnutls.c -+++ b/dlls/bcrypt/gnutls.c -@@ -189,6 +189,7 @@ MAKE_FUNCPTR(gcry_strsource); - MAKE_FUNCPTR(gcry_strerror); - MAKE_FUNCPTR(gcry_sexp_find_token); - MAKE_FUNCPTR(gcry_sexp_nth_mpi); -+MAKE_FUNCPTR(gcry_sexp_nth_data); - #endif - - #undef MAKE_FUNCPTR -@@ -386,6 +387,7 @@ static NTSTATUS gnutls_process_attach( void *args ) - LOAD_FUNCPTR(gcry_strerror); - LOAD_FUNCPTR(gcry_sexp_find_token); - LOAD_FUNCPTR(gcry_sexp_nth_mpi); -+ LOAD_FUNCPTR(gcry_sexp_nth_data); - } - else - WARN("failed to load gcrypt, no support for ECC secret agreement\n"); -@@ -2113,6 +2115,150 @@ static NTSTATUS key_asymmetric_duplicate( void *args ) - return STATUS_SUCCESS; - } - -+#if defined(HAVE_GCRYPT_H) && defined(SONAME_LIBGCRYPT) -+const char * gcrypt_hash_algorithm_name(LPCWSTR alg_id) -+{ -+ if (!wcscmp( alg_id, BCRYPT_SHA1_ALGORITHM )) return "sha1"; -+ if (!wcscmp( alg_id, BCRYPT_SHA256_ALGORITHM )) return "sha256"; -+ if (!wcscmp( alg_id, BCRYPT_SHA384_ALGORITHM )) return "sha384"; -+ if (!wcscmp( alg_id, BCRYPT_SHA512_ALGORITHM )) return "sha512"; -+ if (!wcscmp( alg_id, BCRYPT_MD2_ALGORITHM )) return "md2"; -+ if (!wcscmp( alg_id, BCRYPT_MD5_ALGORITHM )) return "md5"; -+ return NULL; -+} -+ -+static NTSTATUS key_asymmetric_encrypt( void *args ) -+{ -+ struct key_asymmetric_encrypt_params *params = args; -+ struct key *key = params->key; -+ BCRYPT_OAEP_PADDING_INFO *oaep_info = params->padding; -+ UCHAR *input = params->input; -+ ULONG input_len = params->input_len; -+ UCHAR *output = params->output; -+ ULONG output_len = params->output_len; -+ ULONG *ret_len = params->ret_len; -+ ULONG flags = params->flags; -+ NTSTATUS status = STATUS_SUCCESS; -+ gcry_sexp_t sexp_pubkey = NULL; -+ gcry_sexp_t sexp_result = NULL; -+ gcry_sexp_t sexp_input = NULL; -+ BCRYPT_RSAKEY_BLOB *rsa_blob; -+ gcry_sexp_t mpi_a = NULL; -+ const void *result; -+ size_t result_len; -+ gcry_error_t err; -+ -+ if (!gcrypt_available) -+ { -+ ERR("Asymmetric encryption not available.\n"); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ if (key->alg_id != ALG_ID_RSA) -+ { -+ FIXME("Unsupported algorithm id: %u\n", key->alg_id); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ /* import RSA key */ -+ rsa_blob = (BCRYPT_RSAKEY_BLOB *) key->u.a.pubkey; -+ err = pgcry_sexp_build(&sexp_pubkey, NULL, -+ "(public-key(rsa (e %b)(n %b)))", -+ rsa_blob->cbPublicExp, -+ (UCHAR *)(rsa_blob + 1), -+ rsa_blob->cbModulus, -+ (UCHAR *)(rsa_blob + 1) + rsa_blob->cbPublicExp); -+ if (err) -+ { -+ ERR("Failed to build gcrypt public key\n"); -+ goto done; -+ } -+ -+ /* import input data with necessary padding */ -+ if (flags == BCRYPT_PAD_PKCS1) -+ { -+ err = pgcry_sexp_build(&sexp_input, NULL, -+ "(data(flags pksc1)(value %b))", -+ input_len, -+ input); -+ } -+ else if (flags == BCRYPT_PAD_OAEP) -+ { -+ if (oaep_info->pbLabel) -+ err = pgcry_sexp_build(&sexp_input, NULL, -+ "(data(flags oaep)(hash-algo %s)(label %b)(value %b))", -+ gcrypt_hash_algorithm_name(oaep_info->pszAlgId), -+ oaep_info->cbLabel, -+ oaep_info->pbLabel, -+ input_len, -+ input); -+ else -+ err = pgcry_sexp_build(&sexp_input, NULL, -+ "(data(flags oaep)(hash-algo %s)(value %b))", -+ gcrypt_hash_algorithm_name(oaep_info->pszAlgId), -+ input_len, -+ input); -+ } -+ else if (flags == BCRYPT_PAD_NONE) -+ { -+ err = pgcry_sexp_build(&sexp_input, NULL, -+ "(data(flags raw)(value %b))", -+ input_len, -+ input); -+ } -+ else -+ { -+ status = STATUS_INVALID_PARAMETER; -+ goto done; -+ } -+ -+ if (err) -+ { -+ ERR("Failed to build gcrypt padded input data\n"); -+ goto done; -+ } -+ -+ if ((err = pgcry_pk_encrypt(&sexp_result, sexp_input, sexp_pubkey))) -+ { -+ ERR("Failed to encrypt data\n"); -+ goto done; -+ } -+ -+ mpi_a = pgcry_sexp_find_token(sexp_result, "a", 0); -+ result = pgcry_sexp_nth_data(mpi_a, 1, &result_len); -+ -+ *ret_len = result_len; -+ -+ if (output_len < result_len) -+ status = STATUS_BUFFER_TOO_SMALL; -+ else if (output) -+ memcpy(output, result, result_len); -+ -+done: -+ pgcry_sexp_release(sexp_input); -+ pgcry_sexp_release(sexp_pubkey); -+ pgcry_sexp_release(sexp_result); -+ pgcry_sexp_release(mpi_a); -+ -+ if (status) -+ return status; -+ -+ if (err) -+ { -+ ERR("Error = %s/%s\n", pgcry_strsource (err), pgcry_strerror (err)); -+ return STATUS_INTERNAL_ERROR; -+ } -+ -+ return STATUS_SUCCESS; -+} -+#else -+static NTSTATUS key_asymmetric_encrypt( void *args ) -+{ -+ ERR("Asymmetric key encryption not supported without gcrypt.\n"); -+ return STATUS_NOT_IMPLEMENTED; -+} -+#endif -+ - static NTSTATUS key_asymmetric_decrypt( void *args ) - { - struct key_asymmetric_decrypt_params *params = args; -@@ -2393,6 +2539,7 @@ unixlib_entry_t __wine_unix_call_funcs[] = - key_symmetric_get_tag, - key_symmetric_destroy, - key_asymmetric_generate, -+ key_asymmetric_encrypt, - key_asymmetric_decrypt, - key_asymmetric_duplicate, - key_asymmetric_sign, -diff --git a/include/bcrypt.h b/include/bcrypt.h -index 91647e0f333..928f2627073 100644 ---- a/include/bcrypt.h -+++ b/include/bcrypt.h -@@ -293,6 +293,13 @@ typedef struct _BCRYPT_PKCS1_PADDING_INFO - LPCWSTR pszAlgId; - } BCRYPT_PKCS1_PADDING_INFO; - -+typedef struct _BCRYPT_OAEP_PADING_INFO -+{ -+ LPCWSTR pszAlgId; -+ PUCHAR pbLabel; -+ ULONG cbLabel; -+} BCRYPT_OAEP_PADDING_INFO; -+ - #define BCRYPT_PAD_NONE 0x00000001 - #define BCRYPT_PAD_PKCS1 0x00000002 - #define BCRYPT_PAD_OAEP 0x00000004 --- -2.33.1 - diff --git a/patches/wine-hotfixes/staging/0020-stdole32.tlb-Compile-typelib-with-oldtlb.patch b/patches/wine-hotfixes/staging/0020-stdole32.tlb-Compile-typelib-with-oldtlb.patch deleted file mode 100644 index 7089aa268..000000000 --- a/patches/wine-hotfixes/staging/0020-stdole32.tlb-Compile-typelib-with-oldtlb.patch +++ /dev/null @@ -1,10 +0,0 @@ -diff --git a/dlls/stdole32.tlb/Makefile.in b/dlls/stdole32.tlb/Makefile.in -index 6422325b3c7..226235a9218 100644 ---- a/dlls/stdole32.tlb/Makefile.in -+++ b/dlls/stdole32.tlb/Makefile.in -@@ -1,4 +1,5 @@ - MODULE = stdole32.tlb -+EXTRAIDLFLAGS = --oldtlb - - RC_SRCS = rsrc.rc - IDL_SRCS = std_ole_v1.idl diff --git a/patches/wine-hotfixes/staging/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch b/patches/wine-hotfixes/staging/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch deleted file mode 100644 index 00a4e5ce9..000000000 --- a/patches/wine-hotfixes/staging/ntdll-ApiSetMap/0001-ntdll-Add-dummy-apiset-to-PEB.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 5b1520dd617c454ac8e482260b6b437f6f98d185 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Mon, 3 Apr 2017 01:06:26 +0200 -Subject: [PATCH] ntdll: Add dummy apiset to PEB. - ---- - dlls/ntdll/loader.c | 2 ++ - include/Makefile.in | 1 + - include/apiset.h | 37 +++++++++++++++++++++++++++++++++++++ - include/winternl.h | 3 ++- - 4 files changed, 42 insertions(+), 1 deletion(-) - create mode 100644 include/apiset.h - -diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c -index 7a714a5aa6d..62d1b38f4c0 100644 ---- a/dlls/ntdll/loader.c -+++ b/dlls/ntdll/loader.c -@@ -164,6 +164,7 @@ static PEB_LDR_DATA ldr = - - static RTL_BITMAP tls_bitmap; - static RTL_BITMAP tls_expansion_bitmap; -+static API_SET_NAMESPACE_ARRAY apiset_map; - - static WINE_MODREF *cached_modref; - static WINE_MODREF *current_modref; -@@ -3626,6 +3627,7 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR - - peb->LdrData = &ldr; - peb->FastPebLock = &peb_lock; -+ peb->ApiSetMap = &apiset_map; - peb->TlsBitmap = &tls_bitmap; - peb->TlsExpansionBitmap = &tls_expansion_bitmap; - peb->LoaderLock = &loader_section; -diff --git a/include/Makefile.in b/include/Makefile.in -index 9133e5c6315..f56a60fae5e 100644 ---- a/include/Makefile.in -+++ b/include/Makefile.in -@@ -15,6 +15,7 @@ SOURCES = \ - amstream.idl \ - amva.h \ - amvideo.idl \ -+ apiset.h \ - appcompatapi.h \ - appmgmt.h \ - appmodel.h \ -diff --git a/include/apiset.h b/include/apiset.h -new file mode 100644 -index 00000000000..6801cd5f509 ---- /dev/null -+++ b/include/apiset.h -@@ -0,0 +1,37 @@ -+/* -+ * Copyright (C) 2017 Michael Müller -+ * -+ * 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 _API_SET_H_ -+#define _API_SET_H_ -+ -+#include -+ -+typedef struct _API_SET_NAMESPACE_ENTRY -+{ -+ ULONG NameOffset; -+ ULONG NameLength; -+ ULONG DataOffset; -+} API_SET_NAMESPACE_ENTRY, *PAPI_SET_NAMESPACE_ENTRY; -+ -+typedef struct _API_SET_NAMESPACE_ARRAY -+{ -+ ULONG Version; -+ ULONG Count; -+ API_SET_NAMESPACE_ENTRY Array[1]; -+} API_SET_NAMESPACE_ARRAY, *PAPI_SET_NAMESPACE_ARRAY; -+ -+#endif -diff --git a/include/winternl.h b/include/winternl.h -index 298ebbc2d36..163b7737e00 100644 ---- a/include/winternl.h -+++ b/include/winternl.h -@@ -23,6 +23,7 @@ - - #include - #include -+#include - - #ifdef __cplusplus - extern "C" { -@@ -321,7 +322,7 @@ typedef struct _PEB - PVOID KernelCallbackTable; /* 02c/058 */ - ULONG Reserved; /* 030/060 */ - ULONG AtlThunkSListPtr32; /* 034/064 */ -- PVOID /*PPEB_FREE_BLOCK*/ FreeList; /* 038/068 */ -+ PAPI_SET_NAMESPACE_ARRAY ApiSetMap; /* 038/068 */ - ULONG TlsExpansionCounter; /* 03c/070 */ - PRTL_BITMAP TlsBitmap; /* 040/078 */ - ULONG TlsBitmapBits[2]; /* 044/080 */ --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/ntdll-ApiSetMap/definition b/patches/wine-hotfixes/staging/ntdll-ApiSetMap/definition deleted file mode 100644 index 042ee383c..000000000 --- a/patches/wine-hotfixes/staging/ntdll-ApiSetMap/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [44658] Add dummy apiset to PEB struct diff --git a/patches/wine-hotfixes/staging/ntdll-CriticalSection/0002-ntdll-Add-inline-versions-of-RtlEnterCriticalSection.patch b/patches/wine-hotfixes/staging/ntdll-CriticalSection/0002-ntdll-Add-inline-versions-of-RtlEnterCriticalSection.patch deleted file mode 100644 index 9c7eb8687..000000000 --- a/patches/wine-hotfixes/staging/ntdll-CriticalSection/0002-ntdll-Add-inline-versions-of-RtlEnterCriticalSection.patch +++ /dev/null @@ -1,65 +0,0 @@ -From af5cd4a865337f9e37ad3e8548e325fcb0f51d54 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 5 Aug 2017 03:38:38 +0200 -Subject: [PATCH] ntdll: Add inline versions of RtlEnterCriticalSection / - RtlLeaveCriticalSections. - ---- - dlls/ntdll/ntdll_misc.h | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h -index 34af6b780cf..27de37d5b88 100644 ---- a/dlls/ntdll/ntdll_misc.h -+++ b/dlls/ntdll/ntdll_misc.h -@@ -26,6 +26,7 @@ - #include "winnt.h" - #include "winternl.h" - #include "unixlib.h" -+#include "wine/debug.h" - #include "wine/asm.h" - - #define DECLARE_CRITICAL_SECTION(cs) \ -@@ -88,6 +89,39 @@ extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN; - extern int CDECL NTDLL__vsnprintf( char *str, SIZE_T len, const char *format, va_list args ) DECLSPEC_HIDDEN; - extern int CDECL NTDLL__vsnwprintf( WCHAR *str, SIZE_T len, const WCHAR *format, va_list args ) DECLSPEC_HIDDEN; - -+/* inline version of RtlEnterCriticalSection */ -+static inline void enter_critical_section( RTL_CRITICAL_SECTION *crit ) -+{ -+ if (InterlockedIncrement( &crit->LockCount )) -+ { -+ if (crit->OwningThread == ULongToHandle(GetCurrentThreadId())) -+ { -+ crit->RecursionCount++; -+ return; -+ } -+ RtlpWaitForCriticalSection( crit ); -+ } -+ crit->OwningThread = ULongToHandle(GetCurrentThreadId()); -+ crit->RecursionCount = 1; -+} -+ -+/* inline version of RtlLeaveCriticalSection */ -+static inline void leave_critical_section( RTL_CRITICAL_SECTION *crit ) -+{ -+ WINE_DECLARE_DEBUG_CHANNEL(ntdll); -+ if (--crit->RecursionCount) -+ { -+ if (crit->RecursionCount > 0) InterlockedDecrement( &crit->LockCount ); -+ else ERR_(ntdll)( "section %p is not acquired\n", crit ); -+ } -+ else -+ { -+ crit->OwningThread = 0; -+ if (InterlockedDecrement( &crit->LockCount ) >= 0) -+ RtlpUnWaitCriticalSection( crit ); -+ } -+} -+ - struct dllredirect_data - { - ULONG size; --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging/ntdll-CriticalSection/0003-ntdll-Use-fast-CS-functions-for-heap-locking.patch b/patches/wine-hotfixes/staging/ntdll-CriticalSection/0003-ntdll-Use-fast-CS-functions-for-heap-locking.patch deleted file mode 100644 index c1e1aff72..000000000 --- a/patches/wine-hotfixes/staging/ntdll-CriticalSection/0003-ntdll-Use-fast-CS-functions-for-heap-locking.patch +++ /dev/null @@ -1,128 +0,0 @@ -From 50e78099e8c5fbd74131e339b8e48488e1581c74 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 5 Aug 2017 03:39:23 +0200 -Subject: [PATCH] ntdll: Use fast CS functions for heap locking. - ---- - dlls/ntdll/heap.c | 50 +++++++++++++++++++++++------------------------ - 1 file changed, 25 insertions(+), 25 deletions(-) - -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index af2a489b727..178f81006d0 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -diff --git a/dlls/ntdll/heap.c b/dlls/ntdll/heap.c -index 32def2eb072..6b2e8978f1e 100644 ---- a/dlls/ntdll/heap.c -+++ b/dlls/ntdll/heap.c -@@ -454,9 +454,9 @@ static HEAP *HEAP_GetPtr( - } - if (!(heapPtr->flags & HEAP_VALIDATE_ALL)) return heapPtr; - -- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - ret = HEAP_IsRealArena( heapPtr, heapPtr->flags, NULL, NOISY ); -- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - - if (ret) return heapPtr; - if (TRACE_ON(heap)) -@@ -1658,9 +1658,9 @@ void * WINAPI DECLSPEC_HOTPATCH RtlAllocateHeap( HANDLE heap, ULONG flags, SIZE_ - if (!(status = HEAP_lfh_allocate( heap, flags, size, &ptr ))) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - status = HEAP_std_allocate( heap, flags, size, &ptr ); -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -1758,9 +1758,9 @@ BOOLEAN WINAPI DECLSPEC_HOTPATCH RtlFreeHeap( HANDLE heap, ULONG flags, void *pt - if (!(status = HEAP_lfh_free( heap, flags, ptr ))) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - status = HEAP_std_free( heap, flags, ptr ); -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -1832,9 +1832,9 @@ PVOID WINAPI RtlReAllocateHeap( HANDLE heap, ULONG flags, PVOID ptr, SIZE_T size - if (!(status = HEAP_lfh_reallocate( heap, flags, ptr, size, &ret ))) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - status = HEAP_std_reallocate( heap, flags, ptr, size, &ret ); -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -1986,7 +1986,7 @@ BOOLEAN WINAPI RtlLockHeap( HANDLE heap ) - { - HEAP *heapPtr = HEAP_GetPtr( heap ); - if (!heapPtr) return FALSE; -- RtlEnterCriticalSection( &heapPtr->critSection ); -+ enter_critical_section( &heapPtr->critSection ); - return TRUE; - } - -@@ -2007,7 +2007,7 @@ BOOLEAN WINAPI RtlUnlockHeap( HANDLE heap ) - { - HEAP *heapPtr = HEAP_GetPtr( heap ); - if (!heapPtr) return FALSE; -- RtlLeaveCriticalSection( &heapPtr->critSection ); -+ leave_critical_section( &heapPtr->critSection ); - return TRUE; - } - -@@ -2050,9 +2050,9 @@ SIZE_T WINAPI RtlSizeHeap( HANDLE heap, ULONG flags, const void *ptr ) - if (!(status = HEAP_lfh_get_allocated_size( heap, flags, ptr, &size ))) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - status = HEAP_std_get_allocated_size( heap, flags, ptr, &size ); -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -2105,9 +2105,9 @@ BOOLEAN WINAPI RtlValidateHeap( HANDLE heap, ULONG flags, LPCVOID ptr ) - if (!HEAP_lfh_validate( heapPtr, flags, ptr )) break; - /* fallthrough */ - default: -- if (!(flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - if (!HEAP_IsRealArena( heapPtr, flags, ptr, QUIET )) status = STATUS_INVALID_PARAMETER; -- if (!(flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - break; - } - -@@ -2134,7 +2134,7 @@ NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr ) - - if (!heapPtr || !entry) return STATUS_INVALID_PARAMETER; - -- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlEnterCriticalSection( &heapPtr->critSection ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) enter_critical_section( &heapPtr->critSection ); - - /* FIXME: enumerate large blocks too */ - -@@ -2239,7 +2239,7 @@ NTSTATUS WINAPI RtlWalkHeap( HANDLE heap, PVOID entry_ptr ) - if (TRACE_ON(heap)) HEAP_DumpEntry(entry); - - HW_end: -- if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) RtlLeaveCriticalSection( &heapPtr->critSection ); -+ if (!(heapPtr->flags & HEAP_NO_SERIALIZE)) leave_critical_section( &heapPtr->critSection ); - return ret; - } - --- -2.17.1 - diff --git a/patches/wine-hotfixes/staging/ntdll-CriticalSection/0004-ntdll-Use-fast-CS-functions-for-threadpool-locking.patch b/patches/wine-hotfixes/staging/ntdll-CriticalSection/0004-ntdll-Use-fast-CS-functions-for-threadpool-locking.patch deleted file mode 100644 index 566dd3c79..000000000 --- a/patches/wine-hotfixes/staging/ntdll-CriticalSection/0004-ntdll-Use-fast-CS-functions-for-threadpool-locking.patch +++ /dev/null @@ -1,396 +0,0 @@ -From 217794090443a96e712ffe3970e4a70ded2277dc Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Sat, 5 Aug 2017 03:39:37 +0200 -Subject: [PATCH] ntdll: Use fast CS functions for threadpool locking. - ---- - dlls/ntdll/threadpool.c | 90 ++++++++++++++++++++--------------------- - 1 file changed, 45 insertions(+), 45 deletions(-) - -diff --git a/dlls/ntdll/threadpool.c b/dlls/ntdll/threadpool.c -index ca323919d05..581d503b6a4 100644 ---- a/dlls/ntdll/threadpool.c -+++ b/dlls/ntdll/threadpool.c -@@ -1053,7 +1053,7 @@ static void CALLBACK timerqueue_thread_proc( void *param ) - - TRACE( "starting timer queue thread\n" ); - -- RtlEnterCriticalSection( &timerqueue.cs ); -+ enter_critical_section( &timerqueue.cs ); - for (;;) - { - NtQuerySystemTime( &now ); -@@ -1126,7 +1126,7 @@ static void CALLBACK timerqueue_thread_proc( void *param ) - } - - timerqueue.thread_running = FALSE; -- RtlLeaveCriticalSection( &timerqueue.cs ); -+ leave_critical_section( &timerqueue.cs ); - - TRACE( "terminating timer queue thread\n" ); - RtlExitUserThread( 0 ); -@@ -1171,7 +1171,7 @@ static NTSTATUS tp_timerqueue_lock( struct threadpool_object *timer ) - timer->u.timer.period = 0; - timer->u.timer.window_length = 0; - -- RtlEnterCriticalSection( &timerqueue.cs ); -+ enter_critical_section( &timerqueue.cs ); - - /* Make sure that the timerqueue thread is running. */ - if (!timerqueue.thread_running) -@@ -1192,7 +1192,7 @@ static NTSTATUS tp_timerqueue_lock( struct threadpool_object *timer ) - timerqueue.objcount++; - } - -- RtlLeaveCriticalSection( &timerqueue.cs ); -+ leave_critical_section( &timerqueue.cs ); - return status; - } - -@@ -1205,7 +1205,7 @@ static void tp_timerqueue_unlock( struct threadpool_object *timer ) - { - assert( timer->type == TP_OBJECT_TYPE_TIMER ); - -- RtlEnterCriticalSection( &timerqueue.cs ); -+ enter_critical_section( &timerqueue.cs ); - if (timer->u.timer.timer_initialized) - { - /* If timer was pending, remove it. */ -@@ -1224,7 +1224,7 @@ static void tp_timerqueue_unlock( struct threadpool_object *timer ) - - timer->u.timer.timer_initialized = FALSE; - } -- RtlLeaveCriticalSection( &timerqueue.cs ); -+ leave_critical_section( &timerqueue.cs ); - } - - /*********************************************************************** -@@ -1242,7 +1242,7 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - - TRACE( "starting wait queue thread\n" ); - -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - for (;;) - { -@@ -1291,10 +1291,10 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - /* All wait objects have been destroyed, if no new wait objects are created - * within some amount of time, then we can shutdown this thread. */ - assert( num_handles == 0 ); -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - timeout.QuadPart = (ULONGLONG)THREADPOOL_WORKER_TIMEOUT * -10000; - status = NtWaitForMultipleObjects( 1, &bucket->update_event, TRUE, bucket->alertable, &timeout ); -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - if (status == STATUS_TIMEOUT && !bucket->objcount) - break; -@@ -1304,7 +1304,7 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - handles[num_handles] = bucket->update_event; - RtlLeaveCriticalSection( &waitqueue.cs ); - status = NtWaitForMultipleObjects( num_handles + 1, handles, TRUE, bucket->alertable, &timeout ); -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - if (status >= STATUS_WAIT_0 && status < STATUS_WAIT_0 + num_handles) - { -@@ -1388,7 +1388,7 @@ static void CALLBACK waitqueue_thread_proc( void *param ) - if (!--waitqueue.num_buckets) - assert( list_empty( &waitqueue.buckets ) ); - -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - - TRACE( "terminating wait queue thread\n" ); - -@@ -1418,7 +1418,7 @@ static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait ) - wait->u.wait.timeout = 0; - wait->u.wait.handle = INVALID_HANDLE_VALUE; - -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - /* Try to assign to existing bucket if possible. */ - LIST_FOR_EACH_ENTRY( bucket, &waitqueue.buckets, struct waitqueue_bucket, bucket_entry ) -@@ -1475,7 +1475,7 @@ static NTSTATUS tp_waitqueue_lock( struct threadpool_object *wait ) - } - - out: -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - return status; - } - -@@ -1486,7 +1486,7 @@ static void tp_waitqueue_unlock( struct threadpool_object *wait ) - { - assert( wait->type == TP_OBJECT_TYPE_WAIT ); - -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - if (wait->u.wait.bucket) - { - struct waitqueue_bucket *bucket = wait->u.wait.bucket; -@@ -1498,7 +1498,7 @@ static void tp_waitqueue_unlock( struct threadpool_object *wait ) - - NtSetEvent( bucket->update_event, NULL ); - } -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - } - - static void CALLBACK ioqueue_thread_proc( void *param ) -@@ -1775,7 +1775,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON - pool = default_threadpool; - } - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - - /* Make sure that the threadpool has at least one thread. */ - if (!pool->num_workers) -@@ -1789,7 +1789,7 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON - pool->objcount++; - } - -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - - if (status != STATUS_SUCCESS) - return status; -@@ -1805,9 +1805,9 @@ static NTSTATUS tp_threadpool_lock( struct threadpool **out, TP_CALLBACK_ENVIRON - */ - static void tp_threadpool_unlock( struct threadpool *pool ) - { -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - pool->objcount--; -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - tp_threadpool_release( pool ); - } - -@@ -1945,10 +1945,10 @@ static void tp_object_initialize( struct threadpool_object *object, struct threa - struct threadpool_group *group = object->group; - InterlockedIncrement( &group->refcount ); - -- RtlEnterCriticalSection( &group->cs ); -+ enter_critical_section( &group->cs ); - list_add_tail( &group->members, &object->group_entry ); - object->is_group_member = TRUE; -- RtlLeaveCriticalSection( &group->cs ); -+ leave_critical_section( &group->cs ); - } - - if (is_simple_callback) -@@ -1975,7 +1975,7 @@ static void tp_object_submit( struct threadpool_object *object, BOOL signaled ) - assert( !object->shutdown ); - assert( !pool->shutdown ); - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - - /* Start new worker threads if required. */ - if (pool->num_busy_workers >= pool->num_workers && -@@ -1998,7 +1998,7 @@ static void tp_object_submit( struct threadpool_object *object, BOOL signaled ) - RtlWakeConditionVariable( &pool->update_event ); - } - -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - } - - /*********************************************************************** -@@ -2011,7 +2011,7 @@ static void tp_object_cancel( struct threadpool_object *object ) - struct threadpool *pool = object->pool; - LONG pending_callbacks = 0; - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - if (object->num_pending_callbacks) - { - pending_callbacks = object->num_pending_callbacks; -@@ -2026,7 +2026,7 @@ static void tp_object_cancel( struct threadpool_object *object ) - object->u.io.skipped_count += object->u.io.pending_count; - object->u.io.pending_count = 0; - } -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - - while (pending_callbacks--) - tp_object_release( object ); -@@ -2055,7 +2055,7 @@ static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) - { - struct threadpool *pool = object->pool; - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - while (!object_is_finished( object, group_wait )) - { - if (group_wait) -@@ -2063,7 +2063,7 @@ static void tp_object_wait( struct threadpool_object *object, BOOL group_wait ) - else - RtlSleepConditionVariableCS( &object->finished_event, &pool->cs, NULL ); - } -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - } - - static void tp_ioqueue_unlock( struct threadpool_object *io ) -@@ -2117,13 +2117,13 @@ static BOOL tp_object_release( struct threadpool_object *object ) - { - struct threadpool_group *group = object->group; - -- RtlEnterCriticalSection( &group->cs ); -+ enter_critical_section( &group->cs ); - if (object->is_group_member) - { - list_remove( &object->group_entry ); - object->is_group_member = FALSE; - } -- RtlLeaveCriticalSection( &group->cs ); -+ leave_critical_section( &group->cs ); - - tp_group_release( group ); - } -@@ -2324,7 +2324,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - - TRACE( "starting worker thread for pool %p\n", pool ); - -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - for (;;) - { - while ((ptr = threadpool_get_next_item( pool ))) -@@ -2364,7 +2364,7 @@ static void CALLBACK threadpool_worker_proc( void *param ) - } - } - pool->num_workers--; -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - - TRACE( "terminating worker thread for pool %p\n", pool ); - tp_threadpool_release( pool ); -@@ -2612,7 +2612,7 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance ) - return STATUS_SUCCESS; - - pool = object->pool; -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - - /* Start new worker threads if required. */ - if (pool->num_busy_workers >= pool->num_workers) -@@ -2627,7 +2627,7 @@ NTSTATUS WINAPI TpCallbackMayRunLong( TP_CALLBACK_INSTANCE *instance ) - } - } - -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - this->may_run_long = TRUE; - return status; - } -@@ -2708,13 +2708,13 @@ VOID WINAPI TpDisassociateCallback( TP_CALLBACK_INSTANCE *instance ) - return; - - pool = object->pool; -- RtlEnterCriticalSection( &pool->cs ); -+ enter_critical_section( &pool->cs ); - - object->num_associated_callbacks--; - if (object_is_finished( object, FALSE )) - RtlWakeAllConditionVariable( &object->finished_event ); - -- RtlLeaveCriticalSection( &pool->cs ); -+ leave_critical_section( &pool->cs ); - this->associated = FALSE; - } - -@@ -2766,7 +2766,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p - - TRACE( "%p %u %p\n", group, cancel_pending, userdata ); - -- RtlEnterCriticalSection( &this->cs ); -+ enter_critical_section( &this->cs ); - - /* Unset group, increase references, and mark objects for shutdown */ - LIST_FOR_EACH_ENTRY_SAFE( object, next, &this->members, struct threadpool_object, group_entry ) -@@ -2792,7 +2792,7 @@ VOID WINAPI TpReleaseCleanupGroupMembers( TP_CLEANUP_GROUP *group, BOOL cancel_p - list_init( &members ); - list_move_tail( &members, &this->members ); - -- RtlLeaveCriticalSection( &this->cs ); -+ leave_critical_section( &this->cs ); - - /* Cancel pending callbacks if requested */ - if (cancel_pending) -@@ -2915,10 +2915,10 @@ VOID WINAPI TpSetPoolMaxThreads( TP_POOL *pool, DWORD maximum ) - - TRACE( "%p %u\n", pool, maximum ); - -- RtlEnterCriticalSection( &this->cs ); -+ enter_critical_section( &this->cs ); - this->max_workers = max( maximum, 1 ); - this->min_workers = min( this->min_workers, this->max_workers ); -- RtlLeaveCriticalSection( &this->cs ); -+ leave_critical_section( &this->cs ); - } - - /*********************************************************************** -@@ -2931,7 +2931,7 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum ) - - TRACE( "%p %u\n", pool, minimum ); - -- RtlEnterCriticalSection( &this->cs ); -+ enter_critical_section( &this->cs ); - - while (this->num_workers < minimum) - { -@@ -2946,7 +2946,7 @@ BOOL WINAPI TpSetPoolMinThreads( TP_POOL *pool, DWORD minimum ) - this->max_workers = max( this->min_workers, this->max_workers ); - } - -- RtlLeaveCriticalSection( &this->cs ); -+ leave_critical_section( &this->cs ); - return !status; - } - -@@ -2962,7 +2962,7 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO - - TRACE( "%p %p %u %u\n", timer, timeout, period, window_length ); - -- RtlEnterCriticalSection( &timerqueue.cs ); -+ enter_critical_section( &timerqueue.cs ); - - assert( this->u.timer.timer_initialized ); - this->u.timer.timer_set = timeout != NULL; -@@ -3022,7 +3022,7 @@ VOID WINAPI TpSetTimer( TP_TIMER *timer, LARGE_INTEGER *timeout, LONG period, LO - this->u.timer.timer_pending = TRUE; - } - -- RtlLeaveCriticalSection( &timerqueue.cs ); -+ leave_critical_section( &timerqueue.cs ); - - if (submit_timer) - tp_object_submit( this, FALSE ); -@@ -3038,7 +3038,7 @@ VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout ) - - TRACE( "%p %p %p\n", wait, handle, timeout ); - -- RtlEnterCriticalSection( &waitqueue.cs ); -+ enter_critical_section( &waitqueue.cs ); - - assert( this->u.wait.bucket ); - this->u.wait.handle = handle; -@@ -3077,7 +3077,7 @@ VOID WINAPI TpSetWait( TP_WAIT *wait, HANDLE handle, LARGE_INTEGER *timeout ) - NtSetEvent( bucket->update_event, NULL ); - } - -- RtlLeaveCriticalSection( &waitqueue.cs ); -+ leave_critical_section( &waitqueue.cs ); - } - - /*********************************************************************** --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch b/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch deleted file mode 100644 index 86c661409..000000000 --- a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0001-ntdll-Implement-retrieving-DOS-attributes-in-fd_-get.patch +++ /dev/null @@ -1,122 +0,0 @@ -From 11107a30f5ddc2065d2b254fad2d10bc158a1ebb Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Tue, 19 Aug 2014 22:10:49 -0600 -Subject: [PATCH] ntdll: Implement retrieving DOS attributes in - [fd_]get_file_info(). - ---- - configure.ac | 12 ++++++++++++ - dlls/ntdll/unix/file.c | 39 ++++++++++++++++++++++++++++++++++++++- - 2 files changed, 50 insertions(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index d621ae6e712..3ddff238d74 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -65,6 +65,7 @@ AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use the libusb lib - AC_ARG_WITH(v4l2, AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)])) - AC_ARG_WITH(vkd3d, AS_HELP_STRING([--without-vkd3d],[do not use vkd3d (Direct3D 12 support)])) - AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) -+AC_ARG_WITH(xattr, AS_HELP_STRING([--without-xattr],[do not use xattr (security attributes support)])) - AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), - [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi]) - AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]), -@@ -642,6 +643,17 @@ AC_CHECK_HEADERS([libprocstat.h],,, - #include - #endif]) - -+if test "x$with_xattr" != "xno" -+then -+ AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) -+fi -+if test "x$with_xattr" = "xyes" -+then -+ WINE_ERROR_WITH(xattr,[test "x$HAVE_XATTR" = "x"],[xattr ${notice_platform}development files \ -+not found. Wine will be built without extended attribute support, which probably isn't what you \ -+want. You will need to install ${notice_platform}development packages of libattr at the very least.]) -+fi -+ - dnl **** Check for working dll **** - - AC_SUBST(DLLFLAGS,"") -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index e459087af76..0b6e5d3b6a7 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -98,6 +98,9 @@ - #ifdef HAVE_SYS_STATFS_H - #include - #endif -+#ifdef HAVE_ATTR_XATTR_H -+#include -+#endif - #include - #include - -@@ -355,6 +358,20 @@ NTSTATUS errno_to_status( int err ) - } - } - -+#ifndef XATTR_USER_PREFIX -+#define XATTR_USER_PREFIX "user." -+#endif -+ -+static int xattr_get( const char *path, const char *name, void *value, size_t size ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return getxattr( path, name, value, size ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ - /* get space from the current directory data buffer, allocating a new one if necessary */ - static void *get_dir_data_space( struct dir_data *data, unsigned int size ) - { -@@ -1436,6 +1453,22 @@ static BOOL append_entry( struct dir_data *data, const char *long_name, - } - - -+/* Match the Samba conventions for storing DOS file attributes */ -+#define SAMBA_XATTR_DOS_ATTRIB XATTR_USER_PREFIX "DOSATTRIB" -+/* We are only interested in some attributes, the others have corresponding Unix attributes */ -+#define XATTR_ATTRIBS_MASK (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM) -+ -+/* decode the xattr-stored DOS attributes */ -+static inline int get_file_xattr( char *hexattr, int attrlen ) -+{ -+ if (attrlen > 2 && hexattr[0] == '0' && hexattr[1] == 'x') -+ { -+ hexattr[attrlen] = 0; -+ return strtol( hexattr+2, NULL, 16 ) & XATTR_ATTRIBS_MASK; -+ } -+ return 0; -+} -+ - /* fetch the attributes of a file */ - static inline ULONG get_file_attributes( const struct stat *st ) - { -@@ -1479,7 +1512,8 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON - static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - { - char *parent_path; -- int ret; -+ char hexattr[11]; -+ int len, ret; - - *attr = 0; - ret = lstat( path, st ); -@@ -1505,6 +1539,9 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - free( parent_path ); - } - *attr |= get_file_attributes( st ); -+ len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); -+ if (len == -1) return ret; -+ *attr |= get_file_xattr( hexattr, len ); - return ret; - } - --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch b/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch deleted file mode 100644 index 1aa161614..000000000 --- a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0003-ntdll-Implement-storing-DOS-attributes-in-NtSetInfor.patch +++ /dev/null @@ -1,168 +0,0 @@ -From 06af804bd6e75332dd2be2005b443e285bc4f2dc Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Wed, 20 Aug 2014 00:08:52 -0600 -Subject: [PATCH] ntdll: Implement storing DOS attributes in - NtSetInformationFile. - ---- - dlls/ntdll/tests/file.c | 8 ++--- - dlls/ntdll/unix/file.c | 76 +++++++++++++++++++++++++++++------------ - 2 files changed, 59 insertions(+), 25 deletions(-) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 19ae5f2ac21..cb578ceee9e 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -1400,7 +1400,7 @@ static void test_file_basic_information(void) - memset(&fbi, 0, sizeof(fbi)); - res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't get attributes\n"); -- todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fbi.FileAttributes ); -+ ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM (ok in old linux without xattr)\n", fbi.FileAttributes ); - - /* Then HIDDEN */ - memset(&fbi, 0, sizeof(fbi)); -@@ -1413,7 +1413,7 @@ static void test_file_basic_information(void) - memset(&fbi, 0, sizeof(fbi)); - res = pNtQueryInformationFile(h, &io, &fbi, sizeof fbi, FileBasicInformation); - ok ( res == STATUS_SUCCESS, "can't get attributes\n"); -- todo_wine ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fbi.FileAttributes ); -+ ok ( (fbi.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN (ok in old linux without xattr)\n", fbi.FileAttributes ); - - /* Check NORMAL last of all (to make sure we can clear attributes) */ - memset(&fbi, 0, sizeof(fbi)); -@@ -1470,7 +1470,7 @@ static void test_file_all_information(void) - memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); - res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); - ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res); -- todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM\n", fai_buf.fai.BasicInformation.FileAttributes ); -+ ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_SYSTEM, "attribute %x not FILE_ATTRIBUTE_SYSTEM (ok in old linux without xattr)\n", fai_buf.fai.BasicInformation.FileAttributes ); - - /* Then HIDDEN */ - memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); -@@ -1483,7 +1483,7 @@ static void test_file_all_information(void) - memset(&fai_buf.fai, 0, sizeof(fai_buf.fai)); - res = pNtQueryInformationFile(h, &io, &fai_buf.fai, sizeof fai_buf, FileAllInformation); - ok ( res == STATUS_SUCCESS, "can't get attributes\n"); -- todo_wine ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN\n", fai_buf.fai.BasicInformation.FileAttributes ); -+ ok ( (fai_buf.fai.BasicInformation.FileAttributes & attrib_mask) == FILE_ATTRIBUTE_HIDDEN, "attribute %x not FILE_ATTRIBUTE_HIDDEN (ok in old linux without xattr)\n", fai_buf.fai.BasicInformation.FileAttributes ); - - /* Check NORMAL last of all (to make sure we can clear attributes) */ - memset(&fai_buf.fai.BasicInformation, 0, sizeof(fai_buf.fai.BasicInformation)); -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index a2cae9708db..9a1bd50c695 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -374,6 +374,26 @@ NTSTATUS errno_to_status( int err ) - #define XATTR_USER_PREFIX "user." - #endif - -+static int xattr_fremove( int filedes, const char *name ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return fremovexattr( filedes, name ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ -+static int xattr_fset( int filedes, const char *name, void *value, size_t size ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return fsetxattr( filedes, name, value, size, 0 ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ - static int xattr_get( const char *path, const char *name, void *value, size_t size ) - { - #if defined(HAVE_ATTR_XATTR_H) -@@ -1520,6 +1540,39 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON - } - - -+/* set the stat info and file attributes for a file (by file descriptor) */ -+NTSTATUS fd_set_file_info( int fd, ULONG attr ) -+{ -+ char hexattr[11]; -+ struct stat st; -+ -+ if (fstat( fd, &st ) == -1) return errno_to_status( errno ); -+ if (attr & FILE_ATTRIBUTE_READONLY) -+ { -+ if (S_ISDIR( st.st_mode)) -+ WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n"); -+ else -+ st.st_mode &= ~0222; /* clear write permission bits */ -+ } -+ else -+ { -+ /* add write permission only where we already have read permission */ -+ st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~start_umask); -+ } -+ if (fchmod( fd, st.st_mode ) == -1) return errno_to_status( errno ); -+ attr &= ~FILE_ATTRIBUTE_NORMAL; /* do not store everything, but keep everything Samba can use */ -+ if (attr != 0) -+ { -+ int len; -+ -+ len = sprintf( hexattr, "0x%x", attr ); -+ xattr_fset( fd, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); -+ } -+ else -+ xattr_fremove( fd, SAMBA_XATTR_DOS_ATTRIB ); -+ return STATUS_SUCCESS; -+} -+ - /* get the stat info and file attributes for a file (by name) */ - static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - { -@@ -4356,7 +4409,6 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, - case FileBasicInformation: - if (len >= sizeof(FILE_BASIC_INFORMATION)) - { -- struct stat st; - const FILE_BASIC_INFORMATION *info = ptr; - LARGE_INTEGER mtime, atime; - -@@ -4686,33 +4686,7 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, - status = set_file_times( fd, &mtime, &atime ); - - if (status == STATUS_SUCCESS && info->FileAttributes) -- { -- if (fstat( fd, &st ) == -1) status = errno_to_status( errno ); -- else -- { -- if (info->FileAttributes & FILE_ATTRIBUTE_READONLY) -- { -- if (S_ISDIR( st.st_mode)) -- WARN("FILE_ATTRIBUTE_READONLY ignored for directory.\n"); -- else -- st.st_mode &= ~0222; /* clear write permission bits */ -- } -- else -- { -- if (is_wine_file(handle)) -- { -- TRACE("HACK: Not giving write permission to wine file!\n"); -- io->u.Status = STATUS_ACCESS_DENIED; -- } -- else -- { -- /* add write permission only where we already have read permission */ -- st.st_mode |= (0600 | ((st.st_mode & 044) >> 1)) & (~start_umask); -- } -- } -- if (fchmod( fd, st.st_mode ) == -1) status = errno_to_status( errno ); -- } -- } -+ status = fd_set_file_info( fd, info->FileAttributes ); - - if (needs_close) close( fd ); - } --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch b/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch deleted file mode 100644 index c9dde1ab6..000000000 --- a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0004-ntdll-Implement-storing-DOS-attributes-in-NtCreateFi.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 494342c8f911f827783f1aed9717d793c4e6a8c0 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Wed, 20 Aug 2014 15:28:00 -0600 -Subject: [PATCH] ntdll: Implement storing DOS attributes in NtCreateFile. - ---- - dlls/ntdll/tests/directory.c | 24 ++++++++--------- - dlls/ntdll/unix/file.c | 51 ++++++++++++++++++++++++++++++++---- - 2 files changed, 57 insertions(+), 18 deletions(-) - -diff --git a/dlls/ntdll/tests/directory.c b/dlls/ntdll/tests/directory.c -index 6a423174664..fccd48f23e5 100644 ---- a/dlls/ntdll/tests/directory.c -+++ b/dlls/ntdll/tests/directory.c -@@ -55,7 +55,6 @@ static NTSTATUS (WINAPI *pRtlWow64EnableFsRedirectionEx)( ULONG disable, ULONG * - - /* The attribute sets to test */ - static struct testfile_s { -- BOOL todo; /* set if it doesn't work on wine yet */ - BOOL attr_done; /* set if attributes were tested for this file already */ - const DWORD attr; /* desired attribute */ - WCHAR name[20]; /* filename to use */ -@@ -63,16 +62,16 @@ static struct testfile_s { - const char *description; /* for error messages */ - int nfound; /* How many were found (expect 1) */ - } testfiles[] = { -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" }, -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" }, -- { 1, 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" }, -- { 1, 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" }, -- { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" }, -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, -- { 0, 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, -- { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, -- { 0, 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } -+ { 0, FILE_ATTRIBUTE_NORMAL, {'l','o','n','g','f','i','l','e','n','a','m','e','.','t','m','p'}, "normal" }, -+ { 0, FILE_ATTRIBUTE_NORMAL, {'n','.','t','m','p',}, "normal" }, -+ { 0, FILE_ATTRIBUTE_HIDDEN, {'h','.','t','m','p',}, "hidden" }, -+ { 0, FILE_ATTRIBUTE_SYSTEM, {'s','.','t','m','p',}, "system" }, -+ { 0, FILE_ATTRIBUTE_DIRECTORY, {'d','.','t','m','p',}, "directory" }, -+ { 0, FILE_ATTRIBUTE_NORMAL, {0xe9,'a','.','t','m','p'}, "normal" }, -+ { 0, FILE_ATTRIBUTE_NORMAL, {0xc9,'b','.','t','m','p'}, "normal" }, -+ { 0, FILE_ATTRIBUTE_NORMAL, {'e','a','.','t','m','p'}, "normal" }, -+ { 0, FILE_ATTRIBUTE_DIRECTORY, {'.'}, ". directory" }, -+ { 0, FILE_ATTRIBUTE_DIRECTORY, {'.','.'}, ".. directory" } - }; - static const int test_dir_count = ARRAY_SIZE(testfiles); - static const int max_test_dir_size = ARRAY_SIZE(testfiles) + 5; /* size of above plus some for .. etc */ -@@ -162,8 +161,7 @@ static void tally_test_file(FILE_BOTH_DIRECTORY_INFORMATION *dir_info) - if (namelen != len || memcmp(nameW, testfiles[i].name, len*sizeof(WCHAR))) - continue; - if (!testfiles[i].attr_done) { -- todo_wine_if (testfiles[i].todo) -- ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib); -+ ok (attrib == (testfiles[i].attr & attribmask), "file %s: expected %s (%x), got %x (is your linux new enough?)\n", wine_dbgstr_w(testfiles[i].name), testfiles[i].description, testfiles[i].attr, attrib); - testfiles[i].attr_done = TRUE; - } - testfiles[i].nfound++; -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 9a1bd50c695..9b3735dd917 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -404,6 +404,26 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si - #endif - } - -+static int xattr_remove( const char *path, const char *name ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return removexattr( path, name ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ -+static int xattr_set( const char *path, const char *name, void *value, size_t size ) -+{ -+#if defined(HAVE_ATTR_XATTR_H) -+ return setxattr( path, name, value, size, 0 ); -+#else -+ errno = ENOSYS; -+ return -1; -+#endif -+} -+ - /* get space from the current directory data buffer, allocating a new one if necessary */ - static void *get_dir_data_space( struct dir_data *data, unsigned int size ) - { -@@ -3783,6 +3803,20 @@ static NTSTATUS unmount_device( HANDLE handle ) - return status; - } - -+NTSTATUS set_file_info( const char *path, ULONG attr ) -+{ -+ char hexattr[11]; -+ int len; -+ -+ /* Note: unix mode already set when called this way */ -+ attr &= ~FILE_ATTRIBUTE_NORMAL; /* do not store everything, but keep everything Samba can use */ -+ len = sprintf( hexattr, "0x%x", attr ); -+ if (attr != 0) -+ xattr_set( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); -+ else -+ xattr_remove( path, SAMBA_XATTR_DOS_ATTRIB ); -+ return STATUS_SUCCESS; -+} - - /****************************************************************************** - * open_unix_file -@@ -3868,13 +3902,14 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - status = STATUS_SUCCESS; - } - -- if (status == STATUS_SUCCESS) -+ if (status != STATUS_SUCCESS) - { -- status = open_unix_file( handle, unix_name, access, &new_attr, attributes, -- sharing, disposition, options, ea_buffer, ea_length ); -- free( unix_name ); -+ WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), io->u.Status ); -+ return status; - } -- else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); -+ -+ status = open_unix_file( handle, unix_name, access, &new_attr, attributes, -+ sharing, disposition, options, ea_buffer, ea_length ); - - if (status == STATUS_SUCCESS) - { -@@ -3896,6 +3931,11 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - io->Information = FILE_OVERWRITTEN; - break; - } -+ if (io->Information == FILE_CREATED) -+ { -+ /* set any DOS extended attributes */ -+ set_file_info( unix_name, attributes ); -+ } - } - else if (status == STATUS_TOO_MANY_OPENED_FILES) - { -@@ -3904,6 +3944,7 @@ NTSTATUS WINAPI NtCreateFile( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBU - } - - free( nt_name.Buffer ); -+ free( unix_name ); - return io->u.Status = status; - } - --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch b/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch deleted file mode 100644 index 0faf09924..000000000 --- a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0005-libport-Add-support-for-Mac-OS-X-style-extended-attr.patch +++ /dev/null @@ -1,97 +0,0 @@ -From c93462e9ca4529f413b82abaa76b593df9947cc6 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Mon, 6 Oct 2014 14:21:11 -0600 -Subject: [PATCH] libport: Add support for Mac OS X style extended attributes. - ---- - configure.ac | 3 +++ - dlls/ntdll/unix/file.c | 23 ++++++++++++++++++----- - 2 files changed, 21 insertions(+), 5 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 3ddff238d74..57f76f09b96 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -646,6 +646,9 @@ AC_CHECK_HEADERS([libprocstat.h],,, - if test "x$with_xattr" != "xno" - then - AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) -+ AC_CHECK_HEADERS(sys/xattr.h, [HAVE_XATTR=1] -+ [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[getxattr("", "", "", 0, 0, 0);]])], -+ [AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (Mac OS X)])])]) - fi - if test "x$with_xattr" = "xyes" - then -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 6f33d2c748f..d4cb708336c 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -99,7 +99,10 @@ - #include - #endif - #ifdef HAVE_ATTR_XATTR_H -+#undef XATTR_ADDITIONAL_OPTIONS - #include -+#elif defined(HAVE_SYS_XATTR_H) -+#include - #endif - #include - #include -@@ -364,7 +367,9 @@ NTSTATUS errno_to_status( int err ) - - static int xattr_fremove( int filedes, const char *name ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return fremovexattr( filedes, name, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return fremovexattr( filedes, name ); - #else - errno = ENOSYS; -@@ -374,7 +379,9 @@ static int xattr_fremove( int filedes, const char *name ) - - static int xattr_fset( int filedes, const char *name, void *value, size_t size ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return fsetxattr( filedes, name, value, size, 0, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return fsetxattr( filedes, name, value, size, 0 ); - #else - errno = ENOSYS; -@@ -384,7 +391,9 @@ static int xattr_fset( int filedes, const char *name, void *value, size_t size ) - - static int xattr_get( const char *path, const char *name, void *value, size_t size ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return getxattr( path, name, value, size, 0, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return getxattr( path, name, value, size ); - #else - errno = ENOSYS; -@@ -394,7 +403,9 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si - - static int xattr_remove( const char *path, const char *name ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return removexattr( path, name, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return removexattr( path, name ); - #else - errno = ENOSYS; -@@ -404,7 +415,9 @@ static int xattr_remove( const char *path, const char *name ) - - static int xattr_set( const char *path, const char *name, void *value, size_t size ) - { --#if defined(HAVE_ATTR_XATTR_H) -+#if defined(XATTR_ADDITIONAL_OPTIONS) -+ return setxattr( path, name, value, size, 0, 0 ); -+#elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return setxattr( path, name, value, size, 0 ); - #else - errno = ENOSYS; --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch b/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch deleted file mode 100644 index c0c0ac831..000000000 --- a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0006-libport-Add-support-for-FreeBSD-style-extended-attri.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 691c8c2dfe1c14d968cf91f2356d4fca0611d579 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Mon, 6 Oct 2014 14:26:24 -0600 -Subject: [PATCH] ntdll: Add support for FreeBSD style extended attributes. - ---- - configure.ac | 2 +- - dlls/ntdll/unix/file.c | 37 +++++++++++++++++++++++++++++++++++++ - 2 files changed, 38 insertions(+), 1 deletion(-) - -diff --git a/configure.ac b/configure.ac -index 57f76f09b96..b99be0623b9 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -645,7 +645,7 @@ AC_CHECK_HEADERS([libprocstat.h],,, - - if test "x$with_xattr" != "xno" - then -- AC_CHECK_HEADERS(attr/xattr.h, [HAVE_XATTR=1]) -+ AC_CHECK_HEADERS(attr/xattr.h sys/extattr.h, [HAVE_XATTR=1]) - AC_CHECK_HEADERS(sys/xattr.h, [HAVE_XATTR=1] - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[getxattr("", "", "", 0, 0, 0);]])], - [AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [Define if xattr functions take additional arguments (Mac OS X)])])]) -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index d4cb708336c..63fff5f7697 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -104,6 +104,10 @@ - #elif defined(HAVE_SYS_XATTR_H) - #include - #endif -+#ifdef HAVE_SYS_EXTATTR_H -+#undef XATTR_ADDITIONAL_OPTIONS -+#include -+#endif - #include - #include - -@@ -364,6 +368,21 @@ NTSTATUS errno_to_status( int err ) - #ifndef XATTR_USER_PREFIX - #define XATTR_USER_PREFIX "user." - #endif -+#ifndef XATTR_USER_PREFIX_LEN -+#define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1) -+#endif -+ -+#ifdef HAVE_SYS_EXTATTR_H -+static inline int xattr_valid_namespace( const char *name ) -+{ -+ if (strncmp( XATTR_USER_PREFIX, name, XATTR_USER_PREFIX_LEN ) != 0) -+ { -+ errno = EPERM; -+ return 0; -+ } -+ return 1; -+} -+#endif - - static int xattr_fremove( int filedes, const char *name ) - { -@@ -371,6 +390,9 @@ static int xattr_fremove( int filedes, const char *name ) - return fremovexattr( filedes, name, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return fremovexattr( filedes, name ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_delete_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN] ); - #else - errno = ENOSYS; - return -1; -@@ -383,6 +405,10 @@ static int xattr_fset( int filedes, const char *name, void *value, size_t size ) - return fsetxattr( filedes, name, value, size, 0, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return fsetxattr( filedes, name, value, size, 0 ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_set_fd( filedes, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], -+ value, size ); - #else - errno = ENOSYS; - return -1; -@@ -395,6 +421,10 @@ static int xattr_get( const char *path, const char *name, void *value, size_t si - return getxattr( path, name, value, size, 0, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return getxattr( path, name, value, size ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_get_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], -+ value, size ); - #else - errno = ENOSYS; - return -1; -@@ -407,6 +437,9 @@ static int xattr_remove( const char *path, const char *name ) - return removexattr( path, name, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return removexattr( path, name ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_delete_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN] ); - #else - errno = ENOSYS; - return -1; -@@ -419,6 +452,10 @@ static int xattr_set( const char *path, const char *name, void *value, size_t si - return setxattr( path, name, value, size, 0, 0 ); - #elif defined(HAVE_SYS_XATTR_H) || defined(HAVE_ATTR_XATTR_H) - return setxattr( path, name, value, size, 0 ); -+#elif defined(HAVE_SYS_EXTATTR_H) -+ if (!xattr_valid_namespace( name )) return -1; -+ return extattr_set_file( path, EXTATTR_NAMESPACE_USER, &name[XATTR_USER_PREFIX_LEN], -+ value, size ); - #else - errno = ENOSYS; - return -1; --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch b/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch deleted file mode 100644 index b908a1916..000000000 --- a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0007-ntdll-Perform-the-Unix-style-hidden-file-check-withi.patch +++ /dev/null @@ -1,80 +0,0 @@ -From a2e3bc27382f9c0c4894c6e0ab121f075e82db3e Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Wed, 20 Aug 2014 11:26:48 -0600 -Subject: [PATCH] ntdll: Perform the Unix-style hidden file check within the - unified file info grabbing routine. - ---- - dlls/ntdll/unix/file.c | 23 +++++++++-------------- - 1 file changed, 9 insertions(+), 14 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 73d4cce90ae..b790cde3f90 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -1328,15 +1328,15 @@ static BOOLEAN get_dir_case_sensitivity( const char *dir ) - * - * Check if the specified file should be hidden based on its name and the show dot files option. - */ --static BOOL is_hidden_file( const UNICODE_STRING *name ) -+static BOOL is_hidden_file( const char *name ) - { -- WCHAR *p, *end; -+ const char *p, *end; - - if (show_dot_files) return FALSE; - -- end = p = name->Buffer + name->Length/sizeof(WCHAR); -- while (p > name->Buffer && p[-1] == '\\') p--; -- while (p > name->Buffer && p[-1] != '\\') p--; -+ end = p = name + strlen( name ); -+ while (p > name && p[-1] == '\\') p--; -+ while (p > name && p[-1] != '\\') p--; - return (p < end && *p == '.'); - } - -@@ -1679,6 +1679,10 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - free( parent_path ); - } - *attr |= get_file_attributes( st ); -+ /* convert Unix-style hidden files to a DOS hidden file attribute */ -+ if (is_hidden_file( path )) -+ *attr |= FILE_ATTRIBUTE_HIDDEN; -+ /* retrieve any stored DOS attributes */ - len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); - if (len == -1) return ret; - *attr |= get_file_xattr( hexattr, len ); -@@ -2186,11 +2190,6 @@ static NTSTATUS get_dir_data_entry( struct dir_data *dir_data, void *info_ptr, I - if (class != FileNamesInformation) - { - if (st.st_dev != dir_data->id.dev) st.st_ino = 0; /* ignore inode if on a different device */ -- -- if (!show_dot_files && names->long_name[0] == '.' && names->long_name[1] && -- (names->long_name[1] != '.' || names->long_name[2])) -- attributes |= FILE_ATTRIBUTE_HIDDEN; -- - fill_file_info( &st, attributes, info, class ); - } - -@@ -4106,7 +4105,6 @@ NTSTATUS WINAPI NtQueryFullAttributesFile( const OBJECT_ATTRIBUTES *attr, - info->AllocationSize = std.AllocationSize; - info->EndOfFile = std.EndOfFile; - info->FileAttributes = basic.FileAttributes; -- if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; - } - free( unix_name ); - } -@@ -4133,10 +4131,7 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC - else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) - status = STATUS_INVALID_INFO_CLASS; - else -- { - status = fill_file_info( &st, attributes, info, FileBasicInformation ); -- if (is_hidden_file( attr->ObjectName )) info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; -- } - free( unix_name ); - } - else WARN( "%s not found (%x)\n", debugstr_us(attr->ObjectName), status ); --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch b/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch deleted file mode 100644 index f87c79e88..000000000 --- a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/0008-ntdll-Always-store-SAMBA_XATTR_DOS_ATTRIB-when-path-.patch +++ /dev/null @@ -1,46 +0,0 @@ -From dd02380fff84cbef2a6df7b6f82b271e0e9d732f Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Thu, 14 Jan 2016 23:09:19 +0100 -Subject: [PATCH] ntdll: Always store SAMBA_XATTR_DOS_ATTRIB when path could be - interpreted as hidden. - ---- - dlls/ntdll/unix/file.c | 13 ++++++++----- - 1 file changed, 8 insertions(+), 5 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index c6b4928bd53..3bf82b1d45d 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -1567,12 +1567,15 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr ) - free( parent_path ); - } - *attr |= get_file_attributes( st ); -- /* convert Unix-style hidden files to a DOS hidden file attribute */ -- if (is_hidden_file( path )) -- *attr |= FILE_ATTRIBUTE_HIDDEN; - /* retrieve any stored DOS attributes */ - len = xattr_get( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, sizeof(hexattr)-1 ); -- if (len == -1) return ret; -+ if (len == -1) -+ { -+ /* convert Unix-style hidden files to a DOS hidden file attribute */ -+ if (is_hidden_file( path )) -+ *attr |= FILE_ATTRIBUTE_HIDDEN; -+ return ret; -+ } - *attr |= get_file_xattr( hexattr, len ); - return ret; - } -@@ -3556,7 +3559,7 @@ NTSTATUS set_file_info( const char *path, ULONG attr ) - /* Note: unix mode already set when called this way */ - attr &= ~FILE_ATTRIBUTE_NORMAL; /* do not store everything, but keep everything Samba can use */ - len = sprintf( hexattr, "0x%x", attr ); -- if (attr != 0) -+ if (attr != 0 || is_hidden_file( path )) - xattr_set( path, SAMBA_XATTR_DOS_ATTRIB, hexattr, len ); - else - xattr_remove( path, SAMBA_XATTR_DOS_ATTRIB ); --- -2.27.0 - diff --git a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/definition b/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/definition deleted file mode 100644 index 48c34b307..000000000 --- a/patches/wine-hotfixes/staging/ntdll-DOS_Attributes/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [9158] Support for DOS hidden/system file attributes -Fixes: [15679] cygwin symlinks not working in wine diff --git a/patches/wine-hotfixes/staging/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch b/patches/wine-hotfixes/staging/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch deleted file mode 100644 index 745c4ef12..000000000 --- a/patches/wine-hotfixes/staging/ntdll-Serial_Port_Detection/0001-ntdll-Do-a-device-check-before-returning-a-default-s.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0c71b9c48afdc0478941417595998ab21fcf12ae Mon Sep 17 00:00:00 2001 -From: Alex Henrie -Date: Tue, 29 Dec 2015 00:48:02 -0700 -Subject: [PATCH] mountmgr.sys: Do a device check before returning a default - serial port name. - -Fixes https://bugs.winehq.org/show_bug.cgi?id=39793 ---- - dlls/mountmgr.sys/device.c | 2 +- - dlls/mountmgr.sys/unixlib.c | 22 ++++++++++++++++++++++ - dlls/mountmgr.sys/unixlib.h | 1 + - 3 files changed, 24 insertions(+), 1 deletion(-) - -diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c -index 328b0b2f344..0757036c8e3 100644 ---- a/dlls/mountmgr.sys/device.c -+++ b/dlls/mountmgr.sys/device.c -@@ -1884,7 +1884,7 @@ static BOOL create_port_device( DRIVER_OBJECT *driver, int n, const char *unix_p - UNICODE_STRING nt_name, symlink_name, default_name; - DEVICE_OBJECT *dev_obj; - NTSTATUS status; -- struct set_dosdev_symlink_params params = { dosdevices_path, unix_path }; -+ struct set_dosdev_symlink_params params = { dosdevices_path, unix_path, driver == serial_driver }; - - /* create DOS device */ - if (MOUNTMGR_CALL( set_dosdev_symlink, ¶ms )) return FALSE; -diff --git a/dlls/mountmgr.sys/unixlib.c b/dlls/mountmgr.sys/unixlib.c -index 13f6fbecf09..0332f6f6018 100644 ---- a/dlls/mountmgr.sys/unixlib.c -+++ b/dlls/mountmgr.sys/unixlib.c -@@ -36,6 +36,7 @@ - #ifdef HAVE_SYS_STATVFS_H - # include - #endif -+#include - #include - - #include "unixlib.h" -@@ -304,6 +305,27 @@ static NTSTATUS set_dosdev_symlink( void *args ) - char *path; - NTSTATUS status = STATUS_SUCCESS; - -+#ifdef linux -+ /* Serial port device files almost always exist on Linux even if the corresponding serial -+ * ports don't exist. Do a basic functionality check before advertising a serial port. */ -+ if (params->serial) -+ { -+ struct termios tios; -+ int fd; -+ -+ if ((fd = open( params->dest, O_RDONLY )) == -1) -+ return FALSE; -+ -+ if (tcgetattr( fd, &tios ) == -1) -+ { -+ close( fd ); -+ return FALSE; -+ } -+ -+ close( fd ); -+ } -+#endif -+ - if (!(path = get_dosdevices_path( params->dev ))) return STATUS_NO_MEMORY; - - if (params->dest && params->dest[0]) -diff --git a/dlls/mountmgr.sys/unixlib.h b/dlls/mountmgr.sys/unixlib.h -index d70371876fa..ef5b10732f6 100644 ---- a/dlls/mountmgr.sys/unixlib.h -+++ b/dlls/mountmgr.sys/unixlib.h -@@ -90,6 +90,7 @@ struct set_dosdev_symlink_params - { - const char *dev; - const char *dest; -+ BOOL serial; - }; - - struct get_volume_dos_devices_params --- -2.37.2 - diff --git a/patches/wine-hotfixes/staging/ntdll-Serial_Port_Detection/definition b/patches/wine-hotfixes/staging/ntdll-Serial_Port_Detection/definition deleted file mode 100644 index 95fe42a7b..000000000 --- a/patches/wine-hotfixes/staging/ntdll-Serial_Port_Detection/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [39793] Do a device check before returning a default serial port name diff --git a/patches/wine-hotfixes/staging/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch b/patches/wine-hotfixes/staging/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch deleted file mode 100644 index 2e77c5647..000000000 --- a/patches/wine-hotfixes/staging/nvcuda/0016-nvcuda-Make-nvcuda-attempt-to-load-libcuda.so.1.patch +++ /dev/null @@ -1,29 +0,0 @@ -From c70b2b402ac1ca3a923822ddd2128a09ce5de81a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Sveinar=20S=C3=B8pler?= -Date: Mon, 24 Jan 2022 16:02:35 +0100 -Subject: [PATCH] nvcuda: Make nvcuda attempt to load libcuda.so.1 - -libcuda.so is not available when running under steam runtime -container. Adding this will make nvcuda attempt to load -libcuda.so.1 which will be available inside the steam runtime. ---- - dlls/nvcuda/nvcuda.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/nvcuda/nvcuda.c b/dlls/nvcuda/nvcuda.c -index 2cb3a0e2ecf..84da77941c6 100644 ---- a/dlls/nvcuda/nvcuda.c -+++ b/dlls/nvcuda/nvcuda.c -@@ -424,7 +424,8 @@ static BOOL load_functions(void) - "/usr/local/cuda/lib/libcuda.dylib", - "/usr/local/cuda/lib/libcuda.6.0.dylib", - #else -- "libcuda.so" -+ "libcuda.so", -+ "libcuda.so.1" - #endif - }; - int i; --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging/proton-staging-syscall-emu.patch b/patches/wine-hotfixes/staging/proton-staging-syscall-emu.patch deleted file mode 100644 index af4d9100d..000000000 --- a/patches/wine-hotfixes/staging/proton-staging-syscall-emu.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 76e0c24f410417973d784705c9729041af435929 Mon Sep 17 00:00:00 2001 -From: Tk-Glitch -Date: Fri, 2 Apr 2021 06:03:28 +0200 -Subject: protonify staging syscall emu - - -diff --git a/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch b/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch -index 014d6a46..46f04635 100644 ---- a/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch -+++ b/patches/ntdll-Syscall_Emulation/0001-ntdll-Support-x86_64-syscall-emulation.patch -@@ -5,12 +5,13 @@ Subject: [PATCH] ntdll: Support x86_64 syscall emulation. - - --- - configure.ac | 1 + -- dlls/ntdll/unix/signal_x86_64.c | 123 ++++++++++++++++++++++++++++++++ -+ dlls/ntdll/unix/signal_x86_64.c | 118 ++++++++++++++++++++++++++++++++ -+ include/config.h.in | 3 + - tools/winebuild/import.c | 3 +- -- 3 files changed, 125 insertions(+), 2 deletions(-) -+ 5 files changed, 125 insertions(+), 1 deletion(-) - - diff --git a/configure.ac b/configure.ac --index 5a5d88f10b0..7ae43b0c593 100644 -+index 6202d68ee45..bcc37745576 100644 - --- a/configure.ac - +++ b/configure.ac - @@ -448,6 +448,7 @@ AC_CHECK_HEADERS(\ -@@ -53,13 +54,14 @@ index 06d99545913..9a46b4a50b0 100644 - #define NONAMELESSUNION - #define NONAMELESSSTRUCT - #include "ntstatus.h" --@@ -2432,6 +2441,118 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) -+@@ -2344,6 +2352,119 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) - return 0; - } - - +#ifdef HAVE_SECCOMP - +static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext ) - +{ -++ ULONG64 *dispatcher_address = (ULONG64 *)((char *)user_shared_data + page_size); - + ucontext_t *ctx = sigcontext; - + void ***rsp; - + -@@ -70,7 +72,7 @@ index 06d99545913..9a46b4a50b0 100644 - + *rsp -= 1; - + **rsp = (void *)(ctx->uc_mcontext.gregs[REG_RIP] + 0xb); - + --+ ctx->uc_mcontext.gregs[REG_RIP] = (ULONG64)__wine_syscall_dispatcher; -++ ctx->uc_mcontext.gregs[REG_RIP] = *dispatcher_address; - +} - +#endif - + -@@ -172,7 +174,7 @@ index 06d99545913..9a46b4a50b0 100644 - - /*********************************************************************** - * handle_interrupt --@@ -3010,6 +3131,7 @@ void signal_init_process(void) -+@@ -2816,6 +2937,7 @@ void signal_init_process(void) - if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -@@ -188,8 +190,22 @@ index 06d99545913..9a46b4a50b0 100644 - "movq 0x18(%rcx),%rdx\n\t" - "movl %eax,%ebx\n\t" - "shrl $8,%ebx\n\t" -+diff --git a/include/config.h.in b/include/config.h.in -+index cf3aaa17a5d..b602a292eea 100644 -+--- a/include/config.h.in -++++ b/include/config.h.in -+@@ -450,6 +450,9 @@ -+ /* Define to 1 if you have the header file. */ -+ #undef HAVE_LINUX_RTNETLINK_H -+ -++/* Define to 1 if you have the header file. */ -++#undef HAVE_LINUX_SECCOMP_H -++ -+ /* Define to 1 if you have the header file. */ -+ #undef HAVE_LINUX_SERIAL_H -+ - diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c --index c876d51f8e6..37f1465a139 100644 -+index 720cf0589fd..9a7537451ae 100644 - --- a/tools/winebuild/import.c - +++ b/tools/winebuild/import.c - @@ -1366,7 +1366,6 @@ static int cmp_link_name( const void *e1, const void *e2 ) diff --git a/patches/wine-hotfixes/staging/server-Signal_Thread/0001-server-Do-not-signal-thread-until-it-is-really-gone.patch b/patches/wine-hotfixes/staging/server-Signal_Thread/0001-server-Do-not-signal-thread-until-it-is-really-gone.patch deleted file mode 100644 index 26cc29b70..000000000 --- a/patches/wine-hotfixes/staging/server-Signal_Thread/0001-server-Do-not-signal-thread-until-it-is-really-gone.patch +++ /dev/null @@ -1,114 +0,0 @@ -From f649ffcd8f68f82be173367b66f3c505ff75bcc3 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Mon, 12 Nov 2018 18:10:32 +0200 -Subject: [PATCH] server: Do not signal violently terminated threads until they - are really gone -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -When a thread is terminated violently (such as by using TerminateThread) -that is not the current thread, the server sends a signal to the thread to -terminate it, but it immediately wakes up anything waiting on it. The caller -can expect WaitForSingleObject (or similar) to return when the thread is -really gone and doesn't execute anything anymore, and this is exactly what -happens on Windows. - -If that thread was altering global state, and the thread that was waiting -on it will read (or alter) the global state *after* waiting for it and -expecting it to not change (because it assumes the thread is terminated by -that point, as on Windows), the result will be a race condition, since there's -no guarantee currently that the terminated thread really stopped executing. - -Signed-off-by: Gabriel Ivăncescu ---- - server/thread.c | 32 +++++++++++++++++++++++++++++--- - server/thread.h | 1 + - 2 files changed, 30 insertions(+), 3 deletions(-) - -diff --git a/server/thread.c b/server/thread.c -index 55386192fe6..60cd4ee16a8 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -241,6 +241,7 @@ static inline void init_thread_structure( struct thread *thread ) - thread->queue_shared = NULL; - thread->input_shared_mapping = NULL; - thread->input_shared = NULL; -+ thread->exit_poll = NULL; - - thread->creation_time = current_time; - thread->exit_time = 0; -@@ -431,6 +432,7 @@ static void destroy_thread( struct object *obj ) - list_remove( &thread->entry ); - cleanup_thread( thread ); - release_object( thread->process ); -+ if (thread->exit_poll) remove_timeout_user( thread->exit_poll ); - if (thread->id) free_ptid( thread->id ); - if (thread->token) release_object( thread->token ); - } -@@ -455,7 +457,7 @@ static struct object_type *thread_get_type( struct object *obj ) - static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ) - { - struct thread *mythread = (struct thread *)obj; -- return (mythread->state == TERMINATED); -+ return mythread->state == TERMINATED && !mythread->exit_poll; - } - - static unsigned int thread_map_access( struct object *obj, unsigned int access ) -@@ -1249,6 +1251,26 @@ int thread_get_inflight_fd( struct thread *thread, int client ) - return -1; - } - -+static void check_terminated( void *arg ) -+{ -+ struct thread *thread = arg; -+ assert( thread->obj.ops == &thread_ops ); -+ assert( thread->state == TERMINATED ); -+ -+ /* don't wake up until the thread is really dead, to avoid race conditions */ -+ if (thread->unix_tid != -1 && !kill( thread->unix_tid, 0 )) -+ { -+ thread->exit_poll = add_timeout_user( -TICKS_PER_SEC / 1000, check_terminated, thread ); -+ return; -+ } -+ -+ /* grab reference since object can be destroyed while trying to wake up */ -+ grab_object( &thread->obj ); -+ thread->exit_poll = NULL; -+ wake_up( &thread->obj, 0 ); -+ release_object( &thread->obj ); -+} -+ - /* kill a thread on the spot */ - void kill_thread( struct thread *thread, int violent_death ) - { -@@ -1268,8 +1290,12 @@ void kill_thread( struct thread *thread, int violent_death ) - fsync_abandon_mutexes( thread ); - if (do_esync()) - esync_abandon_mutexes( thread ); -- wake_up( &thread->obj, 0 ); -- if (violent_death) send_thread_signal( thread, SIGQUIT ); -+ if (violent_death) -+ { -+ send_thread_signal( thread, SIGQUIT ); -+ check_terminated( thread ); -+ } -+ else wake_up( &thread->obj, 0 ); - cleanup_thread( thread ); - remove_process_thread( thread->process, thread ); - release_object( thread ); -diff --git a/server/thread.h b/server/thread.h -index 184fa92d250..077ab0929ba 100644 ---- a/server/thread.h -+++ b/server/thread.h -@@ -90,6 +90,7 @@ struct thread - struct list kernel_object; /* list of kernel object pointers */ - data_size_t desc_len; /* thread description length in bytes */ - WCHAR *desc; /* thread description string */ -+ struct timeout_user *exit_poll; /* poll if the thread/process has exited already */ - struct object *locked_completion; /* completion port wait object successfully waited by the thread */ - struct object *queue_shared_mapping; /* thread queue shared memory mapping */ - volatile struct queue_shared_memory *queue_shared; /* thread queue shared memory ptr */ --- -2.29.2 - diff --git a/patches/wine-hotfixes/staging/server-Signal_Thread/definition b/patches/wine-hotfixes/staging/server-Signal_Thread/definition deleted file mode 100644 index ef65e975d..000000000 --- a/patches/wine-hotfixes/staging/server-Signal_Thread/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: Do not signal threads until they are really gone diff --git a/patches/wine-hotfixes/staging/server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch b/patches/wine-hotfixes/staging/server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch deleted file mode 100644 index f92eeac74..000000000 --- a/patches/wine-hotfixes/staging/server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 9804dd77fd8c0ec56963306f409fea6b910bb48d Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Sun, 7 Feb 2021 22:54:19 -0600 -Subject: [PATCH] server: Create processes using a limited administrator token - by default. - -Signed-off-by: Zebediah Figura ---- - server/process.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/server/process.c b/server/process.c -index 15387a2affa..3a8bbdbfb2e 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -664,7 +664,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla - if (!parent) - { - process->handles = alloc_handle_table( process, 0 ); -- process->token = token_create_admin( TRUE, -1, TokenElevationTypeFull, default_session_id ); -+ process->token = token_create_admin( TRUE, -1, TokenElevationTypeLimited, default_session_id ); - process->affinity = ~0; - } - else --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/server-default_integrity/0002-shell32-Implement-the-runas-verb.patch b/patches/wine-hotfixes/staging/server-default_integrity/0002-shell32-Implement-the-runas-verb.patch deleted file mode 100644 index 0f53ba56f..000000000 --- a/patches/wine-hotfixes/staging/server-default_integrity/0002-shell32-Implement-the-runas-verb.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 5b1f4126d7eed65f68fb46bec05b226d75ce63e5 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Fri, 26 Feb 2021 22:31:19 -0600 -Subject: [PATCH] shell32: Implement the "runas" verb. -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Based on a patch by Michael Müller. - -Signed-off-by: Zebediah Figura ---- - dlls/shell32/shlexec.c | 26 ++++++++++++++++++++++++-- - 1 file changed, 24 insertions(+), 2 deletions(-) - -diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c -index ba393ad7794..f6e108fd6bf 100644 ---- a/dlls/shell32/shlexec.c -+++ b/dlls/shell32/shlexec.c -@@ -299,6 +299,21 @@ static HRESULT SHELL_GetPathFromIDListForExecuteW(LPCITEMIDLIST pidl, LPWSTR psz - return hr; - } - -+static HANDLE get_admin_token(void) -+{ -+ TOKEN_ELEVATION_TYPE type; -+ TOKEN_LINKED_TOKEN linked; -+ DWORD size; -+ -+ if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenElevationType, &type, sizeof(type), &size) -+ || type == TokenElevationTypeFull) -+ return NULL; -+ -+ if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenLinkedToken, &linked, sizeof(linked), &size)) -+ return NULL; -+ return linked.LinkedToken; -+} -+ - /************************************************************************* - * SHELL_ExecuteW [Internal] - * -@@ -312,6 +327,7 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, - UINT gcdret = 0; - WCHAR curdir[MAX_PATH]; - DWORD dwCreationFlags; -+ HANDLE token = NULL; - - TRACE("Execute %s from directory %s\n", debugstr_w(lpCmd), debugstr_w(psei->lpDirectory)); - -@@ -333,8 +349,12 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, - dwCreationFlags = CREATE_UNICODE_ENVIRONMENT; - if (!(psei->fMask & SEE_MASK_NO_CONSOLE)) - dwCreationFlags |= CREATE_NEW_CONSOLE; -- if (CreateProcessW(NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, dwCreationFlags, env, -- NULL, &startup, &info)) -+ -+ if (psei->lpVerb && !wcsicmp(psei->lpVerb, L"runas")) -+ token = get_admin_token(); -+ -+ if (CreateProcessAsUserW(token, NULL, (LPWSTR)lpCmd, NULL, NULL, FALSE, -+ dwCreationFlags, env, NULL, &startup, &info)) - { - /* Give 30 seconds to the app to come up, if desired. Probably only needed - when starting app immediately before making a DDE connection. */ -@@ -354,6 +374,8 @@ static UINT_PTR SHELL_ExecuteW(const WCHAR *lpCmd, WCHAR *env, BOOL shWait, - retval = ERROR_BAD_FORMAT; - } - -+ CloseHandle(token); -+ - TRACE("returning %lu\n", retval); - - psei_out->hInstApp = (HINSTANCE)retval; --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging/server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch b/patches/wine-hotfixes/staging/server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch deleted file mode 100644 index 8b0ccf789..000000000 --- a/patches/wine-hotfixes/staging/server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch +++ /dev/null @@ -1,29 +0,0 @@ -From dc1f602da6ed3a574697fe8b5bc4590d74e344f5 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Fri, 26 Feb 2021 22:41:35 -0600 -Subject: [PATCH] wine.inf: Set the EnableLUA value to 1. - -This signifies that UAC is active. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50727 -Signed-off-by: Zebediah Figura ---- - loader/wine.inf.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 24da6f3af6b..a72279e9881 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -526,7 +526,7 @@ HKLM,%CurrentVersion%\Explorer\DriveIcons,,16 - HKLM,%CurrentVersion%\Explorer\KindMap,,16 - HKLM,%CurrentVersion%\Group Policy,,16 - HKLM,%CurrentVersion%\Installer,"InstallerLocation",,"%11%" --HKLM,%CurrentVersion%\Policies\System,"EnableLUA",0x10003,0 -+HKLM,%CurrentVersion%\Policies\System,"EnableLUA",0x10001,1 - HKLM,%CurrentVersion%\PreviewHandlers,,16 - HKLM,%CurrentVersion%\Run,,16 - HKLM,%CurrentVersion%\Setup,"BootDir",,"%30%" --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch b/patches/wine-hotfixes/staging/server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch deleted file mode 100644 index 476725ba4..000000000 --- a/patches/wine-hotfixes/staging/server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch +++ /dev/null @@ -1,68 +0,0 @@ -From f2de1c5d2fcda876276e077b61f9fba5ff3f7f12 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Sun, 16 May 2021 20:49:05 -0500 -Subject: [PATCH] msi: Create the custom action server as an elevated process. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51143 -Signed-off-by: Zebediah Figura ---- - dlls/msi/custom.c | 24 ++++++++++++++++++++++-- - 1 file changed, 22 insertions(+), 2 deletions(-) - -diff --git a/dlls/msi/custom.c b/dlls/msi/custom.c -index fb03958eb11..874b9b92118 100644 ---- a/dlls/msi/custom.c -+++ b/dlls/msi/custom.c -@@ -574,12 +574,28 @@ UINT CDECL __wine_msi_call_dll_function(DWORD client_pid, const GUID *guid) - return r; - } - -+static HANDLE get_admin_token(void) -+{ -+ TOKEN_ELEVATION_TYPE type; -+ TOKEN_LINKED_TOKEN linked; -+ DWORD size; -+ -+ if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenElevationType, &type, sizeof(type), &size) -+ || type == TokenElevationTypeFull) -+ return NULL; -+ -+ if (!GetTokenInformation(GetCurrentThreadEffectiveToken(), TokenLinkedToken, &linked, sizeof(linked), &size)) -+ return NULL; -+ return linked.LinkedToken; -+} -+ - static DWORD custom_start_server(MSIPACKAGE *package, DWORD arch) - { - WCHAR path[MAX_PATH], cmdline[MAX_PATH + 23]; - PROCESS_INFORMATION pi = {0}; - STARTUPINFOW si = {0}; - WCHAR buffer[24]; -+ HANDLE token; - void *cookie; - HANDLE pipe; - -@@ -601,14 +617,18 @@ static DWORD custom_start_server(MSIPACKAGE *package, DWORD arch) - lstrcatW(path, L"\\msiexec.exe"); - swprintf(cmdline, ARRAY_SIZE(cmdline), L"%s -Embedding %d", path, GetCurrentProcessId()); - -+ token = get_admin_token(); -+ - if (is_wow64 && arch == SCS_64BIT_BINARY) - { - Wow64DisableWow64FsRedirection(&cookie); -- CreateProcessW(path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); -+ CreateProcessAsUserW(token, path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - Wow64RevertWow64FsRedirection(cookie); - } - else -- CreateProcessW(path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); -+ CreateProcessAsUserW(token, path, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); -+ -+ if (token) CloseHandle(token); - - CloseHandle(pi.hThread); - --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch b/patches/wine-hotfixes/staging/server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch deleted file mode 100644 index e6ad033a9..000000000 --- a/patches/wine-hotfixes/staging/server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch +++ /dev/null @@ -1,50 +0,0 @@ -From b08427ea0575faf213100269bf5bc931ec05930b Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Fri, 21 May 2021 21:52:06 -0500 -Subject: [PATCH] ntdll: Always start the initial process through start.exe. - -Signed-off-by: Zebediah Figura ---- - dlls/ntdll/unix/env.c | 19 +++---------------- - 1 file changed, 3 insertions(+), 16 deletions(-) - -diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c -index ae1afb2797b..02af2c5ca5a 100644 ---- a/dlls/ntdll/unix/env.c -+++ b/dlls/ntdll/unix/env.c -@@ -2116,6 +2116,7 @@ static void init_peb( RTL_USER_PROCESS_PARAMETERS *params, void *module ) - */ - static RTL_USER_PROCESS_PARAMETERS *build_initial_params( void **module ) - { -+ static const char *args[] = { "start.exe", "/exec" }; - static const WCHAR valueW[] = {'1',0}; - static const WCHAR pathW[] = {'P','A','T','H'}; - RTL_USER_PROCESS_PARAMETERS *params = NULL; -@@ -2144,22 +2145,8 @@ static RTL_USER_PROCESS_PARAMETERS *build_initial_params( void **module ) - add_registry_environment( &env, &env_pos, &env_size ); - env[env_pos++] = 0; - -- status = load_main_exe( NULL, main_argv[1], curdir, &image, module ); -- if (!status) -- { -- if (main_image_info.ImageCharacteristics & IMAGE_FILE_DLL) status = STATUS_INVALID_IMAGE_FORMAT; -- if (main_image_info.Machine != current_machine) status = STATUS_INVALID_IMAGE_FORMAT; -- } -- -- if (status) /* try launching it through start.exe */ -- { -- static const char *args[] = { "start.exe", "/exec" }; -- free( image ); -- if (*module) NtUnmapViewOfSection( GetCurrentProcess(), *module ); -- load_start_exe( &image, module ); -- prepend_argv( args, 2 ); -- } -- else rebuild_argv(); -+ load_start_exe( &image, module ); -+ prepend_argv( args, 2 ); - - main_wargv = build_wargv( get_dos_path( image )); - cmdline = build_command_line( main_wargv ); --- -2.32.0 - diff --git a/patches/wine-hotfixes/staging/server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch b/patches/wine-hotfixes/staging/server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch deleted file mode 100644 index 31afa206d..000000000 --- a/patches/wine-hotfixes/staging/server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch +++ /dev/null @@ -1,110 +0,0 @@ -From e695c71722c3ecf8b2666da109dfe172e50f75da Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Sun, 18 Apr 2021 17:46:35 -0500 -Subject: [PATCH] kernelbase: Elevate processes if requested in - CreateProcessInternal(). - -Signed-off-by: Zebediah Figura ---- - dlls/kernelbase/process.c | 57 +++++++++++++++++++++++++++++++++++++-- - 1 file changed, 55 insertions(+), 2 deletions(-) - -diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c -index ab89d3bcf31..270951a795e 100644 ---- a/dlls/kernelbase/process.c -+++ b/dlls/kernelbase/process.c -@@ -30,6 +30,7 @@ - #include "winnls.h" - #include "wincontypes.h" - #include "winternl.h" -+#include "winuser.h" - - #include "kernelbase.h" - #include "wine/debug.h" -@@ -413,6 +414,54 @@ BOOL WINAPI DECLSPEC_HOTPATCH CloseHandle( HANDLE handle ) - } - - -+static BOOL image_needs_elevation( const WCHAR *path ) -+{ -+ ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION run_level; -+ BOOL ret = FALSE; -+ HANDLE handle; -+ ACTCTXW ctx; -+ -+ ctx.cbSize = sizeof(ctx); -+ ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; -+ ctx.lpSource = path; -+ ctx.lpResourceName = (const WCHAR *)CREATEPROCESS_MANIFEST_RESOURCE_ID; -+ -+ if (RtlCreateActivationContext( &handle, &ctx )) return FALSE; -+ -+ if (!RtlQueryInformationActivationContext( 0, handle, NULL, RunlevelInformationInActivationContext, -+ &run_level, sizeof(run_level), NULL )) -+ { -+ TRACE( "image requested run level %#x\n", run_level.RunLevel ); -+ if (run_level.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE -+ || run_level.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN) -+ ret = TRUE; -+ } -+ RtlReleaseActivationContext( handle ); -+ -+ return ret; -+} -+ -+ -+static HANDLE get_elevated_token(void) -+{ -+ TOKEN_ELEVATION_TYPE type; -+ TOKEN_LINKED_TOKEN linked; -+ NTSTATUS status; -+ -+ if ((status = NtQueryInformationToken( GetCurrentThreadEffectiveToken(), -+ TokenElevationType, &type, sizeof(type), NULL ))) -+ return NULL; -+ -+ if (type == TokenElevationTypeFull) return NULL; -+ -+ if ((status = NtQueryInformationToken( GetCurrentThreadEffectiveToken(), -+ TokenLinkedToken, &linked, sizeof(linked), NULL ))) -+ return NULL; -+ -+ return linked.LinkedToken; -+} -+ -+ - /********************************************************************** - * CreateProcessAsUserA (kernelbase.@) - */ -@@ -548,7 +597,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - WCHAR *p, *tidy_cmdline = cmd_line; - RTL_USER_PROCESS_PARAMETERS *params = NULL; - RTL_USER_PROCESS_INFORMATION rtl_info; -- HANDLE parent = 0, debug = 0; -+ HANDLE parent = 0, debug = 0, elevated_token = NULL; - const WCHAR *append; - ULONG nt_flags = 0; - NTSTATUS status; -@@ -607,6 +656,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - if (flags & CREATE_BREAKAWAY_FROM_JOB) nt_flags |= PROCESS_CREATE_FLAGS_BREAKAWAY; - if (flags & CREATE_SUSPENDED) nt_flags |= PROCESS_CREATE_FLAGS_SUSPENDED; - -+ if (!token && image_needs_elevation( params->ImagePathName.Buffer )) -+ token = elevated_token = get_elevated_token(); -+ - status = create_nt_process( token, debug, process_attr, thread_attr, - nt_flags, params, &rtl_info, parent, handle_list, job_list ); - switch (status) -@@ -648,7 +700,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessInternalW( HANDLE token, const WCHAR - TRACE( "started process pid %04x tid %04x\n", info->dwProcessId, info->dwThreadId ); - } - -- done: -+done: -+ if (elevated_token) NtClose( elevated_token ); - RtlDestroyProcessParameters( params ); - if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline ); - return set_ntstatus( status ); --- -2.30.2 - diff --git a/patches/wine-hotfixes/staging/server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch b/patches/wine-hotfixes/staging/server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch deleted file mode 100644 index a0b944389..000000000 --- a/patches/wine-hotfixes/staging/server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch +++ /dev/null @@ -1,127 +0,0 @@ -From 20e95575948faec1eca2e88967e985539a512cd5 Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Sun, 18 Apr 2021 17:46:44 -0500 -Subject: [PATCH] ntdll: Elevate processes if requested in - RtlCreateUserProcess(). - -Signed-off-by: Zebediah Figura ---- - dlls/ntdll/process.c | 79 +++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 74 insertions(+), 5 deletions(-) - -diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c -index 160b1f549c9..fd437ea07d4 100644 ---- a/dlls/ntdll/process.c -+++ b/dlls/ntdll/process.c -@@ -39,6 +39,9 @@ - WINE_DEFAULT_DEBUG_CHANNEL(process); - - -+/* we don't want to include winuser.h */ -+#define CREATEPROCESS_MANIFEST_RESOURCE_ID ((ULONG_PTR)1) -+ - /****************************************************************************** - * RtlGetCurrentPeb [NTDLL.@] - * -@@ -82,6 +85,63 @@ NTSTATUS WINAPI RtlWow64EnableFsRedirectionEx( ULONG disable, ULONG *old_value ) - } - - -+static BOOL image_needs_elevation( const UNICODE_STRING *path ) -+{ -+ ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION run_level; -+ UNICODE_STRING path0; -+ BOOL ret = FALSE; -+ HANDLE handle; -+ ACTCTXW ctx; -+ -+ if (RtlDuplicateUnicodeString( 1, path, &path0 )) -+ return FALSE; -+ -+ ctx.cbSize = sizeof(ctx); -+ ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; -+ ctx.lpSource = path0.Buffer; -+ ctx.lpResourceName = (const WCHAR *)CREATEPROCESS_MANIFEST_RESOURCE_ID; -+ -+ if (RtlCreateActivationContext( &handle, &ctx )) -+ { -+ RtlFreeUnicodeString( &path0 ); -+ return FALSE; -+ } -+ -+ if (!RtlQueryInformationActivationContext( 0, handle, NULL, RunlevelInformationInActivationContext, -+ &run_level, sizeof(run_level), NULL )) -+ { -+ TRACE( "image requested run level %#x\n", run_level.RunLevel ); -+ if (run_level.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE -+ || run_level.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN) -+ ret = TRUE; -+ } -+ RtlReleaseActivationContext( handle ); -+ RtlFreeUnicodeString( &path0 ); -+ return ret; -+} -+ -+ -+static HANDLE get_elevated_token(void) -+{ -+ TOKEN_ELEVATION_TYPE type; -+ TOKEN_LINKED_TOKEN linked; -+ NTSTATUS status; -+ -+ if ((status = NtQueryInformationToken( GetCurrentThreadEffectiveToken(), -+ TokenElevationType, &type, sizeof(type), NULL ))) -+ return NULL; -+ -+ if (type == TokenElevationTypeFull) return NULL; -+ -+ -+ if ((status = NtQueryInformationToken( GetCurrentThreadEffectiveToken(), -+ TokenLinkedToken, &linked, sizeof(linked), NULL ))) -+ return NULL; -+ -+ return linked.LinkedToken; -+} -+ -+ - /********************************************************************** - * RtlWow64GetCurrentMachine (NTDLL.@) - */ -@@ -294,8 +354,15 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes, - PS_CREATE_INFO create_info; - ULONG_PTR buffer[offsetof( PS_ATTRIBUTE_LIST, Attributes[6] ) / sizeof(ULONG_PTR)]; - PS_ATTRIBUTE_LIST *attr = (PS_ATTRIBUTE_LIST *)buffer; -+ HANDLE elevated_token = NULL; -+ NTSTATUS status; - UINT pos = 0; - -+ /* It's not clear whether we should use path or ¶ms->ImagePathName here, -+ * but Roblox Player tries to pass an empty string for the latter. */ -+ if (!token && image_needs_elevation( path )) -+ token = elevated_token = get_elevated_token(); -+ - RtlNormalizeProcessParams( params ); - - attr->Attributes[pos].Attribute = PS_ATTRIBUTE_IMAGE_NAME; -@@ -342,11 +409,13 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes, - InitializeObjectAttributes( &process_attr, NULL, 0, NULL, process_descr ); - InitializeObjectAttributes( &thread_attr, NULL, 0, NULL, thread_descr ); - -- return NtCreateUserProcess( &info->Process, &info->Thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, -- &process_attr, &thread_attr, -- inherit ? PROCESS_CREATE_FLAGS_INHERIT_HANDLES : 0, -- THREAD_CREATE_FLAGS_CREATE_SUSPENDED, params, -- &create_info, attr ); -+ status = NtCreateUserProcess( &info->Process, &info->Thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS, -+ &process_attr, &thread_attr, -+ inherit ? PROCESS_CREATE_FLAGS_INHERIT_HANDLES : 0, -+ THREAD_CREATE_FLAGS_CREATE_SUSPENDED, params, &create_info, attr ); -+ -+ if (elevated_token) NtClose( elevated_token ); -+ return status; - } - - /*********************************************************************** --- -2.32.0 - diff --git a/patches/wine-hotfixes/staging/server-default_integrity/definition b/patches/wine-hotfixes/staging/server-default_integrity/definition deleted file mode 100644 index 31f971cad..000000000 --- a/patches/wine-hotfixes/staging/server-default_integrity/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [40613] Multiple applications require UAC implementation to run installer/app as a normal user instead of administrator (WhatsApp Desktop, Smartflix, Squirrel Installers, OneDrive) -Fixes: [39262] DiscordSetup.exe (.NET 4.5.2 app): Squirrell installer requires being run as unelevated process ('explorer.exe' should run unelevated by default with Vista+ setting) diff --git a/patches/wine-hotfixes/staging/staging-esync_remove_ntdll_Junction_Points_dependency.patch b/patches/wine-hotfixes/staging/staging-esync_remove_ntdll_Junction_Points_dependency.patch deleted file mode 100644 index 22e241f09..000000000 --- a/patches/wine-hotfixes/staging/staging-esync_remove_ntdll_Junction_Points_dependency.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 64a9d9fad97ae0d3ad45ad44390fc5276845d2aa Mon Sep 17 00:00:00 2001 -From: Tk-Glitch -Date: Tue, 2 Nov 2021 12:41:27 +0100 -Subject: Allow for disabling ntdll-Junction_Points, server-File_Permissions and server-Stored_ACLs staging patchsets - -Those are dependencies for eventfd_synchronization in current staging - - -diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh -index 114e663c..b50c06f4 100755 ---- a/patches/patchinstall.sh -+++ b/patches/patchinstall.sh -@@ -1314,9 +1314,6 @@ if test "$enable_winedevice_Default_Drivers" -eq 1; then - fi - - if test "$enable_eventfd_synchronization" -eq 1; then -- if test "$enable_ntdll_Junction_Points" -gt 1; then -- abort "Patchset ntdll-Junction_Points disabled, but eventfd_synchronization depends on that." -- fi - if test "$enable_server_PeekMessage" -gt 1; then - abort "Patchset server-PeekMessage disabled, but eventfd_synchronization depends on that." - fi -@@ -1326,7 +1323,6 @@ if test "$enable_eventfd_synchronization" -eq 1; then - if test "$enable_server_Signal_Thread" -gt 1; then - abort "Patchset server-Signal_Thread disabled, but eventfd_synchronization depends on that." - fi -- enable_ntdll_Junction_Points=1 - enable_server_PeekMessage=1 - enable_server_Realtime_Priority=1 - enable_server_Signal_Thread=1 -diff --git a/patches/eventfd_synchronization/0046-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch b/patches/eventfd_synchronization/0046-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch -index 18dfad0f..f05ef0bb 100644 ---- a/patches/eventfd_synchronization/0046-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch -+++ b/patches/eventfd_synchronization/0046-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch -@@ -31,7 +31,7 @@ index 880a5037925..c6db8d13265 100644 - - static void fd_dump( struct object *obj, int verbose ); - @@ -1606,6 +1608,9 @@ static void fd_destroy( struct object *obj ) -- free( fd->unlink_name ); -+ if (fd->unix_fd != -1) close( fd->unix_fd ); - free( fd->unix_name ); - } - + - diff --git a/patches/wine-hotfixes/staging/staging-revert-user32-msgbox.patch b/patches/wine-hotfixes/staging/staging-revert-user32-msgbox.patch deleted file mode 100644 index 3f6a9a23d..000000000 --- a/patches/wine-hotfixes/staging/staging-revert-user32-msgbox.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff --git a/patches/user32-msgbox-Support-WM_COPY-mesg/0002-user32-msgbox-Use-a-windows-hook-to-trap-Ctrl-C.patch b/patches/user32-msgbox-Support-WM_COPY-mesg/0002-user32-msgbox-Use-a-windows-hook-to-trap-Ctrl-C.patch -index c9d8da655..ec3df53d0 100644 ---- a/patches/user32-msgbox-Support-WM_COPY-mesg/0002-user32-msgbox-Use-a-windows-hook-to-trap-Ctrl-C.patch -+++ b/patches/user32-msgbox-Support-WM_COPY-mesg/0002-user32-msgbox-Use-a-windows-hook-to-trap-Ctrl-C.patch -@@ -1,4 +1,4 @@ --From 455aefaf6f4e5b3b631722be3ad0911dbe015952 Mon Sep 17 00:00:00 2001 -+From 05f0a7d14311569807af62cc87780a67cb26194a Mon Sep 17 00:00:00 2001 - From: Alistair Leslie-Hughes - Date: Thu, 10 Jan 2019 16:17:33 +1100 - Subject: [PATCH] user32/msgbox: Use a windows hook to trap Ctrl+C -@@ -8,7 +8,7 @@ Subject: [PATCH] user32/msgbox: Use a windows hook to trap Ctrl+C - 1 file changed, 20 insertions(+) - - diff --git a/dlls/user32/msgbox.c b/dlls/user32/msgbox.c --index d47d9eaac22..db036b28b69 100644 -+index d47d9eaac22..cf00d69df69 100644 - --- a/dlls/user32/msgbox.c - +++ b/dlls/user32/msgbox.c - @@ -388,6 +388,22 @@ static void MSGBOX_CopyToClipbaord( HWND hwnd ) -@@ -28,7 +28,7 @@ index d47d9eaac22..db036b28b69 100644 - + } - + } - + --+ return CallNextHookEx(msghook_handle, nCode, wParam, lParam); -++ return NtUserCallNextHookEx(msghook_handle, nCode, wParam, lParam); - +} - + - /************************************************************************** -@@ -53,5 +53,5 @@ index d47d9eaac22..db036b28b69 100644 - case WM_COMMAND: - switch (LOWORD(wParam)) - -- --2.34.1 -+2.35.1 diff --git a/patches/wine-hotfixes/staging/staging-server-default-integrity.patch b/patches/wine-hotfixes/staging/staging-server-default-integrity.patch deleted file mode 100644 index 23dc6ead1..000000000 --- a/patches/wine-hotfixes/staging/staging-server-default-integrity.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh -index 97b65fafd..44061a2c1 100755 ---- a/patches/patchinstall.sh -+++ b/patches/patchinstall.sh -@@ -3070,13 +3070,17 @@ fi - # | should run unelevated by default with Vista+ setting) - # | - # | Modified files: --# | * dlls/msi/custom.c, dlls/shell32/shlexec.c, loader/wine.inf.in, server/process.c -+# | * dlls/kernelbase/process.c, dlls/msi/custom.c, dlls/ntdll/process.c, dlls/ntdll/unix/env.c, dlls/shell32/shlexec.c, -+# | loader/wine.inf.in, server/process.c - # | - if test "$enable_server_default_integrity" -eq 1; then - patch_apply server-default_integrity/0001-server-Create-processes-using-a-limited-administrato.patch - patch_apply server-default_integrity/0002-shell32-Implement-the-runas-verb.patch - patch_apply server-default_integrity/0003-wine.inf-Set-the-EnableLUA-value-to-1.patch - patch_apply server-default_integrity/0004-msi-Create-the-custom-action-server-as-an-elevated-p.patch -+ patch_apply server-default_integrity/0005-ntdll-Always-start-the-initial-process-through-start.patch -+ patch_apply server-default_integrity/0006-kernelbase-Elevate-processes-if-requested-in-CreateP.patch -+ patch_apply server-default_integrity/0007-ntdll-Elevate-processes-if-requested-in-RtlCreateUse.patch - fi - - # Patchset setupapi-DiskSpaceList diff --git a/patches/wine-hotfixes/staging/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch b/patches/wine-hotfixes/staging/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch deleted file mode 100644 index 734db8878..000000000 --- a/patches/wine-hotfixes/staging/winemenubuilder-Desktop_Icon_Path/0001-winemenubuilder-Create-desktop-shortcuts-with-absolu.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 38af730d23f017ce256d3f2cc81e96402112ca7b Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Wed, 24 Sep 2014 21:13:59 +0200 -Subject: [PATCH] winemenubuilder: Create desktop shortcuts with absolute wine - path. - -When having multiple wine versions installed (for example regular wine and wine staging), the desktop -shortcuts will always run regular wine, even if the app was installed with wine staging. This patch -changes the behaviour to use the absolute wine path in desktop shortcuts. The patch only modifies the -behaviour on Linux, because some other distros are a bit special (FreeBSD requires a wrapper to start -wine, and so on ...). ---- - programs/winemenubuilder/Makefile.in | 1 + - programs/winemenubuilder/winemenubuilder.c | 12 ++++++++++-- - 2 files changed, 11 insertions(+), 2 deletions(-) - -diff --git a/programs/winemenubuilder/Makefile.in b/programs/winemenubuilder/Makefile.in -index 12326d1e4e2..07191b56d82 100644 ---- a/programs/winemenubuilder/Makefile.in -+++ b/programs/winemenubuilder/Makefile.in -@@ -1,5 +1,6 @@ - MODULE = winemenubuilder.exe - IMPORTS = uuid windowscodecs shell32 shlwapi ole32 user32 advapi32 -+EXTRADEFS = -DBINDIR="\"${bindir}\"" - - EXTRADLLFLAGS = -mwindows -municode - -diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c -index ab8798a88b5..31c97107802 100644 ---- a/programs/winemenubuilder/winemenubuilder.c -+++ b/programs/winemenubuilder/winemenubuilder.c -@@ -97,6 +97,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(menubuilder); - #define IS_OPTION_TRUE(ch) \ - ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') - -+/* On linux we create all menu item entries with an absolute path to wine, -+ * in order to allow using multiple wine versions at the same time. */ -+#ifdef __linux__ -+ static const char wine_path[] = BINDIR "/wine"; -+#else -+ static const char wine_path[] = "wine"; -+#endif -+ - /* link file formats */ - - #include "pshpack1.h" -@@ -1275,7 +1283,7 @@ static BOOL write_desktop_entry(const WCHAR *link, const WCHAR *location, const - fprintf(file, "env WINEPREFIX=\"%s\" ", path); - heap_free( path ); - } -- fprintf(file, "wine %s", escape(path)); -+ fprintf(file, "%s %s", wine_path, escape(path)); - if (args) fprintf(file, " %s", escape(args) ); - fputc( '\n', file ); - fprintf(file, "Type=Application\n"); -@@ -1985,7 +1993,7 @@ static BOOL write_freedesktop_association_entry(const WCHAR *desktopPath, const - if (prefix) - { - char *path = wine_get_unix_file_name( prefix ); -- fprintf(desktop, "Exec=env WINEPREFIX=\"%s\" wine start /ProgIDOpen %s %%f\n", path, escape(progId)); -+ fprintf(desktop, "Exec=env WINEPREFIX=\"%s\" %s start /ProgIDOpen %s %%f\n", path, wine_path, escape(progId)); - heap_free( path ); - } - else --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging/winemenubuilder-integration/0001-winemenubuilder-Blacklist-desktop-integration-for-ce.patch b/patches/wine-hotfixes/staging/winemenubuilder-integration/0001-winemenubuilder-Blacklist-desktop-integration-for-ce.patch deleted file mode 100644 index f3b1da782..000000000 --- a/patches/wine-hotfixes/staging/winemenubuilder-integration/0001-winemenubuilder-Blacklist-desktop-integration-for-ce.patch +++ /dev/null @@ -1,174 +0,0 @@ -From d83180d032eee8c3ec72c22fc2706d8b7231090e Mon Sep 17 00:00:00 2001 -From: Alex Henrie -Date: Sun, 1 Mar 2020 17:58:12 -0700 -Subject: [PATCH] winemenubuilder: Blacklist desktop integration for certain - associations - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=41275 -Signed-off-by: Alex Henrie ---- - dlls/mshtml/mshtml.inf | 6 +++ - loader/wine.inf.in | 10 +++++ - programs/winemenubuilder/winemenubuilder.c | 52 +++++++++++++++++++--- - 3 files changed, 62 insertions(+), 6 deletions(-) - -diff --git a/dlls/mshtml/mshtml.inf b/dlls/mshtml/mshtml.inf -index 4a650b444fc..548739f4326 100644 ---- a/dlls/mshtml/mshtml.inf -+++ b/dlls/mshtml/mshtml.inf -@@ -111,6 +111,7 @@ HKCR,"giffile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," - HKCR,"giffile\shell\open\ddeexec\Application",,,"IExplore" - HKCR,"giffile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" - ;; HKCR,"giffile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,9" -+HKCU,Software\Wine\FileOpenBlacklist\.gif,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" - - ;; GZIP - HKCR,"MIME\Database\Content Type\application/x-gzip","Extension",,".gz" -@@ -158,6 +159,7 @@ HKCR,"jpegfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," - HKCR,"jpegfile\shell\open\ddeexec\Application",,,"IExplore" - HKCR,"jpegfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" - ;; HKCR,"jpegfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,8" -+HKCU,Software\Wine\FileOpenBlacklist\.jpe,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" - - ;; JPEG - HKCR,"MIME\Database\Content Type\image/jpeg","CLSID",,"%CLSID_HTMLDocument%" -@@ -173,6 +175,7 @@ HKCR,"jpegfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," - HKCR,"jpegfile\shell\open\ddeexec\Application",,,"IExplore" - HKCR,"jpegfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" - ;; HKCR,"jpegfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,8" -+HKCU,Software\Wine\FileOpenBlacklist\.jpeg,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" - - ;; JPG - HKCR,".jpg",,2,"jpegfile" -@@ -184,6 +187,7 @@ HKCR,"jpegfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," - HKCR,"jpegfile\shell\open\ddeexec\Application",,,"IExplore" - HKCR,"jpegfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" - ;; HKCR,"jpegfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,8" -+HKCU,Software\Wine\FileOpenBlacklist\.jpg,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" - - ;; MHTML - HKCR,"MIME\Database\Content Type\message/rfc822","CLSID",,"%CLSID_MHTMLDocument%" -@@ -221,6 +225,7 @@ HKCR,"pjpegfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," - HKCR,"pjpegfile\shell\open\ddeexec\Application",,,"IExplore" - HKCR,"pjpegfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" - ;; HKCR,"pjpegfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,8" -+HKCU,Software\Wine\FileOpenBlacklist\.jfif,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" - - ;; PNG - HKCR,"MIME\Database\Content Type\image/png","Extension",,".png" -@@ -234,6 +239,7 @@ HKCR,"pngfile\shell\open\ddeexec",,,"""file:%%1"",,-1,,,,," - HKCR,"pngfile\shell\open\ddeexec\Application",,,"IExplore" - HKCR,"pngfile\shell\open\ddeexec\Topic",,,"WWW_OpenURL" - ;; HKCR,"pngfile\DefaultIcon",,,"%16422%\Internet Explorer\iexplore.exe,9" -+HKCU,Software\Wine\FileOpenBlacklist\.png,"iexplore",,"""%16422%\Internet Explorer\iexplore.exe"" -nohome" - - ;; PS - HKCR,"MIME\Database\Content Type\application/postscript","Extension",,".ps" -diff --git a/loader/wine.inf.in b/loader/wine.inf.in -index 131fd34ed7a..48c867cd216 100644 ---- a/loader/wine.inf.in -+++ b/loader/wine.inf.in -@@ -329,6 +329,16 @@ HKCR,http\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" - HKCR,https\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" - HKCR,mailto\shell\open\command,,2,"""%11%\winebrowser.exe"" ""%1""" - -+HKCU,Software\Wine\FileOpenBlacklist\.htm,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" -+HKCU,Software\Wine\FileOpenBlacklist\.html,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" -+HKCU,Software\Wine\FileOpenBlacklist\.ini,"notepad",,"%11%\notepad.exe %1" -+HKCU,Software\Wine\FileOpenBlacklist\.pdf,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" -+HKCU,Software\Wine\FileOpenBlacklist\.rtf,"wordpad",,"""%16422%\Windows NT\Accessories\wordpad.exe"" %1" -+HKCU,Software\Wine\FileOpenBlacklist\.txt,"notepad",,"%11%\notepad.exe %1" -+HKCU,Software\Wine\FileOpenBlacklist\.url,"ieframe",,"rundll32.exe ieframe.dll,OpenURL %l" -+HKCU,Software\Wine\FileOpenBlacklist\.wri,"wordpad",,"""%16422%\Windows NT\Accessories\wordpad.exe"" %1" -+HKCU,Software\Wine\FileOpenBlacklist\.xml,"winebrowser",,"""%11%\winebrowser.exe"" -nohome" -+ - [ContentIndex] - HKLM,System\CurrentControlSet\Control\ContentIndex\Language\Neutral,"WBreakerClass",,"{369647e0-17b0-11ce-9950-00aa004bbb1f}" - HKLM,System\CurrentControlSet\Control\ContentIndex\Language\Neutral,"StemmerClass",,"" -diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c -index 31c97107802..0226d0d7ad9 100644 ---- a/programs/winemenubuilder/winemenubuilder.c -+++ b/programs/winemenubuilder/winemenubuilder.c -@@ -1954,7 +1954,7 @@ static BOOL write_freedesktop_mime_type_entry(const WCHAR *packages_dir, const W - return ret; - } - --static BOOL is_extension_banned(LPCWSTR extension) -+static BOOL is_extension_banned(const WCHAR *extension) - { - /* These are managed through external tools like wine.desktop, to evade malware created file type associations */ - if (!wcsicmp(extension, L".com") || -@@ -1964,6 +1964,42 @@ static BOOL is_extension_banned(LPCWSTR extension) - return FALSE; - } - -+static BOOL is_soft_blacklisted(const WCHAR *extension, const WCHAR *command) -+{ -+ static const WCHAR FileOpenBlacklistW[] = {'S','o','f','t','w','a','r','e','\\', -+ 'W','i','n','e','\\', -+ 'F','i','l','e','O','p','e','n','B','l','a','c','k','l','i','s','t','\\',0}; -+ WCHAR blacklist_key_path[MAX_PATH]; -+ HKEY blacklist_key; -+ WCHAR program_name[MAX_PATH], *blacklisted_command; -+ DWORD len = ARRAY_SIZE(program_name); -+ DWORD i = 0; -+ -+ if (ARRAY_SIZE(FileOpenBlacklistW) + lstrlenW(extension) > ARRAY_SIZE(blacklist_key_path)) -+ return FALSE; -+ -+ lstrcpyW(blacklist_key_path, FileOpenBlacklistW); -+ lstrcatW(blacklist_key_path, extension); -+ -+ if (RegOpenKeyExW(HKEY_CURRENT_USER, blacklist_key_path, 0, KEY_QUERY_VALUE, &blacklist_key) != ERROR_SUCCESS) -+ return FALSE; -+ -+ while (RegEnumValueW(blacklist_key, i, program_name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) -+ { -+ blacklisted_command = reg_get_valW(HKEY_CURRENT_USER, blacklist_key_path, program_name); -+ if (wcscmp(command, blacklisted_command) == 0) -+ { -+ RegCloseKey(blacklist_key); -+ return TRUE; -+ } -+ len = ARRAY_SIZE(program_name); -+ i++; -+ } -+ -+ RegCloseKey(blacklist_key); -+ return FALSE; -+} -+ - static WCHAR *get_special_mime_type(LPCWSTR extension) - { - if (!wcsicmp(extension, L".lnk")) -@@ -2044,6 +2080,15 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic - WCHAR *mimeProgId = NULL; - struct rb_string_entry *entry; - -+ commandW = assoc_query(ASSOCSTR_COMMAND, extensionW, L"open"); -+ if (commandW == NULL) -+ /* no command => no application is associated */ -+ goto end; -+ -+ if (is_soft_blacklisted(extensionW, commandW)) -+ /* command is on the blacklist => desktop integration is not desirable */ -+ goto end; -+ - wcslwr(extensionW); - friendlyDocNameW = assoc_query(ASSOCSTR_FRIENDLYDOCNAME, extensionW, NULL); - -@@ -2083,11 +2128,6 @@ static BOOL generate_associations(const WCHAR *packages_dir, const WCHAR *applic - hasChanged = TRUE; - } - -- commandW = assoc_query(ASSOCSTR_COMMAND, extensionW, L"open"); -- if (commandW == NULL) -- /* no command => no application is associated */ -- goto end; -- - executableW = assoc_query(ASSOCSTR_EXECUTABLE, extensionW, L"open"); - if (executableW) - openWithIcon = compute_native_identifier(0, executableW, NULL); --- -2.35.1 - diff --git a/patches/wine-hotfixes/staging/winemenubuilder-integration/definition b/patches/wine-hotfixes/staging/winemenubuilder-integration/definition deleted file mode 100644 index dc8d54570..000000000 --- a/patches/wine-hotfixes/staging/winemenubuilder-integration/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [41275] Winemenubuilder should respect existing defaults for filetype associations -Fixes: [22904] Register URL protocol handlers under Linux diff --git a/patches/wine-hotfixes/staging/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch b/patches/wine-hotfixes/staging/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch deleted file mode 100644 index 2c43aa01c..000000000 --- a/patches/wine-hotfixes/staging/winex11-UpdateLayeredWindow/0001-winex11-Fix-alpha-blending-in-X11DRV_UpdateLayeredWi.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 5fe1a81fa6564f2d201bd3e225ac3bc4f41a2d2e Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Tue, 24 Jan 2017 12:37:46 +0100 -Subject: [PATCH] winex11: Fix alpha blending in X11DRV_UpdateLayeredWindow. - -Based on a patch by Dmitry Timoshkov. ---- - dlls/winex11.drv/window.c | 31 +++++++++++++++---------------- - 1 file changed, 15 insertions(+), 16 deletions(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 4dfb1bb6f76..8fb1a4a2786 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -434,14 +434,11 @@ static void sync_window_region( struct x11drv_win_data *data, HRGN win_region ) - - - /*********************************************************************** -- * sync_window_opacity -+ * set_window_opacity - */ --static void sync_window_opacity( Display *display, Window win, -- COLORREF key, BYTE alpha, DWORD flags ) -+static void set_window_opacity( Display *display, Window win, BYTE alpha ) - { -- unsigned long opacity = 0xffffffff; -- -- if (flags & LWA_ALPHA) opacity = (0xffffffff / 0xff) * alpha; -+ unsigned long opacity = (0xffffffff / 0xff) * alpha; - - if (opacity == 0xffffffff) - XDeleteProperty( display, win, x11drv_atom(_NET_WM_WINDOW_OPACITY) ); -@@ -1608,7 +1605,7 @@ static void create_whole_window( struct x11drv_win_data *data ) - - /* set the window opacity */ - if (!GetLayeredWindowAttributes( data->hwnd, &key, &alpha, &layered_flags )) layered_flags = 0; -- sync_window_opacity( data->display, data->whole_window, key, alpha, layered_flags ); -+ set_window_opacity( data->display, data->whole_window, (layered_flags & LWA_ALPHA) ? alpha : 0xff ); - - XFlush( data->display ); /* make sure the window exists before we start painting to it */ - -@@ -1740,7 +1737,7 @@ void CDECL X11DRV_SetWindowStyle( HWND hwnd, INT offset, STYLESTRUCT *style ) - { - data->layered = FALSE; - set_window_visual( data, &default_visual, FALSE ); -- sync_window_opacity( data->display, data->whole_window, 0, 0, 0 ); -+ set_window_opacity( data->display, data->whole_window, 0xff ); - if (data->surface) set_surface_color_key( data->surface, CLR_INVALID ); - } - done: -@@ -2668,7 +2665,7 @@ void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alph - set_window_visual( data, &default_visual, FALSE ); - - if (data->whole_window) -- sync_window_opacity( data->display, data->whole_window, key, alpha, flags ); -+ set_window_opacity( data->display, data->whole_window, (flags & LWA_ALPHA) ? alpha : 0xff ); - if (data->surface) - set_surface_color_key( data->surface, (flags & LWA_COLORKEY) ? key : CLR_INVALID ); - -@@ -2692,7 +2689,7 @@ void CDECL X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alph - Window win = X11DRV_get_whole_window( hwnd ); - if (win) - { -- sync_window_opacity( gdi_display, win, key, alpha, flags ); -+ set_window_opacity( gdi_display, win, (flags & LWA_ALPHA) ? alpha : 0xff ); - if (flags & LWA_COLORKEY) - FIXME( "LWA_COLORKEY not supported on foreign process window %p\n", hwnd ); - } -@@ -2708,7 +2705,6 @@ BOOL CDECL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO - { - struct window_surface *surface; - struct x11drv_win_data *data; -- BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, 0 }; - COLORREF color_key = (info->dwFlags & ULW_COLORKEY) ? info->crKey : CLR_INVALID; - char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )]; - BITMAPINFO *bmi = (BITMAPINFO *)buffer; -@@ -2736,6 +2732,10 @@ BOOL CDECL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO - } - else set_surface_color_key( surface, color_key ); - -+ if (data->whole_window) -+ set_window_opacity( data->display, data->whole_window, -+ (info->dwFlags & ULW_ALPHA) ? info->pblend->SourceConstantAlpha : 0xff ); -+ - if (surface) window_surface_add_ref( surface ); - mapped = data->mapped; - release_win_data( data ); -@@ -2769,16 +2769,15 @@ BOOL CDECL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO - { - IntersectRect( &rect, &rect, info->prcDirty ); - memcpy( src_bits, dst_bits, bmi->bmiHeader.biSizeImage ); -- PatBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, BLACKNESS ); - } - src_rect = rect; - if (info->pptSrc) OffsetRect( &src_rect, info->pptSrc->x, info->pptSrc->y ); - DPtoLP( info->hdcSrc, (POINT *)&src_rect, 2 ); - -- ret = GdiAlphaBlend( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, -- info->hdcSrc, src_rect.left, src_rect.top, -- src_rect.right - src_rect.left, src_rect.bottom - src_rect.top, -- (info->dwFlags & ULW_ALPHA) ? *info->pblend : blend ); -+ ret = StretchBlt( hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, -+ info->hdcSrc, src_rect.left, src_rect.top, -+ src_rect.right - src_rect.left, src_rect.bottom - src_rect.top, -+ SRCCOPY ); - if (ret) - { - memcpy( dst_bits, src_bits, bmi->bmiHeader.biSizeImage ); --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging/winex11-UpdateLayeredWindow/definition b/patches/wine-hotfixes/staging/winex11-UpdateLayeredWindow/definition deleted file mode 100644 index fc7874a5c..000000000 --- a/patches/wine-hotfixes/staging/winex11-UpdateLayeredWindow/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: [33943] Fix alpha blending in X11DRV_UpdateLayeredWindow diff --git a/patches/wine-hotfixes/staging/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch b/patches/wine-hotfixes/staging/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch deleted file mode 100644 index 3c70f5fbf..000000000 --- a/patches/wine-hotfixes/staging/winex11-XEMBED/0001-winex11-Enable-disable-windows-when-they-are-un-mapped.patch +++ /dev/null @@ -1,56 +0,0 @@ -From e1440086421942267ff1df00fdb11e724bd0119b Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Fri, 22 Nov 2013 18:54:18 +0100 -Subject: [PATCH] winex11: Enable/disable windows when they are (un)mapped by - foreign applications - ---- - dlls/winex11.drv/event.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 68cf638f1ed..38abae1278b 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -1148,6 +1148,7 @@ static BOOL X11DRV_Expose( HWND hwnd, XEvent *xev ) - static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) - { - struct x11drv_win_data *data; -+ BOOL is_embedded; - - x11drv_input_add_window( hwnd, event->xany.window ); - -@@ -1161,7 +1162,12 @@ static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) - if (hwndFocus && NtUserIsChild( hwnd, hwndFocus )) - set_input_focus( data ); - } -+ -+ is_embedded = data->embedded; - release_win_data( data ); -+ -+ if (is_embedded) -+ NtUserEnableWindow( hwnd, TRUE ); - return TRUE; - } - -@@ -1171,6 +1177,17 @@ static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) - */ - static BOOL X11DRV_UnmapNotify( HWND hwnd, XEvent *event ) - { -+ struct x11drv_win_data *data; -+ BOOL is_embedded; -+ -+ if (!(data = get_win_data( hwnd ))) return FALSE; -+ -+ is_embedded = data->embedded; -+ release_win_data( data ); -+ -+ if (is_embedded) -+ NtUserEnableWindow( hwnd, FALSE ); -+ - x11drv_input_remove_window( event->xany.window ); - return TRUE; - } --- -2.34.1 - diff --git a/patches/wine-hotfixes/staging/winex11-XEMBED/definition b/patches/wine-hotfixes/staging/winex11-XEMBED/definition deleted file mode 100644 index 2fe89b51c..000000000 --- a/patches/wine-hotfixes/staging/winex11-XEMBED/definition +++ /dev/null @@ -1 +0,0 @@ -Fixes: XEMBED support for embedding Wine windows inside Linux applications diff --git a/patches/wine-hotfixes/staging/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch b/patches/wine-hotfixes/staging/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch deleted file mode 100644 index 420e23bce..000000000 --- a/patches/wine-hotfixes/staging/winex11-wglShareLists/0001-winex11.drv-Only-warn-about-used-contexts-in-wglShar.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 4d2c03539d7316d75b56fd8a2c852a9013234f0c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Michael=20M=C3=BCller?= -Date: Sun, 28 Sep 2014 21:20:52 +0200 -Subject: winex11.drv: Only warn about used contexts in wglShareLists. - ---- - dlls/opengl32/tests/opengl.c | 2 +- - dlls/winex11.drv/opengl.c | 10 ++++------ - 2 files changed, 5 insertions(+), 7 deletions(-) - -diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c -index e5e1507..5454d3a 100644 ---- a/dlls/opengl32/tests/opengl.c -+++ b/dlls/opengl32/tests/opengl.c -@@ -365,7 +365,7 @@ static void test_sharelists(HDC winhdc) - res = wglMakeCurrent(winhdc, hglrc2); - ok(res, "Make current failed\n"); - res = wglShareLists(hglrc1, hglrc2); -- todo_wine ok(res, "Sharing display lists with a destination context which has been made current failed\n"); -+ ok(res, "Sharing display lists with a destination context which has been made current failed\n"); - wglMakeCurrent(0, 0); - wglDeleteContext(hglrc2); - } -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 0f7534e..39929f2 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -1959,18 +1959,16 @@ static BOOL glxdrv_wglShareLists(struct wgl_context *org, struct wgl_context *de - - if (share_all_contexts == 1) return TRUE; - -- if((org->has_been_current && dest->has_been_current) || dest->has_been_current) -- { -- ERR("Could not share display lists, one of the contexts has been current already !\n"); -- return FALSE; -- } -- else if(dest->sharing) -+ if(dest->sharing) - { - ERR("Could not share display lists because hglrc2 has already shared lists before\n"); - return FALSE; - } - else - { -+ if(dest->has_been_current) -+ ERR("Recreating OpenGL context to share display lists, although the context has been current!\n"); -+ - /* Re-create the GLX context and share display lists */ - pglXDestroyContext(gdi_display, dest->ctx); - dest->ctx = create_glxcontext(gdi_display, dest, org->ctx); --- -2.8.0 - diff --git a/patches/wine-hotfixes/staging/winex11-wglShareLists/definition b/patches/wine-hotfixes/staging/winex11-wglShareLists/definition deleted file mode 100644 index a74ef1868..000000000 --- a/patches/wine-hotfixes/staging/winex11-wglShareLists/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [11436] Do not fail when a used context is passed to wglShareLists -Fixes: [25419] Fix broken textures in XIII Century: Death or Glory diff --git a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch b/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch deleted file mode 100644 index 06d4b73af..000000000 --- a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0001-Add-support-for-private-contexts.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 71be762c3d84b84c3d9249f80467797ce3519bb6 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 12 Sep 2020 16:31:09 +1000 -Subject: Add support for private contexts - - -diff --git a/libs/faudio/include/FACT.h b/libs/faudio/include/FACT.h -index 579b7168812..084b1e55cfe 100644 ---- a/libs/faudio/include/FACT.h -+++ b/libs/faudio/include/FACT.h -@@ -805,6 +805,18 @@ FACTAPI uint32_t FACTCue_SetOutputVoiceMatrix( - const float *pLevelMatrix /* SourceChannels * DestinationChannels */ - ); - -+FACTAPI void FACTWave_SetPrivateContext(FACTWave *pWave, void *context); -+FACTAPI void* FACTWave_GetPrivateContext(FACTWave *pWave); -+ -+FACTAPI void FACTWaveBank_SetPrivateContext(FACTWaveBank *pWaveBank, void *context); -+FACTAPI void* FACTWaveBank_GetPrivateContext(FACTWaveBank *pWaveBank); -+ -+FACTAPI void FACTSoundBank_SetPrivateContext(FACTSoundBank *pSoundBank, void *context); -+FACTAPI void* FACTSoundBank_GetPrivateContext(FACTSoundBank *pSoundBank); -+ -+FACTAPI void FACTCue_SetPrivateContext(FACTCue *pCue, void *context); -+FACTAPI void* FACTCue_GetPrivateContext(FACTCue *pCue); -+ - #ifdef __cplusplus - } - #endif /* __cplusplus */ -diff --git a/libs/faudio/src/FACT.c b/libs/faudio/src/FACT.c -index 5eca83b389f..e2e7b10058d 100644 ---- a/libs/faudio/src/FACT.c -+++ b/libs/faudio/src/FACT.c -@@ -1177,6 +1177,9 @@ uint32_t FACTSoundBank_Prepare( - (*ppCue)->notifyOnDestroy = 0; - (*ppCue)->usercontext = NULL; - -+ /* User data */ -+ (*ppCue)->privatecontext = NULL; -+ - /* Sound data */ - (*ppCue)->data = &pSoundBank->cues[nCueIndex]; - if ((*ppCue)->data->flags & 0x04) -@@ -1798,6 +1801,9 @@ uint32_t FACTWaveBank_Prepare( - (*ppWave)->pitch = 0; - (*ppWave)->loopCount = nLoopCount; - -+ /* User data */ -+ (*ppWave)->privatecontext = NULL; -+ - /* TODO: Convert dwPlayOffset to a byte offset */ - FAudio_assert(dwPlayOffset == 0); - #if 0 -@@ -2175,11 +2181,14 @@ uint32_t FACTWave_Stop(FACTWave *pWave, uint32_t dwFlags) - { - FACTNotification note; - note.type = FACTNOTIFICATIONTYPE_WAVESTOP; -+ note.wave.cueIndex = pWave->parentCue->index; -+ note.wave.pCue = pWave->parentCue; -+ note.wave.pSoundBank = pWave->parentCue->parentBank; - note.wave.pWave = pWave; -- if (pWave->parentBank->parentEngine->notifications & NOTIFY_WAVESTOP) -- { -- note.pvContext = pWave->parentBank->parentEngine->wave_context; -- } -+ note.wave.pWaveBank = pWave->parentBank; -+ -+ note.pvContext = pWave->parentBank->parentEngine->wave_context; -+ - pWave->parentBank->parentEngine->notificationCallback(¬e); - } - -@@ -3018,4 +3027,42 @@ uint32_t FACTCue_SetOutputVoiceMatrix( - return 0; - } - -+void FACTWave_SetPrivateContext(FACTWave *pWave, void *context) -+{ -+ pWave->privatecontext = context; -+} -+void* FACTWave_GetPrivateContext(FACTWave *pWave) -+{ -+ return pWave->privatecontext; -+} -+ -+FACTAPI void FACTWaveBank_SetPrivateContext(FACTWaveBank *pWaveBank, void *context) -+{ -+ pWaveBank->privatecontext = context; -+} -+ -+FACTAPI void* FACTWaveBank_GetPrivateContext(FACTWaveBank *pWaveBank) -+{ -+ return pWaveBank->privatecontext; -+} -+ -+FACTAPI void FACTSoundBank_SetPrivateContext(FACTSoundBank *pSoundBank, void *context) -+{ -+ pSoundBank->privatecontext = context; -+} -+FACTAPI void* FACTSoundBank_GetPrivateContext(FACTSoundBank *pSoundBank) -+{ -+ return pSoundBank->privatecontext; -+} -+ -+FACTAPI void FACTCue_SetPrivateContext(FACTCue *pCue, void *context) -+{ -+ pCue->privatecontext = context; -+} -+ -+FACTAPI void* FACTCue_GetPrivateContext(FACTCue *pCue) -+{ -+ return pCue->privatecontext; -+} -+ - /* vim: set noexpandtab shiftwidth=8 tabstop=8: */ -diff --git a/libs/faudio/src/FACT_internal.h b/libs/faudio/src/FACT_internal.h -index 6bf522e64c4..52d07e5f9d3 100644 ---- a/libs/faudio/src/FACT_internal.h -+++ b/libs/faudio/src/FACT_internal.h -@@ -473,6 +473,9 @@ struct FACTSoundBank - uint32_t *variationCodes; - FACTTransitionTable *transitions; - uint32_t *transitionCodes; -+ -+ /* Application data */ -+ void *privatecontext; - }; - - struct FACTWaveBank -@@ -498,6 +501,9 @@ struct FACTWaveBank - uint8_t *packetBuffer; - uint32_t packetBufferLen; - void* io; -+ -+ /* Application data */ -+ void *privatecontext; - }; - - struct FACTWave -@@ -524,6 +530,9 @@ struct FACTWave - uint16_t srcChannels; - FAudioSourceVoice *voice; - FACTWaveCallback callback; -+ -+ /* Application data */ -+ void *privatecontext; - }; - - struct FACTCue -@@ -569,6 +578,9 @@ struct FACTCue - /* Timer */ - uint32_t start; - uint32_t elapsed; -+ -+ /* Application data */ -+ void *privatecontext; - }; - - /* Internal functions */ diff --git a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch b/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch deleted file mode 100644 index 90d2fbece..000000000 --- a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0002-xactengine3_7-notifications.patch +++ /dev/null @@ -1,155 +0,0 @@ -From a5439a8a6d3706ee6c3ea13cd76deee1484083d4 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 12 Sep 2020 14:10:18 +1000 -Subject: xactengine3_7: notifications - - -diff --git a/dlls/xactengine3_7/xact_dll.c b/dlls/xactengine3_7/xact_dll.c -index 326f79f0ecd..62084f9234f 100644 ---- a/dlls/xactengine3_7/xact_dll.c -+++ b/dlls/xactengine3_7/xact_dll.c -@@ -329,6 +329,8 @@ static HRESULT WINAPI IXACT3SoundBankImpl_Prepare(IXACT3SoundBank *iface, - cue->fact_cue = fcue; - *ppCue = &cue->IXACT3Cue_iface; - -+ FACTCue_SetPrivateContext(fcue, &cue->IXACT3Cue_iface); -+ - TRACE("Created Cue: %p\n", cue); - - return S_OK; -@@ -370,6 +372,8 @@ static HRESULT WINAPI IXACT3SoundBankImpl_Play(IXACT3SoundBank *iface, - cue->IXACT3Cue_iface.lpVtbl = &XACT3Cue_Vtbl; - cue->fact_cue = fcue; - *ppCue = &cue->IXACT3Cue_iface; -+ -+ FACTCue_SetPrivateContext(fcue, &cue->IXACT3Cue_iface); - } - - return hr; -@@ -627,6 +631,8 @@ static HRESULT WINAPI IXACT3WaveBankImpl_Prepare(IXACT3WaveBank *iface, - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; - -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); -+ - TRACE("Created Wave: %p\n", wave); - - return S_OK; -@@ -668,6 +674,8 @@ static HRESULT WINAPI IXACT3WaveBankImpl_Play(IXACT3WaveBank *iface, - wave->IXACT3Wave_iface.lpVtbl = &XACT3Wave_Vtbl; - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; -+ -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); - } - - return hr; -@@ -837,6 +845,7 @@ static HRESULT WINAPI IXACT3EngineImpl_GetFinalMixFormat(IXACT3Engine *iface, - static void FACTCALL fact_notification_cb(const FACTNotification *notification) - { - XACT3EngineImpl *engine = (XACT3EngineImpl *)notification->pvContext; -+ XACT_NOTIFICATION note; - - /* Older versions of FAudio don't pass through the context */ - if (!engine) -@@ -845,7 +854,45 @@ static void FACTCALL fact_notification_cb(const FACTNotification *notification) - return; - } - -- FIXME("Unsupported callback type %d\n", notification->type); -+ note.type = notification->type; -+ note.pvContext = engine->contexts[notification->type - 1]; -+ -+ switch (notification->type) -+ { -+ case XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED: -+ note.soundBank.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -+ break; -+#if XACT3_VER >= 0x0205 -+ case XACTNOTIFICATIONTYPE_WAVEDESTROYED: -+ case XACTNOTIFICATIONTYPE_WAVELOOPED: -+ case XACTNOTIFICATIONTYPE_WAVEPLAY: -+ case XACTNOTIFICATIONTYPE_WAVEPREPARED: -+#endif -+ case XACTNOTIFICATIONTYPE_WAVESTOP: -+ note.wave.cueIndex = notification->wave.cueIndex; -+ note.wave.pCue = FACTCue_GetPrivateContext(notification->wave.pCue); -+ note.wave.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -+#if XACT3_VER >= 0x0205 -+ note.wave.pWave = FACTWave_GetPrivateContext(notification->wave.pWave); -+#endif -+ note.wave.pWaveBank = FACTWaveBank_GetPrivateContext(notification->wave.pWaveBank); -+ break; -+ -+ case XACTNOTIFICATIONTYPE_CUEPLAY: -+ case XACTNOTIFICATIONTYPE_CUEPREPARED: -+ case XACTNOTIFICATIONTYPE_CUESTOP: -+ note.cue.pCue = FACTCue_GetPrivateContext(notification->cue.pCue); -+ /* Fall through */ -+ case XACTNOTIFICATIONTYPE_CUEDESTROYED: -+ note.cue.cueIndex = notification->cue.cueIndex; -+ note.cue.pSoundBank = FACTSoundBank_GetPrivateContext(notification->cue.pSoundBank); -+ break; -+ default: -+ FIXME("Unsupported callback type %d\n", notification->type); -+ return; -+ } -+ -+ engine->notification_callback(¬e); - } - - static HRESULT WINAPI IXACT3EngineImpl_Initialize(IXACT3Engine *iface, -@@ -961,6 +1008,8 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateSoundBank(IXACT3Engine *iface, - sb->fact_soundbank = fsb; - *ppSoundBank = &sb->IXACT3SoundBank_iface; - -+ FACTSoundBank_SetPrivateContext(fsb, &sb->IXACT3SoundBank_iface); -+ - TRACE("Created SoundBank: %p\n", sb); - - return S_OK; -@@ -1037,6 +1086,8 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateInMemoryWaveBank(IXACT3Engine *ifac - - send_wavebank_notification(This, &wb->IXACT3WaveBank_iface); - -+ FACTWaveBank_SetPrivateContext(fwb, &wb->IXACT3WaveBank_iface); -+ - TRACE("Created in-memory WaveBank: %p\n", wb); - - return S_OK; -@@ -1087,6 +1138,8 @@ static HRESULT WINAPI IXACT3EngineImpl_CreateStreamingWaveBank(IXACT3Engine *ifa - - send_wavebank_notification(This, &wb->IXACT3WaveBank_iface); - -+ FACTWaveBank_SetPrivateContext(fwb, &wb->IXACT3WaveBank_iface); -+ - TRACE("Created streaming WaveBank: %p\n", wb); - - return S_OK; -@@ -1135,6 +1188,8 @@ static HRESULT WINAPI IXACT3EngineImpl_PrepareInMemoryWave(IXACT3Engine *iface, - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; - -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); -+ - TRACE("Created Wave: %p\n", wave); - - return S_OK; -@@ -1197,6 +1252,8 @@ static HRESULT WINAPI IXACT3EngineImpl_PrepareStreamingWave(IXACT3Engine *iface, - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; - -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); -+ - TRACE("Created Wave: %p\n", wave); - - return S_OK; -@@ -1234,6 +1291,8 @@ static HRESULT WINAPI IXACT3EngineImpl_PrepareWave(IXACT3Engine *iface, - wave->fact_wave = fwave; - *ppWave = &wave->IXACT3Wave_iface; - -+ FACTWave_SetPrivateContext(fwave, &wave->IXACT3Wave_iface); -+ - TRACE("Created Wave: %p\n", wave); - - return S_OK; diff --git a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch b/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch deleted file mode 100644 index c474b8b80..000000000 --- a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0003-Send-NOTIFY_CUESTOP-when-Stop-is-called.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a8f9265b71b423e2d280645a225465750a1d4594 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Mon, 25 Oct 2021 09:48:50 +1100 -Subject: [PATCH 3/3] Send NOTIFY_CUESTOP when Stop is called - ---- - libs/faudio/src/FACT.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/libs/faudio/src/FACT.c b/libs/faudio/src/FACT.c -index cea960d6710..d9c5d7c2766 100644 ---- a/libs/faudio/src/FACT.c -+++ b/libs/faudio/src/FACT.c -@@ -2685,6 +2685,8 @@ uint32_t FACTCue_Stop(FACTCue *pCue, uint32_t dwFlags) - } - } - -+ FACT_INTERNAL_SendCueNotification(pCue, NOTIFY_CUESTOP, FACTNOTIFICATIONTYPE_CUESTOP); -+ - FAudio_PlatformUnlockMutex(pCue->parentBank->parentEngine->apiLock); - return 0; - } --- -2.33.0 - diff --git a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch b/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch deleted file mode 100644 index 54340ffac..000000000 --- a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/0004-xactengine3_7-Don-t-use-switch-with-constant-integer.patch +++ /dev/null @@ -1,83 +0,0 @@ -From cb0480cc441f4f2c599f506fbac5d27552f55cdd Mon Sep 17 00:00:00 2001 -From: "Olivier F. R. Dierick" -Date: Sat, 29 Jan 2022 22:46:07 +0100 -Subject: xactengine3_7: Don't use switch with constant integers. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52478 - -diff --git a/dlls/xactengine3_7/xact_dll.c b/dlls/xactengine3_7/xact_dll.c -index 62084f9234f..83b7b760118 100644 ---- a/dlls/xactengine3_7/xact_dll.c -+++ b/dlls/xactengine3_7/xact_dll.c -@@ -857,40 +857,43 @@ static void FACTCALL fact_notification_cb(const FACTNotification *notification) - note.type = notification->type; - note.pvContext = engine->contexts[notification->type - 1]; - -- switch (notification->type) -+ if (notification->type == XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED) - { -- case XACTNOTIFICATIONTYPE_SOUNDBANKDESTROYED: -- note.soundBank.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -- break; -+ note.soundBank.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -+ } -+ else if (notification->type == XACTNOTIFICATIONTYPE_WAVESTOP - #if XACT3_VER >= 0x0205 -- case XACTNOTIFICATIONTYPE_WAVEDESTROYED: -- case XACTNOTIFICATIONTYPE_WAVELOOPED: -- case XACTNOTIFICATIONTYPE_WAVEPLAY: -- case XACTNOTIFICATIONTYPE_WAVEPREPARED: -+ || notification->type == XACTNOTIFICATIONTYPE_WAVEDESTROYED -+ || notification->type == XACTNOTIFICATIONTYPE_WAVELOOPED -+ || notification->type == XACTNOTIFICATIONTYPE_WAVEPLAY -+ || notification->type == XACTNOTIFICATIONTYPE_WAVEPREPARED) -+#else -+ ) - #endif -- case XACTNOTIFICATIONTYPE_WAVESTOP: -- note.wave.cueIndex = notification->wave.cueIndex; -- note.wave.pCue = FACTCue_GetPrivateContext(notification->wave.pCue); -- note.wave.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); -+ { -+ note.wave.cueIndex = notification->wave.cueIndex; -+ note.wave.pCue = FACTCue_GetPrivateContext(notification->wave.pCue); -+ note.wave.pSoundBank = FACTSoundBank_GetPrivateContext(notification->wave.pSoundBank); - #if XACT3_VER >= 0x0205 -- note.wave.pWave = FACTWave_GetPrivateContext(notification->wave.pWave); -+ note.wave.pWave = FACTWave_GetPrivateContext(notification->wave.pWave); - #endif -- note.wave.pWaveBank = FACTWaveBank_GetPrivateContext(notification->wave.pWaveBank); -- break; -- -- case XACTNOTIFICATIONTYPE_CUEPLAY: -- case XACTNOTIFICATIONTYPE_CUEPREPARED: -- case XACTNOTIFICATIONTYPE_CUESTOP: -+ note.wave.pWaveBank = FACTWaveBank_GetPrivateContext(notification->wave.pWaveBank); -+ } -+ else if (notification->type == XACTNOTIFICATIONTYPE_CUEPLAY || -+ notification->type == XACTNOTIFICATIONTYPE_CUEPREPARED || -+ notification->type == XACTNOTIFICATIONTYPE_CUESTOP || -+ notification->type == XACTNOTIFICATIONTYPE_CUEDESTROYED) -+ { -+ if (notification->type != XACTNOTIFICATIONTYPE_CUEDESTROYED) - note.cue.pCue = FACTCue_GetPrivateContext(notification->cue.pCue); -- /* Fall through */ -- case XACTNOTIFICATIONTYPE_CUEDESTROYED: -- note.cue.cueIndex = notification->cue.cueIndex; -- note.cue.pSoundBank = FACTSoundBank_GetPrivateContext(notification->cue.pSoundBank); -- break; -- default: -- FIXME("Unsupported callback type %d\n", notification->type); -- return; -- } -+ note.cue.cueIndex = notification->cue.cueIndex; -+ note.cue.pSoundBank = FACTSoundBank_GetPrivateContext(notification->cue.pSoundBank); -+ } -+ else -+ { -+ FIXME("Unsupported callback type %d\n", notification->type); -+ return; -+ } - - engine->notification_callback(¬e); - } diff --git a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/definition b/patches/wine-hotfixes/staging/xactengine3_7-callbacks/definition deleted file mode 100644 index b44efb6dd..000000000 --- a/patches/wine-hotfixes/staging/xactengine3_7-callbacks/definition +++ /dev/null @@ -1,2 +0,0 @@ -Fixes: [49678] - xactengine: Implement callback notifications. -Depends: xactengine3_7-Notification diff --git a/patches/wine-hotfixes/upstream/2326.patch b/patches/wine-hotfixes/upstream/2326.patch deleted file mode 100644 index acc64d0f7..000000000 --- a/patches/wine-hotfixes/upstream/2326.patch +++ /dev/null @@ -1,75 +0,0 @@ -From d7d94ed0df6931907d1c89d7d7551dd40f5214c5 Mon Sep 17 00:00:00 2001 -From: Brendan Shanks -Date: Fri, 3 Mar 2023 10:49:18 -0800 -Subject: [PATCH] kernelbase: Implement DiscardVirtualMemory(). - ---- - dlls/kernel32/kernel32.spec | 1 + - dlls/kernelbase/kernelbase.spec | 2 +- - dlls/kernelbase/memory.c | 13 +++++++++++++ - include/memoryapi.h | 1 + - 4 files changed, 16 insertions(+), 1 deletion(-) - -diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec -index 47ff251067a..8da6321e8d0 100644 ---- a/dlls/kernel32/kernel32.spec -+++ b/dlls/kernel32/kernel32.spec -@@ -371,6 +371,7 @@ - @ stdcall -import DeleteProcThreadAttributeList(ptr) - # @ stub DisableThreadProfiling - @ stdcall DisassociateCurrentThreadFromCallback(ptr) NTDLL.TpDisassociateCallback -+@ stdcall DiscardVirtualMemory(ptr long) kernelbase.DiscardVirtualMemory - @ stdcall DeleteTimerQueue(long) - @ stdcall -import DeleteTimerQueueEx(long long) - @ stdcall -import DeleteTimerQueueTimer(long long long) -diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec -index e3a0ad257f2..af3af8ecabe 100644 ---- a/dlls/kernelbase/kernelbase.spec -+++ b/dlls/kernelbase/kernelbase.spec -@@ -269,7 +269,7 @@ - @ stdcall DisablePredefinedHandleTableInternal(long) - @ stdcall DisableThreadLibraryCalls(long) - @ stdcall DisassociateCurrentThreadFromCallback(ptr) ntdll.TpDisassociateCallback --# @ stub DiscardVirtualMemory -+@ stdcall DiscardVirtualMemory(ptr long) - @ stdcall DisconnectNamedPipe(long) - @ stdcall DnsHostnameToComputerNameExW(wstr ptr ptr) - # @ stub DsBindWithSpnExW -diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c -index 4bcd4a639f6..a3ba79f3405 100644 ---- a/dlls/kernelbase/memory.c -+++ b/dlls/kernelbase/memory.c -@@ -52,6 +52,19 @@ BOOLEAN WINAPI RtlSetUserValueHeap( HANDLE handle, ULONG flags, void *ptr, void - ***********************************************************************/ - - -+/*********************************************************************** -+ * DiscardVirtualMemory (kernelbase.@) -+ */ -+DWORD WINAPI DECLSPEC_HOTPATCH DiscardVirtualMemory( void *addr, SIZE_T size ) -+{ -+ NTSTATUS status; -+ LPVOID ret = addr; -+ -+ status = NtAllocateVirtualMemory( GetCurrentProcess(), &ret, 0, &size, MEM_RESET, PAGE_NOACCESS ); -+ return RtlNtStatusToDosError( status ); -+} -+ -+ - /*********************************************************************** - * FlushViewOfFile (kernelbase.@) - */ -diff --git a/include/memoryapi.h b/include/memoryapi.h -index 8743e67927c..6728b832fa7 100644 ---- a/include/memoryapi.h -+++ b/include/memoryapi.h -@@ -41,5 +41,6 @@ typedef struct WIN32_MEMORY_REGION_INFORMATION - SIZE_T CommitSize; - } WIN32_MEMORY_REGION_INFORMATION; - -+DWORD WINAPI DiscardVirtualMemory(void *addr, SIZE_T size); - BOOL WINAPI QueryVirtualMemoryInformation(HANDLE process,const void *addr, - WIN32_MEMORY_INFORMATION_CLASS info_class, void *info, SIZE_T size, SIZE_T *ret_size); --- -GitLab - diff --git a/patches/wine-hotfixes/upstream/32-bit-ldap-upstream-fix.patch b/patches/wine-hotfixes/upstream/32-bit-ldap-upstream-fix.patch deleted file mode 100644 index c65a533a7..000000000 --- a/patches/wine-hotfixes/upstream/32-bit-ldap-upstream-fix.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 25946b48148784e8275c1685f6498ab88f553ca3 Mon Sep 17 00:00:00 2001 -From: Eric Pouech -Date: Fri, 4 Feb 2022 09:34:49 +0100 -Subject: [PATCH] wldap32: Fix compilation in 32-bit. - -32-bit compilation has been broken by 8db1662d749991a77b8945c752ab024d2d6b1244. - -Signed-off-by: Eric Pouech -Signed-off-by: Hans Leidekker -Signed-off-by: Alexandre Julliard ---- - dlls/wldap32/libldap.c | 18 ++++++++++++++---- - 1 file changed, 14 insertions(+), 4 deletions(-) - -diff --git a/dlls/wldap32/libldap.c b/dlls/wldap32/libldap.c -index 8872421dabcd..592e526ecdc0 100644 ---- a/dlls/wldap32/libldap.c -+++ b/dlls/wldap32/libldap.c -@@ -53,7 +53,14 @@ C_ASSERT( sizeof(LDAPSortKeyU) == sizeof(LDAPSortKey) ); - C_ASSERT( sizeof(LDAPVLVInfoU) == sizeof(LDAPVLVInfo) ); - C_ASSERT( sizeof(LDAPAPIInfoU) == sizeof(LDAPAPIInfo) ); - C_ASSERT( sizeof(LDAPAPIFeatureInfoU) == sizeof(LDAPAPIFeatureInfo) ); --C_ASSERT( sizeof(struct timevalU) == sizeof(struct timeval) ); -+ -+static struct timeval *convert_timeval(const struct timevalU *tvu, struct timeval *tv) -+{ -+ if (!tvu) return NULL; -+ tv->tv_sec = tvu->tv_sec; -+ tv->tv_usec = tvu->tv_usec; -+ return tv; -+} - - #define WLDAP32_LBER_ERROR (~0l) - -@@ -488,8 +495,9 @@ static NTSTATUS wrap_ldap_rename_s( void *args ) - static NTSTATUS wrap_ldap_result( void *args ) - { - struct ldap_result_params *params = args; -+ struct timeval tv; - return ldap_result( params->ld, params->msgid, params->all, -- (struct timeval *)params->timeout, (LDAPMessage **)params->result ); -+ convert_timeval(params->timeout, &tv), (LDAPMessage **)params->result ); - } - - static NTSTATUS wrap_ldap_sasl_bind( void *args ) -@@ -555,18 +563,20 @@ static NTSTATUS wrap_ldap_sasl_interactive_bind_s( void *args ) - static NTSTATUS wrap_ldap_search_ext( void *args ) - { - struct ldap_search_ext_params *params = args; -+ struct timeval tv; - return ldap_search_ext( params->ld, params->base, params->scope, params->filter, params->attrs, - params->attrsonly, (LDAPControl **)params->serverctrls, -- (LDAPControl **)params->clientctrls, (struct timeval *)params->timeout, -+ (LDAPControl **)params->clientctrls, convert_timeval(params->timeout, &tv), - params->sizelimit, (int *)params->msg ); - } - - static NTSTATUS wrap_ldap_search_ext_s( void *args ) - { - struct ldap_search_ext_s_params *params = args; -+ struct timeval tv; - return ldap_search_ext_s( params->ld, params->base, params->scope, params->filter, params->attrs, - params->attrsonly, (LDAPControl **)params->serverctrls, -- (LDAPControl **)params->clientctrls, (struct timeval *)params->timeout, -+ (LDAPControl **)params->clientctrls, convert_timeval(params->timeout, &tv), - params->sizelimit, (LDAPMessage **)params->result ); - } - diff --git a/patches/wine-hotfixes/upstream/381c2a9ae151f676a009e89b4b101679fd90b9ae.patch b/patches/wine-hotfixes/upstream/381c2a9ae151f676a009e89b4b101679fd90b9ae.patch deleted file mode 100644 index 98a49c713..000000000 --- a/patches/wine-hotfixes/upstream/381c2a9ae151f676a009e89b4b101679fd90b9ae.patch +++ /dev/null @@ -1,203 +0,0 @@ -From 381c2a9ae151f676a009e89b4b101679fd90b9ae Mon Sep 17 00:00:00 2001 -From: Nikolay Sivov -Date: Thu, 10 Feb 2022 11:21:32 +0300 -Subject: [PATCH] mfplat: Implement MFAverageTimePerFrameToFrameRate(). - -Signed-off-by: Nikolay Sivov -Signed-off-by: Alexandre Julliard ---- - dlls/mfplat/mediatype.c | 68 +++++++++++++++++++++++++++++++++++--- - dlls/mfplat/mfplat.spec | 2 +- - dlls/mfplat/tests/mfplat.c | 48 +++++++++++++++++++++++++++ - include/mfapi.h | 1 + - 4 files changed, 113 insertions(+), 6 deletions(-) - -diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c -index 417583902897..b77db17189f2 100644 ---- a/dlls/mfplat/mediatype.c -+++ b/dlls/mfplat/mediatype.c -@@ -3215,15 +3215,15 @@ HRESULT WINAPI MFConvertColorInfoToDXVA(DWORD *dxva_info, const MFVIDEOFORMAT *f - - struct frame_rate - { -- UINT64 rate; -- UINT64 frame_time; -+ UINT64 key; -+ UINT64 value; - }; - - static int __cdecl frame_rate_compare(const void *a, const void *b) - { -- const UINT64 *rate = a; -+ const UINT64 *key = a; - const struct frame_rate *known_rate = b; -- return *rate == known_rate->rate ? 0 : ( *rate < known_rate->rate ? 1 : -1 ); -+ return *key == known_rate->key ? 0 : ( *key < known_rate->key ? 1 : -1 ); - } - - /*********************************************************************** -@@ -3252,7 +3252,7 @@ HRESULT WINAPI MFFrameRateToAverageTimePerFrame(UINT32 numerator, UINT32 denomin - if ((entry = bsearch(&rate, known_rates, ARRAY_SIZE(known_rates), sizeof(*known_rates), - frame_rate_compare))) - { -- *avgframetime = entry->frame_time; -+ *avgframetime = entry->value; - } - else - *avgframetime = numerator ? denominator * (UINT64)10000000 / numerator : 0; -@@ -3260,6 +3260,64 @@ HRESULT WINAPI MFFrameRateToAverageTimePerFrame(UINT32 numerator, UINT32 denomin - return S_OK; - } - -+static unsigned int get_gcd(unsigned int a, unsigned int b) -+{ -+ unsigned int m; -+ -+ while (b) -+ { -+ m = a % b; -+ a = b; -+ b = m; -+ } -+ -+ return a; -+} -+ -+/*********************************************************************** -+ * MFAverageTimePerFrameToFrameRate (mfplat.@) -+ */ -+HRESULT WINAPI MFAverageTimePerFrameToFrameRate(UINT64 avgtime, UINT32 *numerator, UINT32 *denominator) -+{ -+ static const struct frame_rate known_rates[] = -+ { -+#define KNOWN_RATE(ft,n,d) { ft, ((UINT64)n << 32) | d } -+ KNOWN_RATE(417188, 24000, 1001), -+ KNOWN_RATE(416667, 24, 1), -+ KNOWN_RATE(400000, 25, 1), -+ KNOWN_RATE(333667, 30000, 1001), -+ KNOWN_RATE(333333, 30, 1), -+ KNOWN_RATE(200000, 50, 1), -+ KNOWN_RATE(166833, 60000, 1001), -+ KNOWN_RATE(166667, 60, 1), -+#undef KNOWN_RATE -+ }; -+ const struct frame_rate *entry; -+ unsigned int gcd; -+ -+ TRACE("%s, %p, %p.\n", wine_dbgstr_longlong(avgtime), numerator, denominator); -+ -+ if ((entry = bsearch(&avgtime, known_rates, ARRAY_SIZE(known_rates), sizeof(*known_rates), -+ frame_rate_compare))) -+ { -+ *numerator = entry->value >> 32; -+ *denominator = entry->value; -+ } -+ else if (avgtime) -+ { -+ if (avgtime > 100000000) avgtime = 100000000; -+ gcd = get_gcd(10000000, avgtime); -+ *numerator = 10000000 / gcd; -+ *denominator = avgtime / gcd; -+ } -+ else -+ { -+ *numerator = *denominator = 0; -+ } -+ -+ return S_OK; -+} -+ - /*********************************************************************** - * MFMapDXGIFormatToDX9Format (mfplat.@) - */ -diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec -index 5d177732fa80..31c80f596c27 100644 ---- a/dlls/mfplat/mfplat.spec -+++ b/dlls/mfplat/mfplat.spec -@@ -20,7 +20,7 @@ - @ stdcall MFAllocateWorkQueue(ptr) - @ stdcall MFAllocateWorkQueueEx(long ptr) rtworkq.RtwqAllocateWorkQueue - @ stub MFAppendCollection --@ stub MFAverageTimePerFrameToFrameRate -+@ stdcall MFAverageTimePerFrameToFrameRate(int64 ptr ptr) - @ stdcall MFBeginCreateFile(long long long wstr ptr ptr ptr) - @ stub MFBeginGetHostByName - @ stdcall MFBeginRegisterWorkQueueWithMMCSS(long wstr long ptr ptr) -diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c -index f89a5202d805..c70d8a9ca817 100644 ---- a/dlls/mfplat/tests/mfplat.c -+++ b/dlls/mfplat/tests/mfplat.c -@@ -6399,6 +6399,53 @@ static void test_MFFrameRateToAverageTimePerFrame(void) - } - } - -+static void test_MFAverageTimePerFrameToFrameRate(void) -+{ -+ static const struct frame_rate_test -+ { -+ unsigned int numerator; -+ unsigned int denominator; -+ UINT64 avgtime; -+ } frame_rate_tests[] = -+ { -+ { 60000, 1001, 166833 }, -+ { 30000, 1001, 333667 }, -+ { 24000, 1001, 417188 }, -+ { 60, 1, 166667 }, -+ { 30, 1, 333333 }, -+ { 50, 1, 200000 }, -+ { 25, 1, 400000 }, -+ { 24, 1, 416667 }, -+ -+ { 1000000, 25641, 256410 }, -+ { 10000000, 83333, 83333 }, -+ { 1, 10, 100000000 }, -+ { 1, 10, 100000001 }, -+ { 1, 10, 200000000 }, -+ { 1, 1, 10000000 }, -+ { 1, 2, 20000000 }, -+ { 5, 1, 2000000 }, -+ { 10, 1, 1000000 }, -+ }; -+ unsigned int i, numerator, denominator; -+ HRESULT hr; -+ -+ numerator = denominator = 1; -+ hr = MFAverageTimePerFrameToFrameRate(0, &numerator, &denominator); -+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr); -+ ok(!numerator && !denominator, "Unexpected output %u/%u.\n", numerator, denominator); -+ -+ for (i = 0; i < ARRAY_SIZE(frame_rate_tests); ++i) -+ { -+ numerator = denominator = 12345; -+ hr = MFAverageTimePerFrameToFrameRate(frame_rate_tests[i].avgtime, &numerator, &denominator); -+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr); -+ ok(numerator == frame_rate_tests[i].numerator && denominator == frame_rate_tests[i].denominator, -+ "%u: unexpected %u/%u, expected %u/%u.\n", i, numerator, denominator, frame_rate_tests[i].numerator, -+ frame_rate_tests[i].denominator); -+ } -+} -+ - static void test_MFMapDXGIFormatToDX9Format(void) - { - static const struct format_pair -@@ -7874,6 +7921,7 @@ START_TEST(mfplat) - test_MFCreateDXSurfaceBuffer(); - test_MFCreateTrackedSample(); - test_MFFrameRateToAverageTimePerFrame(); -+ test_MFAverageTimePerFrameToFrameRate(); - test_MFMapDXGIFormatToDX9Format(); - test_d3d11_surface_buffer(); - test_d3d12_surface_buffer(); -diff --git a/include/mfapi.h b/include/mfapi.h -index 105613693c9d..b4e4d095bb4f 100644 ---- a/include/mfapi.h -+++ b/include/mfapi.h -@@ -500,6 +500,7 @@ HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *cont - HRESULT WINAPI MFAllocateSerialWorkQueue(DWORD target_queue, DWORD *queue); - HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue); - HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue); -+HRESULT WINAPI MFAverageTimePerFrameToFrameRate(UINT64 avgtime, UINT32 *numerator, UINT32 *denominator); - HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMODE open_mode, MF_FILE_FLAGS flags, - const WCHAR *path, IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_cookie); - HRESULT WINAPI MFBeginRegisterWorkQueueWithMMCSS(DWORD queue, const WCHAR *usage_class, DWORD taskid, diff --git a/patches/wine-hotfixes/upstream/481.patch b/patches/wine-hotfixes/upstream/481.patch deleted file mode 100644 index bbd927143..000000000 --- a/patches/wine-hotfixes/upstream/481.patch +++ /dev/null @@ -1,108 +0,0 @@ -From 9090229e6789f8ba3c24047134c47c7964b1d73b Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Tue, 19 Jul 2022 23:58:21 +0900 -Subject: [PATCH 5/5] server: Use the token owner instead of the token user for - default object owner. - -Also, replace the token user with the token owner for the default DACL -as well. Wine currently selects domain_users_sid as the token owner, so -use that. This is required to pass the advapi32:security test which -expects the security descriptor owner SID to be referenced in the DACL -as well. ---- - server/change.c | 2 +- - server/file.c | 4 ++-- - server/object.c | 2 +- - server/security.h | 2 +- - server/token.c | 6 +++--- - 5 files changed, 8 insertions(+), 8 deletions(-) - -diff --git a/server/change.c b/server/change.c -index 6477b457f74..7a806abc017 100644 ---- a/server/change.c -+++ b/server/change.c -@@ -391,7 +391,7 @@ static int dir_set_sd( struct object *obj, const struct security_descriptor *sd, - else if (obj->sd) - owner = sd_get_owner( obj->sd ); - else -- owner = token_get_user( current->process->token ); -+ owner = token_get_owner( current->process->token ); - - if (set_info & DACL_SECURITY_INFORMATION) - { -diff --git a/server/file.c b/server/file.c -index eb2dc5696ed..76c687833c9 100644 ---- a/server/file.c -+++ b/server/file.c -@@ -245,7 +245,7 @@ static struct object *create_file( struct fd *root, const char *nameptr, data_si - { - const struct sid *owner = sd_get_owner( sd ); - if (!owner) -- owner = token_get_user( current->process->token ); -+ owner = token_get_owner( current->process->token ); - mode = sd_to_mode( sd, owner ); - } - else if (options & FILE_DIRECTORY_FILE) -@@ -528,7 +528,7 @@ static int file_set_sd( struct object *obj, const struct security_descriptor *sd - else if (obj->sd) - owner = sd_get_owner( obj->sd ); - else -- owner = token_get_user( current->process->token ); -+ owner = token_get_owner( current->process->token ); - - /* group and sacl not supported */ - -diff --git a/server/object.c b/server/object.c -index 333f9e7b5d6..89e541ffb6b 100644 ---- a/server/object.c -+++ b/server/object.c -@@ -574,7 +574,7 @@ int set_sd_defaults_from_token( struct object *obj, const struct security_descri - } - else if (token) - { -- owner = token_get_user( token ); -+ owner = token_get_owner( token ); - new_sd.owner_len = sid_len( owner ); - } - else new_sd.owner_len = 0; -diff --git a/server/security.h b/server/security.h -index fa91b81b77c..58ab1594eae 100644 ---- a/server/security.h -+++ b/server/security.h -@@ -73,7 +73,7 @@ extern int token_check_privileges( struct token *token, int all_required, - const struct luid_attr *reqprivs, - unsigned int count, struct luid_attr *usedprivs ); - extern const struct acl *token_get_default_dacl( struct token *token ); --extern const struct sid *token_get_user( struct token *token ); -+extern const struct sid *token_get_owner( struct token *token ); - extern const struct sid *token_get_primary_group( struct token *token ); - extern unsigned int token_get_session_id( struct token *token ); - extern int token_sid_present( struct token *token, const struct sid *sid, int deny ); -diff --git a/server/token.c b/server/token.c -index f817c1114f8..99f5e36e279 100644 ---- a/server/token.c -+++ b/server/token.c -@@ -732,7 +732,7 @@ struct token *token_create_admin( unsigned primary, int impersonation_level, int - /* on Windows, this value changes every time the user logs on */ - struct sid logon_sid = { SID_REVISION, 3, SECURITY_NT_AUTHORITY, { SECURITY_LOGON_IDS_RID, 0, 0 /* FIXME: should be randomly generated when tokens are inherited by new processes */ }}; - const struct sid *user_sid = security_unix_uid_to_sid( getuid() ); -- struct acl *default_dacl = create_default_dacl( user_sid ); -+ struct acl *default_dacl = create_default_dacl( &domain_users_sid ); - const struct luid_attr admin_privs[] = - { - { SeChangeNotifyPrivilege, SE_PRIVILEGE_ENABLED }, -@@ -1044,9 +1044,9 @@ const struct acl *token_get_default_dacl( struct token *token ) - return token->default_dacl; - } - --const struct sid *token_get_user( struct token *token ) -+const struct sid *token_get_owner( struct token *token ) - { -- return token->user; -+ return token->owner; - } - - const struct sid *token_get_primary_group( struct token *token ) --- -GitLab - diff --git a/patches/wine-hotfixes/upstream/Fix-regression-introduced-by-0e7fd41.patch b/patches/wine-hotfixes/upstream/Fix-regression-introduced-by-0e7fd41.patch deleted file mode 100644 index 99449d581..000000000 --- a/patches/wine-hotfixes/upstream/Fix-regression-introduced-by-0e7fd41.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: Christopher Egert -Subject: [PATCH] libs: Enable WAV49 support in gsm. -Message-Id: <20220306173302.1432353-1-cme3000@gmail.com> -Date: Sun, 6 Mar 2022 18:33:02 +0100 - -Fixes a regression introduced by 0e7fd41af953b2a9fa23cf6920fac229f2dd2e44 -causing missing audio elements in the 64k intros elysian by logicoma -and clean state by conspiracy. - -Signed-off-by: Christopher Egert ---- - libs/gsm/Makefile.in | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/libs/gsm/Makefile.in b/libs/gsm/Makefile.in -index 482004cab8d..36c749aa60f 100644 ---- a/libs/gsm/Makefile.in -+++ b/libs/gsm/Makefile.in -@@ -1,5 +1,6 @@ - EXTLIB = libgsm.a - EXTRAINCL = -I$(srcdir)/inc -+EXTRADEFS = -DWAV49 - - C_SRCS = \ - src/add.c \ - --- -2.35.1 - diff --git a/patches/wine-hotfixes/upstream/visual-novel-doukyuusei.patch b/patches/wine-hotfixes/upstream/visual-novel-doukyuusei.patch deleted file mode 100644 index d5bcbe7d4..000000000 --- a/patches/wine-hotfixes/upstream/visual-novel-doukyuusei.patch +++ /dev/null @@ -1,285 +0,0 @@ -From 6d8279f0ee34a1cbb9463c4f952144d31d082633 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 13 Aug 2022 11:57:20 +1000 -Subject: [PATCH] dsdmo: Add Echo FX Support. - ---- - dlls/dsdmo/dsdmo.idl | 8 ++++ - dlls/dsdmo/main.c | 97 ++++++++++++++++++++++++++++++++++++++++ - dlls/dsdmo/tests/dsdmo.c | 8 ++-- - 3 files changed, 110 insertions(+), 3 deletions(-) - -diff --git a/dlls/dsdmo/dsdmo.idl b/dlls/dsdmo/dsdmo.idl -index 7f172084828..c8130f8a1ce 100644 ---- a/dlls/dsdmo/dsdmo.idl -+++ b/dlls/dsdmo/dsdmo.idl -@@ -41,3 +41,11 @@ coclass DirectSoundParamEqDMO {} - uuid(87fc0268-9a55-4360-95aa-004a1d9de26c) - ] - coclass DirectSoundWavesReverbDMO {} -+ -+[ -+ uuid(ef3e932c-d40b-4f51-8ccf-3f98f1b29d5d), -+ threading(both), -+ progid("Microsoft.DirectSoundEchoDMO.1"), -+ vi_progid("Microsoft.DirectSoundEchoDMO") -+] -+coclass DirectSoundEchoDMO {} -diff --git a/dlls/dsdmo/main.c b/dlls/dsdmo/main.c -index 3b106a8f633..200293f5214 100644 ---- a/dlls/dsdmo/main.c -+++ b/dlls/dsdmo/main.c -@@ -947,6 +947,102 @@ static HRESULT waves_reverb_create(IUnknown *outer, IUnknown **out) - return S_OK; - } - -+struct dmo_echofx -+{ -+ struct effect effect; -+ IDirectSoundFXEcho IDirectSoundFXEcho_iface; -+}; -+ -+static inline struct dmo_echofx *impl_from_IDirectSoundFXEcho(IDirectSoundFXEcho *iface) -+{ -+ return CONTAINING_RECORD(iface, struct dmo_echofx, IDirectSoundFXEcho_iface); -+} -+ -+static HRESULT WINAPI echofx_QueryInterface(IDirectSoundFXEcho *iface, REFIID iid, void **out) -+{ -+ struct dmo_echofx *effect = impl_from_IDirectSoundFXEcho(iface); -+ return IUnknown_QueryInterface(effect->effect.outer_unk, iid, out); -+} -+ -+static ULONG WINAPI echofx_AddRef(IDirectSoundFXEcho *iface) -+{ -+ struct dmo_echofx *effect = impl_from_IDirectSoundFXEcho(iface); -+ return IUnknown_AddRef(effect->effect.outer_unk); -+} -+ -+static ULONG WINAPI echofx_Release(IDirectSoundFXEcho *iface) -+{ -+ struct dmo_echofx *effect = impl_from_IDirectSoundFXEcho(iface); -+ return IUnknown_Release(effect->effect.outer_unk); -+} -+ -+static HRESULT WINAPI echofx_SetAllParameters(IDirectSoundFXEcho *iface, const DSFXEcho *echo) -+{ -+ struct dmo_echofx *effect = impl_from_IDirectSoundFXEcho(iface); -+ FIXME("(%p) %p\n", effect, echo); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI echofx_GetAllParameters(IDirectSoundFXEcho *iface, DSFXEcho *echo) -+{ -+ struct dmo_echofx *effect = impl_from_IDirectSoundFXEcho(iface); -+ FIXME("(%p) %p\n", effect, echo); -+ -+ return E_NOTIMPL; -+} -+ -+static const struct IDirectSoundFXEchoVtbl echofx_vtbl = -+{ -+ echofx_QueryInterface, -+ echofx_AddRef, -+ echofx_Release, -+ echofx_SetAllParameters, -+ echofx_GetAllParameters -+}; -+ -+static struct dmo_echofx *impl_echo_from_effect(struct effect *iface) -+{ -+ return CONTAINING_RECORD(iface, struct dmo_echofx, effect); -+} -+ -+static void *echo_query_interface(struct effect *iface, REFIID iid) -+{ -+ struct dmo_echofx *effect = impl_echo_from_effect(iface); -+ -+ if (IsEqualGUID(iid, &IID_IDirectSoundFXEcho)) -+ return &effect->IDirectSoundFXEcho_iface; -+ return NULL; -+} -+ -+static void echo_destroy(struct effect *iface) -+{ -+ struct dmo_echofx *effect = impl_echo_from_effect(iface); -+ -+ free(effect); -+} -+ -+static const struct effect_ops echo_ops = -+{ -+ .destroy = echo_destroy, -+ .query_interface = echo_query_interface, -+}; -+ -+static HRESULT echo_create(IUnknown *outer, IUnknown **out) -+{ -+ struct dmo_echofx *object; -+ -+ if (!(object = calloc(1, sizeof(*object)))) -+ return E_OUTOFMEMORY; -+ -+ effect_init(&object->effect, outer, &echo_ops); -+ object->IDirectSoundFXEcho_iface.lpVtbl = &echofx_vtbl; -+ -+ TRACE("Created echo effect %p.\n", object); -+ *out = &object->effect.IUnknown_inner; -+ return S_OK; -+} -+ - struct class_factory - { - IClassFactory IClassFactory_iface; -@@ -1031,6 +1127,7 @@ class_factories[] = - {&GUID_DSFX_STANDARD_I3DL2REVERB, {{&class_factory_vtbl}, reverb_create}}, - {&GUID_DSFX_STANDARD_PARAMEQ, {{&class_factory_vtbl}, eq_create}}, - {&GUID_DSFX_WAVES_REVERB, {{&class_factory_vtbl}, waves_reverb_create}}, -+ {&GUID_DSFX_STANDARD_ECHO, {{&class_factory_vtbl}, echo_create}}, - }; - - HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) -From 39889f19c3db917703a8b42167ee4084dfa091d7 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Sat, 13 Aug 2022 15:03:46 +1000 -Subject: [PATCH] dsdmo: Add Compressor FX Support. - ---- - dlls/dsdmo/dsdmo.idl | 8 ++++ - dlls/dsdmo/main.c | 97 ++++++++++++++++++++++++++++++++++++++++ - dlls/dsdmo/tests/dsdmo.c | 8 ++-- - 3 files changed, 109 insertions(+), 4 deletions(-) - -diff --git a/dlls/dsdmo/dsdmo.idl b/dlls/dsdmo/dsdmo.idl -index c8130f8a1ce..3922b4d6778 100644 ---- a/dlls/dsdmo/dsdmo.idl -+++ b/dlls/dsdmo/dsdmo.idl -@@ -49,3 +49,11 @@ coclass DirectSoundWavesReverbDMO {} - vi_progid("Microsoft.DirectSoundEchoDMO") - ] - coclass DirectSoundEchoDMO {} -+ -+[ -+ uuid(ef011f79-4000-406d-87af-bffb3fc39d57), -+ threading(both), -+ progid("Microsoft.DirectSoundCompressorDMO.1"), -+ vi_progid("Microsoft.DirectSoundCompressorDMO") -+] -+coclass DirectSoundCompressorDMO {} -diff --git a/dlls/dsdmo/main.c b/dlls/dsdmo/main.c -index 200293f5214..bb19b7b7e2e 100644 ---- a/dlls/dsdmo/main.c -+++ b/dlls/dsdmo/main.c -@@ -1043,6 +1043,102 @@ static HRESULT echo_create(IUnknown *outer, IUnknown **out) - return S_OK; - } - -+struct dmo_compressorfx -+{ -+ struct effect effect; -+ IDirectSoundFXCompressor IDirectSoundFXCompressor_iface; -+}; -+ -+static inline struct dmo_compressorfx *impl_from_IDirectSoundFXCompressor(IDirectSoundFXCompressor *iface) -+{ -+ return CONTAINING_RECORD(iface, struct dmo_compressorfx, IDirectSoundFXCompressor_iface); -+} -+ -+static HRESULT WINAPI compressorfx_QueryInterface(IDirectSoundFXCompressor *iface, REFIID iid, void **out) -+{ -+ struct dmo_compressorfx *effect = impl_from_IDirectSoundFXCompressor(iface); -+ return IUnknown_QueryInterface(effect->effect.outer_unk, iid, out); -+} -+ -+static ULONG WINAPI compressorfx_AddRef(IDirectSoundFXCompressor *iface) -+{ -+ struct dmo_compressorfx *effect = impl_from_IDirectSoundFXCompressor(iface); -+ return IUnknown_AddRef(effect->effect.outer_unk); -+} -+ -+static ULONG WINAPI compressorfx_Release(IDirectSoundFXCompressor *iface) -+{ -+ struct dmo_compressorfx *effect = impl_from_IDirectSoundFXCompressor(iface); -+ return IUnknown_Release(effect->effect.outer_unk); -+} -+ -+static HRESULT WINAPI compressorfx_SetAllParameters(IDirectSoundFXCompressor *iface, const DSFXCompressor *compressor) -+{ -+ struct dmo_compressorfx *This = impl_from_IDirectSoundFXCompressor(iface); -+ FIXME("(%p) %p\n", This, compressor); -+ -+ return E_NOTIMPL; -+} -+ -+static HRESULT WINAPI compressorfx_GetAllParameters(IDirectSoundFXCompressor *iface, DSFXCompressor *compressor) -+{ -+ struct dmo_compressorfx *This = impl_from_IDirectSoundFXCompressor(iface); -+ FIXME("(%p) %p\n", This, compressor); -+ -+ return E_NOTIMPL; -+} -+ -+static const struct IDirectSoundFXCompressorVtbl compressor_vtbl = -+{ -+ compressorfx_QueryInterface, -+ compressorfx_AddRef, -+ compressorfx_Release, -+ compressorfx_SetAllParameters, -+ compressorfx_GetAllParameters -+}; -+ -+static struct dmo_compressorfx *impl_compressor_from_effect(struct effect *iface) -+{ -+ return CONTAINING_RECORD(iface, struct dmo_compressorfx, effect); -+} -+ -+static void *compressor_query_interface(struct effect *iface, REFIID iid) -+{ -+ struct dmo_compressorfx *effect = impl_compressor_from_effect(iface); -+ -+ if (IsEqualGUID(iid, &IID_IDirectSoundFXCompressor)) -+ return &effect->IDirectSoundFXCompressor_iface; -+ return NULL; -+} -+ -+static void compressor_destroy(struct effect *iface) -+{ -+ struct dmo_compressorfx *effect = impl_compressor_from_effect(iface); -+ -+ free(effect); -+} -+ -+static const struct effect_ops compressor_ops = -+{ -+ .destroy = compressor_destroy, -+ .query_interface = compressor_query_interface, -+}; -+ -+static HRESULT compressor_create(IUnknown *outer, IUnknown **out) -+{ -+ struct dmo_compressorfx *object; -+ -+ if (!(object = calloc(1, sizeof(*object)))) -+ return E_OUTOFMEMORY; -+ -+ effect_init(&object->effect, outer, &compressor_ops); -+ object->IDirectSoundFXCompressor_iface.lpVtbl = &compressor_vtbl; -+ -+ TRACE("Created compressor effect %p.\n", object); -+ *out = &object->effect.IUnknown_inner; -+ return S_OK; -+} -+ - struct class_factory - { - IClassFactory IClassFactory_iface; -@@ -1128,6 +1224,7 @@ class_factories[] = - {&GUID_DSFX_STANDARD_PARAMEQ, {{&class_factory_vtbl}, eq_create}}, - {&GUID_DSFX_WAVES_REVERB, {{&class_factory_vtbl}, waves_reverb_create}}, - {&GUID_DSFX_STANDARD_ECHO, {{&class_factory_vtbl}, echo_create}}, -+ {&GUID_DSFX_STANDARD_COMPRESSOR, {{&class_factory_vtbl}, compressor_create}}, - }; - - HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out) -