diff --git a/.config/1espt/PipelineAutobaseliningConfig.yml b/.config/1espt/PipelineAutobaseliningConfig.yml new file mode 100644 index 000000000..4b9969c37 --- /dev/null +++ b/.config/1espt/PipelineAutobaseliningConfig.yml @@ -0,0 +1,14 @@ +## DO NOT MODIFY THIS FILE MANUALLY. This is part of auto-baselining from 1ES Pipeline Templates. Go to [https://aka.ms/1espt-autobaselining] for more details. + +pipelines: + 98194: + retail: + source: + credscan: + lastModifiedDate: 2023-12-06 + eslint: + lastModifiedDate: 2023-12-06 + psscriptanalyzer: + lastModifiedDate: 2023-12-06 + armory: + lastModifiedDate: 2023-12-06 diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json new file mode 100644 index 000000000..38fe35171 --- /dev/null +++ b/.config/tsaoptions.json @@ -0,0 +1,8 @@ +{ + "instanceUrl": "https://microsoft.visualstudio.com", + "projectName": "os", + "areaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\AmUse- App Metadata and User Setup Experience\\Projections\\Cppwinrt", + "notificationAliases": [ "cpp4uwpt@microsoft.com" ], + "ignoreBranchName": true, + "codebaseName": "cppwinrt" +} diff --git a/.gdn/.gdnsettings b/.gdn/.gdnsettings new file mode 100644 index 000000000..156408362 --- /dev/null +++ b/.gdn/.gdnsettings @@ -0,0 +1,7 @@ +{ + "files": { }, + "folders": { }, + "overwriteLogs": true, + "telemetryFlushTimeout": 10, + "variables": { } +} \ No newline at end of file diff --git a/.gdn/.gitignore b/.gdn/.gitignore new file mode 100644 index 000000000..decb1055f --- /dev/null +++ b/.gdn/.gitignore @@ -0,0 +1,11 @@ +īģŋ## Ignore Guardian internal files +.r/ +rc/ +rs/ +i/ +p/ +c/ +o/ + +## Ignore Guardian Local settings +LocalSettings.gdn.json \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..748763028 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,54 @@ +name: Bug report +description: File a bug report about cppwinrt +title: "Bug:" +labels: [bug] +assignees: [] +body: + - type: markdown + attributes: + value: "Thank you for filing a bug report! 🐛" + - type: input + attributes: + label: Version + description: What is the version of cppwinrt you're using? + placeholder: You can find the exact version by running `cppwinrt.exe`. + - type: textarea + attributes: + label: Summary + description: > + Please provide a short summary of the bug, along with any information + you feel relevant to replicating the bug. + - type: textarea + attributes: + label: Reproducible example + description: > + Please provide all code needed to reproduce the issue. + placeholder: | + #include "winrt/Windows.Foundation.h" + + using namespace winrt; + using namespace Windows::Foundation; + + int main() + { + Uri uri(L"https://kennykerr.ca"); + printf("%ls\n", uri.ToString().c_str()); + } + render: cpp + - type: textarea + attributes: + label: Expected behavior + description: "I expected to see this happen:" + - type: textarea + attributes: + label: Actual behavior + description: "Instead, this happened:" + - type: textarea + attributes: + label: Additional comments + description: Is there anything else you'd like to share? + validations: + required: false + - type: markdown + attributes: + value: "Thank you! ÂŠī¸âž•âž•" diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..d32d2339d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Visual Studio or C++ question + url: https://developercommunity.visualstudio.com/cpp + about: Your open channel to Microsoft engineering teams + - name: Windows API question + url: https://docs.microsoft.com/en-us/answers/topics/windows-api.html + about: Please ask questions about the Windows API on Microsoft Q&A diff --git a/.github/actions/setup-llvm-mingw/action.yml b/.github/actions/setup-llvm-mingw/action.yml new file mode 100644 index 000000000..d36b48a75 --- /dev/null +++ b/.github/actions/setup-llvm-mingw/action.yml @@ -0,0 +1,79 @@ +name: 'Set up llvm-mingw toolchain' +description: 'Set up llvm-mingw toolchain' +inputs: + llvm-mingw-version: + description: 'llvm-mingw version' + required: true + default: '20220906' + host-arch: + description: 'llvm-mingw toolchain host architecture (e.g. i686, x86_64)' + required: true + default: 'x86_64' +outputs: + llvm-path: + description: "The path in which llvm-mingw is installed to" + value: ${{ ((runner.os == 'Windows') && steps.setup-llvm.outputs.llvm-path) || steps.setup-llvm-linux.outputs.llvm-path }} +runs: + using: "composite" + steps: + - name: Cache llvm-mingw (Windows) + id: cache-llvm + if: runner.os == 'Windows' + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: .llvm-mingw + key: llvm-mingw-${{ runner.os }}-${{ inputs.llvm-mingw-version }}-${{ inputs.host-arch }} + + - name: Install llvm-mingw ${{ inputs.llvm-mingw-version }} (Windows ${{ inputs.host-arch }}) + if: runner.os == 'Windows' && steps.cache-llvm.outputs.cache-hit != 'true' + shell: pwsh + run: | + $llvm_mingw_version = "${{ inputs.llvm-mingw-version }}" + $llvm_arch = "${{ inputs.host-arch }}" + Invoke-WebRequest "https://github.com/mstorsjo/llvm-mingw/releases/download/${llvm_mingw_version}/llvm-mingw-${llvm_mingw_version}-ucrt-${llvm_arch}.zip" -OutFile llvm-mingw.zip + 7z x llvm-mingw.zip -o"$pwd\.llvm-mingw" + rm llvm-mingw.zip + + - name: Set up llvm-mingw (Windows) + id: setup-llvm + if: runner.os == 'Windows' + shell: pwsh + run: | + $llvm_mingw_version = "${{ inputs.llvm-mingw-version }}" + $llvm_arch = "${{ inputs.host-arch }}" + if (!(Test-Path "$pwd\.llvm-mingw\llvm-mingw-${llvm_mingw_version}-ucrt-${llvm_arch}\bin\clang++.exe")) { return 1 } + Add-Content $env:GITHUB_OUTPUT "llvm-path=$pwd\.llvm-mingw\llvm-mingw-${llvm_mingw_version}-ucrt-${llvm_arch}" + Add-Content $env:GITHUB_PATH "$pwd\.llvm-mingw\llvm-mingw-${llvm_mingw_version}-ucrt-${llvm_arch}\bin" + # for the ASAN runtime DLL: + Add-Content $env:GITHUB_PATH "$pwd\.llvm-mingw\llvm-mingw-${llvm_mingw_version}-ucrt-${llvm_arch}\${llvm_arch}-w64-mingw32\bin" + + - name: Cache llvm-mingw (Linux) + id: cache-llvm-linux + if: runner.os == 'Linux' + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: /opt/llvm-mingw + key: llvm-mingw-${{ runner.os }}-${{ inputs.llvm-mingw-version }}-${{ inputs.host-arch }} + + - name: Install llvm-mingw ${{ inputs.llvm-mingw-version }} (Linux ${{ inputs.host-arch }}) + if: runner.os == 'Linux' && steps.cache-llvm-linux.outputs.cache-hit != 'true' + shell: bash + run: | + llvm_mingw_version="${{ inputs.llvm-mingw-version }}" + llvm_arch="${{ inputs.host-arch }}" + mkdir -p /opt/llvm-mingw + cd /opt/llvm-mingw + curl -L https://github.com/mstorsjo/llvm-mingw/releases/download/20220906/llvm-mingw-${llvm_mingw_version}-ucrt-ubuntu-18.04-${llvm_arch}.tar.xz | tar xJ --strip-components=1 + + - name: Set up llvm-mingw (Linux) + id: setup-llvm-linux + if: runner.os == 'Linux' + shell: bash + run: | + cd /opt/llvm-mingw + if [ ! -x bin/clang++ ]; then + echo "$PWD/bin/clang++ not found or not executable!" + exit 1 + fi + echo "llvm-path=$PWD/llvm-mingw" >> $GITHUB_OUTPUT + echo "$PWD/bin" >> $GITHUB_PATH diff --git a/.github/actions/setup-llvm-msvc/action.yml b/.github/actions/setup-llvm-msvc/action.yml new file mode 100644 index 000000000..e5a696a9f --- /dev/null +++ b/.github/actions/setup-llvm-msvc/action.yml @@ -0,0 +1,48 @@ +name: 'Set up LLVM for MSVC' +description: 'Set up upstream LLVM for targeting MSVC ABI' +inputs: + llvm-version: + description: 'LLVM version' + required: true + default: '17.0.5' +outputs: + llvm-path: + description: "The path in which LLVM is installed to" + value: ${{ steps.setup-llvm.outputs.llvm-path }} +runs: + using: "composite" + steps: + - name: Cache LLVM and tools + id: cache-llvm + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: | + .LLVM + .llvm-utils + key: llvm-msvc-${{ runner.os }}-${{ inputs.llvm-version }} + + - name: Install LLVM ${{ inputs.llvm-version }} + if: steps.cache-llvm.outputs.cache-hit != 'true' + shell: pwsh + run: | + Invoke-WebRequest "https://github.com/llvm/llvm-project/releases/download/llvmorg-${{ inputs.llvm-version }}/LLVM-${{ inputs.llvm-version }}-win64.exe" -OutFile LLVM-installer.exe + .\LLVM-installer.exe /S "/D=$pwd\.LLVM" | Out-Null + rm LLVM-installer.exe + + # Not using the LLVM tools that comes with MSVC. + - name: Download LLVM build tools for msbuild + if: steps.cache-llvm.outputs.cache-hit != 'true' + shell: pwsh + run: | + Invoke-WebRequest "https://github.com/zufuliu/llvm-utils/releases/download/v22.09/LLVM_VS2017.zip" -OutFile LLVM_VS2017.zip + 7z x -y "LLVM_VS2017.zip" -o"$pwd\.llvm-utils\" + rm LLVM_VS2017.zip + + - name: Set up LLVM build tools for msbuild + id: setup-llvm + shell: pwsh + run: | + if (!(Test-Path "$pwd\.LLVM\bin\clang-cl.exe")) { exit 1 } + Add-Content $env:GITHUB_PATH "$pwd\.LLVM\bin" + Add-Content $env:GITHUB_OUTPUT "llvm-path=$pwd\.LLVM" + cmd /c ".llvm-utils\LLVM_VS2017\install.bat" 1 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..9557baa7a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "daily" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + cooldown: + default-days: 7 diff --git a/.github/instructions/cppwinrt.instructions.md b/.github/instructions/cppwinrt.instructions.md new file mode 100644 index 000000000..eae2fc3c6 --- /dev/null +++ b/.github/instructions/cppwinrt.instructions.md @@ -0,0 +1,58 @@ +# C++/WinRT Codebase — Agent Instructions + +## Repository Structure + +- `cppwinrt/` — The cppwinrt.exe code generator (C++ source) + - `main.cpp` — CLI parsing, namespace iteration, SCC detection, .ixx orchestration + - `file_writers.h` — All file generation functions (headers, .ixx modules, component stubs) + - `code_writers.h` — Code-level writing utilities (guards, namespace wrappers, type writers) + - `type_writers.h` — Type formatting (ABI signatures, names, GUIDs) + - `component_writers.h` — Component authoring code generation + - `helpers.h` — Metadata reading helpers + - `settings.h` — Global settings populated from CLI args + - `text_writer.h` — Core text writer infrastructure +- `strings/` — String literal `.h` files embedded by the prebuild step. Changes require: delete prebuild.exe → rebuild solution +- `nuget/` — MSBuild targets, props, and NuGet packaging + - `Microsoft.Windows.CppWinRT.targets` — Main MSBuild integration (projections, module support) +- `test/` — Test projects + - `test/test_cpp20_module/` — Standalone module test (in main solution) + - `test/nuget/` — NuGet integration tests (multi-project module chain) +- `docs/` — Documentation +- `natvis/` — Visual Studio debug visualizer (includes strings/*.h in its pch.h — add new files there too) + +## Build Process + +- Use VS Developer Shell for correct toolset environment +- `cmake --build build --config Release --target cppwinrt` for cppwinrt.exe (or MSBuild: `msbuild cppwinrt\cppwinrt.vcxproj /p:Configuration=Release /p:Platform=x64`) +- NuGet tests: `msbuild test\nuget\NuGetTest.sln /p:Configuration=Release /p:Platform=x64` +- Module test projects require v145 toolset (VS 2026). Directory.Build.Props selects v145 when VisualStudioVersion >= 18.0 (VS 2026) and falls back to v143 otherwise; override `` in the Configuration PropertyGroup to force a specific toolset + +## Key Patterns + +### Prebuild Embedding +The `strings/*.h` files are embedded as string literals by the prebuild step. If you modify any `strings/*.h` file, you must delete `prebuild.exe` and rebuild the entire solution for changes to take effect. + +### Module Guard Macros +- `WINRT_IMPL_BUILD_MODULE` — Defined in .ixx global fragment. Makes `WINRT_EXPORT` expand to `export extern "C++"` and suppresses `#include` of dependencies +- `WINRT_IMPORT_MODULE` — Defined by consumers who import modules. Makes namespace headers and base.h no-op (types come from module import) +- `WINRT_EXPORT` — Empty in header mode, `export extern "C++"` in module mode. Defined in `winrt/base_macros.h` +- `WINRT_IMPL_STD_EXPORT` — Empty in header mode, `extern "C++"` (without export) in module mode. Used for `namespace std` specializations + +### Generated Header Structure +Each namespace produces four header files: +- `impl/.0.h` — Forward declarations, ABIs, GUIDs, categories +- `impl/.1.h` — Interface definitions +- `impl/.2.h` — Delegates, structs, class implementations +- `.h` — Public API surface (consume definitions, class wrappers, operators) + +### Dependency Collection +When generating headers with `-modules`, writer.depends is inspected after each header to build a namespace dependency graph. This graph drives SCC detection and module import lists. + +## Common Gotchas + +- Module IFCs are NOT compatible across toolset versions — always clean rebuild when switching +- PCH and modules can coexist but PCH should NOT include winrt headers when using modules +- `/ifcSearchDir` works for the module dependency scanner to find IFCs, but cross-component modules may need explicit `/reference "name=path.ifc"` flags +- `import std;` requires `BuildStlModules=true` +- `strings/base_macros.h` is the single source of truth for shared macros (generated as `winrt/base_macros.h`). New macros go in `base_macros.h` only +- When adding, removing, or heavily refactoring `strings/*.h` files, always rebuild the natvis project (`natvis/cppwinrtvisualizer.sln`) to verify — it includes strings/*.h directly in its pch.h diff --git a/.github/instructions/modules.instructions.md b/.github/instructions/modules.instructions.md new file mode 100644 index 000000000..3deee2955 --- /dev/null +++ b/.github/instructions/modules.instructions.md @@ -0,0 +1,40 @@ +# C++/WinRT Modules — Agent Instructions + +## Module Architecture (v2 — Per-Namespace) + +Each WinRT namespace gets its own C++20 named module (`winrt.`). Base infrastructure is in `winrt_base` and `winrt_numerics`. + +### Code Generator Flow + +1. `-modules` flag enables .ixx generation in cppwinrt.exe +2. `-module_include`/`-module_exclude` filter which namespaces get modules +3. Headers are generated with dependency tracking (deps_ptr parameter) +4. Tarjan's SCC algorithm detects cyclic namespace groups +5. Standalone namespaces get individual .ixx; cyclic groups get consolidated SCC owner + re-export stubs + +### MSBuild Flow + +1. `CppWinRTBuildModule=true` adds `-modules` to cppwinrt.exe invocations +2. `CppWinRTAddModuleInterfaces` discovers `$(GeneratedFilesDir)winrt\*.ixx` and adds to ClCompile +3. `CppWinRTConsumeModule` metadata on ProjectReference controls per-reference IFC sharing +4. `CppWinRTResolveModuleReferences` calls `CppWinRTGetModuleOutputs` on tagged references +5. Platform projection suppresses `-modules` when consuming pre-built IFCs + +### Critical Invariants + +- Module guards are unconditional in codegen — `-modules` controls .ixx generation and component codegen (module.g.cpp, stub .cpp) +- SCC owner is alphabetically first namespace in the cycle +- All .ixx filenames use `winrt` prefix: `winrt.Windows.Foundation.ixx`, `winrt_base.ixx` +- Shared macros live in `strings/base_module.h` → generates `winrt/macros.h`. `base_macros.h` includes it via `#include "winrt/macros.h"` + +### Testing Changes + +After modifying cppwinrt.exe code: +1. Rebuild cppwinrt.exe: `msbuild cppwinrt\cppwinrt.vcxproj /p:Configuration=Release /p:Platform=x64` +2. Run standalone test: build `test_cpp20_module` in main solution +3. Run NuGet tests: `msbuild test\nuget\NuGetTest.sln /p:Configuration=Release /p:Platform=x64` + +After modifying targets: +1. Clean NuGet test obj dirs +2. Build with `/v:normal` and check "Module providers:" diagnostic messages +3. Inspect `.rsp` files in `obj/` to verify correct `-modules` flag placement diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..88999e247 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,3 @@ +What's this all about? + +Fixes: #0000 âŦ…ī¸ Be sure to refer to an existing issue here! diff --git a/.github/workflows/check-line-endings.yml b/.github/workflows/check-line-endings.yml new file mode 100644 index 000000000..3891aec09 --- /dev/null +++ b/.github/workflows/check-line-endings.yml @@ -0,0 +1,32 @@ +name: Check Line Endings + +on: + pull_request: + push: + branches: + - master + +jobs: + check-line-endings: + name: Enforce .gitattributes line endings + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Check for line ending violations + run: | + # Re-normalize all files according to .gitattributes + git add --renormalize . + + # Check if renormalization changed anything + if git diff --cached --name-only | grep -q .; then + echo "::error::The following files have line endings that don't match .gitattributes settings:" + git diff --cached --name-only + echo "" + echo "To fix, run:" + echo " git add --renormalize ." + echo " git commit -m 'Normalize line endings'" + exit 1 + fi + + echo "All files have correct line endings." diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..5e2677fed --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,405 @@ +name: CI Tests + +on: + pull_request: + push: + branches: + - master + +jobs: + test-msvc-cppwinrt-build: + name: '${{ matrix.compiler }}: Build (${{ matrix.arch }}, ${{ matrix.config }}, ${{ matrix.toolchain.platform_toolset }})' + strategy: + matrix: + compiler: [MSVC, clang-cl] + arch: [x86, x64, arm64] + config: [Debug, Release] + toolchain: + - image: windows-2025-vs2026 + platform_toolset: v145 + exclude: + - arch: arm64 + config: Debug + - compiler: clang-cl + arch: arm64 + - compiler: clang-cl + config: Release + runs-on: ${{ matrix.toolchain.image }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Download nuget + run: | + mkdir ".\.nuget" + Invoke-WebRequest "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile ".\.nuget\nuget.exe" + + - name: Find VsDevCmd.bat + run: | + $VSDevCmd = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere" -latest -find Common7\tools\VSDevCmd.bat + if (!$VSDevCmd) { exit 1 } + echo "Using VSDevCmd: ${VSDevCmd}" + Add-Content $env:GITHUB_ENV "VSDevCmd=$VSDevCmd" + + - name: Prepare build flags + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + $target_version = "999.999.999.999" + $props = "Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" + if ("${{ matrix.compiler }}" -eq "clang-cl") { + $props += ",Clang=1,PlatformToolset=ClangCl" + } else { + $props += ",PlatformToolset=${{ matrix.toolchain.platform_toolset }}" + } + Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:$props" + + - name: Restore nuget packages + run: | + cmd /c "$env:VSDevCmd" "&" nuget restore cppwinrt.sln + + - name: Build fast_fwd + run: | + cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" cppwinrt.sln /t:fast_fwd + + - name: Build x86 prebuild tool + if: matrix.arch == 'arm64' + run: | + cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" /p:Platform=x86 cppwinrt.sln /t:cppwinrt + + - name: Build cppwinrt + run: | + cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" cppwinrt.sln /t:cppwinrt + + - name: Upload built executables + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-${{ matrix.toolchain.platform_toolset }}-bin + path: | + _build/${{ matrix.arch }}/${{ matrix.config }}/*.exe + _build/${{ matrix.arch }}/${{ matrix.config }}/*.dll + _build/${{ matrix.arch }}/${{ matrix.config }}/*.winmd + _build/${{ matrix.arch }}/${{ matrix.config }}/*.lib + _build/${{ matrix.arch }}/${{ matrix.config }}/*.pdb + + - name: Run cppwinrt to build projection + if: matrix.arch != 'arm64' + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + & "_build\$target_platform\$target_configuration\cppwinrt.exe" -in local -out _build\$target_platform\$target_configuration -verbose + + test-msvc-cppwinrt-test: + name: '${{ matrix.compiler }}: Test [${{ matrix.test_exe }}] (${{ matrix.arch }}, ${{ matrix.config }}, ${{ matrix.toolchain.platform_toolset }})' + needs: test-msvc-cppwinrt-build + strategy: + fail-fast: false + matrix: + compiler: [MSVC, clang-cl] + arch: [x86, x64, arm64] + config: [Debug, Release] + test_exe: [test, test_nocoro, test_cpp20, test_cpp20_no_sourcelocation, test_cpp20_module, test_fast, test_slow, test_old, test_module_lock_custom, test_module_lock_none] + toolchain: + - image: windows-2025-vs2026 + platform_toolset: v145 + exclude: + - arch: arm64 + config: Debug + - compiler: clang-cl + arch: arm64 + - compiler: clang-cl + config: Release + # C++20 named modules require the MSVC v145 toolset; clang-cl is not supported. + - compiler: clang-cl + test_exe: test_cpp20_module + runs-on: ${{ matrix.toolchain.image }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Fetch cppwinrt executables + if: matrix.arch != 'arm64' + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-${{ matrix.toolchain.platform_toolset }}-bin + path: _build/${{ matrix.arch }}/${{ matrix.config }}/ + + - name: Fetch x86 cppwinrt executables (arm64 only) + if: matrix.arch == 'arm64' + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: msvc-build-${{ matrix.compiler}}-x86-Release-${{ matrix.toolchain.platform_toolset }}-bin + path: _build/x86/Release/ + + - name: Download nuget + run: | + mkdir ".\.nuget" + Invoke-WebRequest "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile ".\.nuget\nuget.exe" + + - name: Find VsDevCmd.bat + run: | + $VSDevCmd = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere" -latest -find Common7\tools\VSDevCmd.bat + if (!$VSDevCmd) { exit 1 } + echo "Using VSDevCmd: ${VSDevCmd}" + Add-Content $env:GITHUB_ENV "VSDevCmd=$VSDevCmd" + + - name: Prepare build flags + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + $target_version = "999.999.999.999" + $props = "Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version" + if ("${{ matrix.compiler }}" -eq "clang-cl") { + $props += ",Clang=1,PlatformToolset=ClangCl" + } else { + $props += ",PlatformToolset=${{ matrix.toolchain.platform_toolset }}" + } + Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:$props" + + - name: Restore nuget packages + run: | + cmd /c "$env:VSDevCmd" "&" nuget restore cppwinrt.sln + + - name: Remove cppwinrt dependency from all test projects + run: | + # HACK: We already have a built exe, so we want to avoid rebuilding cppwinrt + mv cppwinrt.sln cppwinrt.sln.orig + Get-Content cppwinrt.sln.orig | + Where-Object { -not $_.Contains("{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}") } | + Set-Content cppwinrt.sln + + - name: Patch catch.hpp to make it build with ANSI colour + run: | + # HACK: Remove include and the isatty call in catch.hpp to make ANSI colour build work + mv test/catch.hpp test/catch.hpp.orig + Get-Content test/catch.hpp.orig | + Where-Object { -not $_.Contains("#include ") } | + ForEach-Object { + $_.Replace("isatty(STDOUT_FILENO)", "false") + } | + Set-Content test/catch.hpp + + - name: Run cppwinrt to build projection + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + $cppwinrt_path = "_build\$target_platform\$target_configuration\cppwinrt.exe" + if ($target_platform -eq "arm64") { + $cppwinrt_path = "_build\x86\Release\cppwinrt.exe" + } + & $cppwinrt_path -in local -out _build\$target_platform\$target_configuration -verbose + + - name: Build test '${{ matrix.test_exe }}' + run: | + $test_proj = "${{ matrix.test_exe }}" + if ($test_proj -eq "test_old") { + $test_proj = "old_tests\test_old" + } + + cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor /p:TestsUseAnsiColor=1 "$env:msbuild_config_props" cppwinrt.sln /t:test\$test_proj + + - name: Run tests in '${{ matrix.test_exe }}' one by one + if: matrix.compiler == 'clang-cl' + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + $test_exe = "${{ matrix.test_exe }}" + $test_path = "_build\$target_platform\$target_configuration\$test_exe.exe" + if (!(Test-Path $test_path)) { + echo "::error::Test $test_exe is missing." + exit 1 + } + $test_names = @( & $test_path --list-test-names-only ) + $failed_tests = 0 + foreach ($test_name in $test_names) { + echo "::group::Running test $test_name" + $escaped = $test_name.Replace("\", "\\").Replace(",", "\,").Replace("[", "\[") + & $test_path --use-colour yes --warn NoTests "$escaped" + echo "::endgroup::" + if ($LastExitCode -ne 0) { + $failed_tests += 1 + # Add a newline in case test exited abnormally without newline + echo "" + echo "::error::Test $test_exe/'$test_name' failed with exit code $LastExitCode!" + } + } + if ($failed_tests -eq 0) { + echo "All tests in $test_exe passed." + } else { + echo "$failed_tests failed in $test_exe." + exit 1 + } + + - name: Run test '${{ matrix.test_exe }}' + if: matrix.arch != 'arm64' + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + $test_exe = "${{ matrix.test_exe }}" + $test_path = "_build\$target_platform\$target_configuration\$test_exe.exe" + if (!(Test-Path $test_path)) { + echo "::error::Test $test_exe is missing." + exit 1 + } + & $test_path --use-colour yes + + - name: Upload arm64 test executables + if: matrix.arch == 'arm64' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: msvc-tests-${{ matrix.test_exe }}-${{ matrix.compiler }}-${{ matrix.arch }}-${{ matrix.config }}-${{ matrix.toolchain.platform_toolset }}-bin + path: | + _build/${{ matrix.arch }}/${{ matrix.config }}/*.exe + _build/${{ matrix.arch }}/${{ matrix.config }}/*.dll + _build/${{ matrix.arch }}/${{ matrix.config }}/*.winmd + _build/${{ matrix.arch }}/${{ matrix.config }}/*.lib + _build/${{ matrix.arch }}/${{ matrix.config }}/*.pdb + + build-linux-cross-cppwinrt: + name: 'cross: Cross-build from Linux' + strategy: + matrix: + arch: [i686, x86_64] + runs-on: ubuntu-22.04 + env: + CMAKE_COLOR_DIAGNOSTICS: 1 + CLICOLOR_FORCE: 1 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Install cross compiler + run: | + arch=${{ matrix.arch }} + sudo apt-get install g++-mingw-w64-${arch/_/-} + sudo update-alternatives --set "${{ matrix.arch }}-w64-mingw32-gcc" "/usr/bin/${{ matrix.arch }}-w64-mingw32-gcc-posix" + sudo update-alternatives --set "${{ matrix.arch }}-w64-mingw32-g++" "/usr/bin/${{ matrix.arch }}-w64-mingw32-g++-posix" + + - name: Cross-build cppwinrt + run: | + cmake -S . -B build/cross_x64/ --toolchain cross-mingw-toolchain.cmake \ + -DCMAKE_SYSTEM_PROCESSOR=${{ matrix.arch }} \ + -DCMAKE_BUILD_TYPE=RelWithDebInfo \ + -DCMAKE_CXX_FLAGS="-static" \ + -DCMAKE_INSTALL_PREFIX=$PWD/install/ + cmake --build build/cross_x64/ --target install -j2 + + - name: Upload cppwinrt.exe + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: cross-build-${{ matrix.arch }}-bin + path: install/bin/cppwinrt.exe + + build-msvc-natvis: + name: 'Build natvis' + strategy: + matrix: + arch: [x86, x64, arm64] + config: [Release] + Deployment: [Component, Standalone] + runs-on: windows-2025-vs2026 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Download nuget + run: | + mkdir ".\.nuget" + Invoke-WebRequest "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile ".\.nuget\nuget.exe" + + - name: Find VsDevCmd.bat + run: | + $VSDevCmd = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere" -latest -find Common7\tools\VSDevCmd.bat + if (!$VSDevCmd) { exit 1 } + echo "Using VSDevCmd: ${VSDevCmd}" + Add-Content $env:GITHUB_ENV "VSDevCmd=$VSDevCmd" + + - name: Prepare build flags + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + $target_version = "999.999.999.999" + Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version,PlatformToolset=v145" + + - name: Restore nuget packages + run: | + cmd /c "$env:VSDevCmd" "&" nuget restore natvis\cppwinrtvisualizer.sln + + - name: Build natvis + run: | + cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" /p:Deployment=${{ matrix.Deployment }} natvis\cppwinrtvisualizer.sln + + build-msvc-nuget-test: + name: 'Build nuget test (${{ matrix.arch }}, ${{ matrix.toolchain.platform_toolset }})' + needs: test-msvc-cppwinrt-build + strategy: + matrix: + compiler: + - MSVC + arch: [x86, x64] + config: [Release] + toolchain: + - image: windows-2025-vs2026 + platform_toolset: v145 + runs-on: ${{ matrix.toolchain.image }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Fetch cppwinrt executables + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: msvc-build-${{ matrix.compiler}}-${{ matrix.arch }}-${{ matrix.config }}-${{ matrix.toolchain.platform_toolset }}-bin + path: _build/${{ matrix.arch }}/${{ matrix.config }}/ + + - name: Download nuget + run: | + mkdir ".\.nuget" + Invoke-WebRequest "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile ".\.nuget\nuget.exe" + + - name: Find VsDevCmd.bat + run: | + $VSDevCmd = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere" -latest -find Common7\tools\VSDevCmd.bat + if (!$VSDevCmd) { exit 1 } + echo "Using VSDevCmd: ${VSDevCmd}" + Add-Content $env:GITHUB_ENV "VSDevCmd=$VSDevCmd" + + - name: Prepare build flags + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + $target_version = "999.999.999.999" + Add-Content $env:GITHUB_ENV "msbuild_config_props=/p:Configuration=$target_configuration,Platform=$target_platform,CppWinRTBuildVersion=$target_version,PlatformToolset=${{ matrix.toolchain.platform_toolset }}" + + - name: Restore nuget packages + run: | + cmd /c "$env:VSDevCmd" "&" nuget restore test\nuget\NugetTest.sln + + - name: Run cppwinrt to build projection + run: | + $target_configuration = "${{ matrix.config }}" + $target_platform = "${{ matrix.arch }}" + & "_build\$target_platform\$target_configuration\cppwinrt.exe" -in local -out _build\$target_platform\$target_configuration -verbose + + - name: Run nuget test + run: | + cmd /c "$env:VSDevCmd" "&" msbuild /m /clp:ForceConsoleColor "$env:msbuild_config_props" test\nuget\NugetTest.sln + + build-nuget: + name: Build nuget package with MSVC + runs-on: windows-2025-vs2026 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Package + run: | + $VSDevCmd = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere" -latest -find Common7\tools\VSDevCmd.bat + if (!$VSDevCmd) { exit 1 } + echo "Using VSDevCmd: ${VSDevCmd}" + cmd /c "${VSDevCmd}" "&" nuget.exe restore cppwinrt.sln + cmd /c "${VSDevCmd}" "&" build_nuget.cmd + if (!(Test-Path "*.nupkg")) { + echo "::error::Output nuget package not found!" + exit 1 + } + + - name: Upload nuget package artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: package + path: "*.nupkg" diff --git a/.gitignore b/.gitignore index 39ccd342c..9493fdad5 100644 --- a/.gitignore +++ b/.gitignore @@ -8,10 +8,11 @@ *.nupkg test*.xml test*_results.txt +test_failures.txt build packages Debug Release Generated Files obj -vsix/LICENSE \ No newline at end of file +vsix/LICENSE diff --git a/.pipelines/OneBranch.Official.yml b/.pipelines/OneBranch.Official.yml new file mode 100644 index 000000000..158d3bf4e --- /dev/null +++ b/.pipelines/OneBranch.Official.yml @@ -0,0 +1,157 @@ +parameters: # parameters are shown up in ADO UI in a build queue time +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + +variables: +- template: variables/version.yml + parameters: + OfficialBuild: true +- template: variables/OneBranchVariables.yml + parameters: + debug: ${{ parameters.debug }} + +name: 3.0.$(date:yyMMdd)$(rev:.r) + +trigger: none + +resources: + repositories: + - repository: templates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/Microsoft.Official.yml@templates + parameters: + platform: + name: 'windows_undocked' + product: 'build_tools' + + featureFlags: + WindowsHostVersion: + Version: 2022 + + cloudvault: + enabled: false + + globalSdl: + isNativeCode: true + asyncSdl: + enabled: true + tsa: + enabled: true + codeql: + compiled: + enabled: true + tsaEnabled: true + + stages: + - stage: build + jobs: + - template: .pipelines/jobs/OneBranchBuild.yml@self + parameters: + BuildConfiguration: $(BuildConfiguration) + BuildVersion: $(BuildVersion) + OfficialBuild: true + + - stage: vpack + dependsOn: build + jobs: + - job: Compiler_vpack + pool: + type: windows + variables: + ob_outputDirectory: '$(Build.SourcesDirectory)\out' + ob_createvpack_enabled: true + ob_createvpack_packagename: CppWinRT.Compiler + ob_createvpack_owneralias: cpp4uwpt + ob_createvpack_description: C++/WinRT Compiler + ob_createvpack_provData: true + ob_createvpack_versionAs: parts + ob_createvpack_majorVer: $(MajorVersion) + ob_createvpack_minorVer: $(MinorVersion) + ob_createvpack_patchVer: $(PatchVersion) + ob_createvpack_metadata: $(Build.SourceBranchName).x86.$(Build.BuildNumber).$(Build.SourceVersion) + ob_createvpack_target: $(OSBuildToolsRoot)\cppwinrt + + steps: + - task: UseDotNet@2 + continueOnError: true + inputs: + packageType: 'runtime' + version: '6.x' + performMultiLevelLookup: true + + - task: DownloadPipelineArtifact@2 + displayName: 'Download x86 artifacts' + inputs: + artifactName: 'drop_build_x86' + targetPath: '$(Build.SourcesDirectory)/x86' + + - task: DownloadPipelineArtifact@2 + displayName: 'Download x64 artifacts' + inputs: + artifactName: 'drop_build_x64' + targetPath: '$(Build.SourcesDirectory)/x64' + + - task: DownloadPipelineArtifact@2 + displayName: 'Download arm64 artifacts' + inputs: + artifactName: 'drop_build_arm64' + targetPath: '$(Build.SourcesDirectory)/arm64' + + - task: CopyFiles@2 + displayName: 'Stage compiler vpack contents' + inputs: + SourceFolder: $(Build.SourcesDirectory)/x86/cppwinrt + Contents: | + cppwinrt.exe + cppwinrt.pdb + TargetFolder: $(ob_outputDirectory) + + - task: CmdLine@2 + displayName: 'Stage MSBuild vpack contents' + inputs: + script: | + set TargetDir=$(ob_outputDirectory) + cd %TargetDir% + + copy $(Build.SourcesDirectory)\vsix\Microsoft.Cpp.CppWinRT.props + copy $(Build.SourcesDirectory)\nuget\Microsoft.Windows.CppWinRT.props Microsoft.Cpp.CppWinRTEnabled.props + copy $(Build.SourcesDirectory)\nuget\Microsoft.Windows.CppWinRT.targets Microsoft.Cpp.CppWinRTEnabled.targets + copy $(Build.SourcesDirectory)\nuget\CppWinrtRules.Project.xml CppWinrtRules.Project.xml + echo d | xcopy $(Build.SourcesDirectory)\x86\cppwinrt_fast_forwarder.lib build\native\lib\i386 + echo d | xcopy $(Build.SourcesDirectory)\x86\cppwinrt_fast_forwarder.lib build\native\lib\Win32 + echo d | xcopy $(Build.SourcesDirectory)\x64\cppwinrt_fast_forwarder.lib build\native\lib\amd64 + echo d | xcopy $(Build.SourcesDirectory)\x64\cppwinrt_fast_forwarder.lib build\native\lib\x64 + echo d | xcopy $(Build.SourcesDirectory)\arm64\cppwinrt_fast_forwarder.lib build\native\lib\arm64 + + - stage: NuGet + dependsOn: build + jobs: + - template: .pipelines/jobs/OneBranchNuGet.yml@self + parameters: + BuildConfiguration: $(BuildConfiguration) + NugetPackageVersion: $(NugetPackageVersion) + OfficialBuild: true + + - stage: Test + dependsOn: build + jobs: + - template: .pipelines/jobs/OneBranchTest.yml@self + parameters: + BuildConfiguration: $(BuildConfiguration) + BuildVersion: $(BuildVersion) + + - stage: Vsix + dependsOn: NuGet + jobs: + - template: .pipelines/jobs/OneBranchVsix.yml@self + parameters: + BuildConfiguration: $(BuildConfiguration) + BuildVersion: $(BuildVersion) + NugetPackageVersion: $(NugetPackageVersion) + OfficialBuild: true diff --git a/.pipelines/OneBranch.PullRequest.yml b/.pipelines/OneBranch.PullRequest.yml new file mode 100644 index 000000000..d92dccaa2 --- /dev/null +++ b/.pipelines/OneBranch.PullRequest.yml @@ -0,0 +1,76 @@ +parameters: +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + +variables: +- template: variables/version.yml +- template: variables/OneBranchVariables.yml + parameters: + debug: ${{ parameters.debug }} + +name: PullRequest_3.0.$(date:yyMMdd)$(rev:.r) + +trigger: none + +pool: + type: windows + +resources: + repositories: + - repository: templates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/Microsoft.NonOfficial.yml@templates + parameters: + platform: + name: 'windows_undocked' + product: 'build_tools' + + featureFlags: + WindowsHostVersion: + Version: 2022 + + globalSdl: + isNativeCode: true + tsa: + enabled: false + sbom: + enabled: true + + stages: + - stage: build + jobs: + - template: .pipelines/jobs/OneBranchBuild.yml@self + parameters: + BuildConfiguration: $(BuildConfiguration) + BuildVersion: $(BuildVersion) + + - stage: NuGet + dependsOn: build + jobs: + - template: .pipelines/jobs/OneBranchNuGet.yml@self + parameters: + BuildConfiguration: $(BuildConfiguration) + NugetPackageVersion: $(NugetPackageVersion) + + - stage: Test + dependsOn: build + jobs: + - template: .pipelines/jobs/OneBranchTest.yml@self + parameters: + BuildConfiguration: $(BuildConfiguration) + BuildVersion: $(BuildVersion) + + - stage: Vsix + dependsOn: NuGet + jobs: + - template: .pipelines/jobs/OneBranchVsix.yml@self + parameters: + BuildConfiguration: $(BuildConfiguration) + BuildVersion: $(BuildVersion) + NugetPackageVersion: $(NugetPackageVersion) diff --git a/.pipelines/build.yml b/.pipelines/build.yml new file mode 100644 index 000000000..ebe8ad041 --- /dev/null +++ b/.pipelines/build.yml @@ -0,0 +1,640 @@ +# 'Allow scripts to access the OAuth token' was selected in pipeline. Add the following YAML to any steps requiring access: +# env: +# MY_ACCESS_TOKEN: $(System.AccessToken) +# Variable 'MajorVersion' was defined in the Variables tab +# Variable 'MinorVersion' was defined in the Variables tab +trigger: + branches: + include: + - refs/heads/master + batch: True +schedules: +- cron: 0 18 * * * + branches: + include: + - refs/heads/master +name: $(MajorVersion).$(MinorVersion).$(date:yyMMdd)$(rev:.r) + +variables: + manualRelease: $[and(eq(variables['BuildConfiguration'], 'release'), in(variables['Build.Reason'], 'Manual'))] + +jobs: +- job: BuildBinaries + pool: + name: Azure Pipelines + vmImage: 'windows-2022' + demands: + - msbuild + strategy: + matrix: + x86: + buildPlatform: 'x86' + x64: + buildPlatform: 'x64' + arm64: + buildPlatform: 'arm64' + + steps: + - checkout: self + clean: true + persistCredentials: True + + - task: NuGetToolInstaller@1 + displayName: Use NuGet 6.0.2 + continueOnError: True + inputs: + versionSpec: 6.0.2 + + - task: NuGetCommand@2 + displayName: NuGet restore + inputs: + command: 'restore' + feedsToUse: config + nugetConfigPath: NuGet.config + + - task: CmdLine@2 + displayName: Build Tools + inputs: + script: | + if "%VSCMD_VER%"=="" ( + pushd c: + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" >nul 2>&1 + popd + ) + + build_test_all.cmd $(BuildPlatform) $(BuildConfiguration) $(Build.BuildNumber) true + failOnStderr: true + + - task: ComponentGovernanceComponentDetection@0 + displayName: Component Detection + condition: eq(variables['BuildPlatform'], 'x64') + + - task: PublishTestResults@2 + displayName: Publish Test Results + enabled: False + + - task: CopyFiles@2 + displayName: Stage cppwinrt.* + condition: and(eq(variables['BuildPlatform'], 'x86'), eq(variables.manualRelease, 'true')) + inputs: + SourceFolder: $(Build.SourcesDirectory)\_build\$(BuildPlatform)\$(BuildConfiguration) + Contents: | + cppwinrt.exe + cppwinrt.pdb + TargetFolder: $(Build.ArtifactStagingDirectory)\cppwinrt + + - task: CopyFiles@2 + displayName: Stage Component cppwinrtvisualizer.* + condition: and(or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'arm64')), eq(variables.manualRelease, 'true')) + inputs: + SourceFolder: $(Build.SourcesDirectory)\natvis\$(BuildPlatform)\$(BuildConfiguration)\Component + Contents: | + cppwinrtvisualizer.dll + cppwinrtvisualizer.pdb + cppwinrtvisualizer.vsdconfig + TargetFolder: $(Build.ArtifactStagingDirectory)\Component + + - task: CopyFiles@2 + displayName: Stage Standalone cppwinrtvisualizer.* + condition: and(or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'arm64')), eq(variables.manualRelease, 'true')) + inputs: + SourceFolder: $(Build.SourcesDirectory)\natvis\$(BuildPlatform)\$(BuildConfiguration)\Standalone + Contents: | + cppwinrtvisualizer.dll + cppwinrtvisualizer.pdb + cppwinrtvisualizer.vsdconfig + TargetFolder: $(Build.ArtifactStagingDirectory)\Standalone + + - task: CopyFiles@2 + displayName: Stage cppwinrt_fast_forwarder.lib + condition: eq(variables.manualRelease, 'true') + inputs: + SourceFolder: $(Build.SourcesDirectory)\_build\$(BuildPlatform)\$(BuildConfiguration) + Contents: cppwinrt_fast_forwarder.lib + TargetFolder: $(Build.ArtifactStagingDirectory) + + - task: ManifestGeneratorTask@0 + displayName: 'Manifest Generator ' + condition: and(eq(variables['BuildPlatform'], 'x86'), eq(variables.manualRelease, 'true')) + inputs: + BuildDropPath: $(Build.ArtifactStagingDirectory)\cppwinrt + + - task: PublishPipelineArtifact@0 + displayName: Publish Artifacts + condition: eq(variables.manualRelease, 'true') + inputs: + artifactName: $(BuildConfiguration)_$(BuildPlatform) + targetPath: $(Build.ArtifactStagingDirectory) + + - task: PublishSymbols@2 + displayName: Publish symbols + condition: eq(variables.manualRelease, 'true') + inputs: + SymbolsFolder: $(Build.ArtifactStagingDirectory) + SearchPattern: '**/*.pdb' + SymbolServerType: TeamServices + SymbolsProduct: CppWinRT + +- job: BuildInternal + displayName: Build Internal Packages (VPacks) + dependsOn: BuildBinaries + condition: and(succeeded(), ne(variables['SkipInternalPackages'], 'true'), eq(variables.manualRelease, 'true')) + pool: + name: Azure Pipelines + vmImage: 'windows-2022' + steps: + - checkout: self + clean: true + persistCredentials: True + + - task: PkgESSetupBuild@12 + displayName: Package ES - Setup Build + inputs: + branchVersionExcludeBranch: master + disableWorkspace: true + disableMsbuildVersion: true + disableBuildTools: true + + - task: DownloadPipelineArtifact@1 + displayName: Download x86 Artifacts + inputs: + artifactName: $(BuildConfiguration)_x86 + downloadPath: $(Build.SourcesDirectory)\x86 + + - task: DownloadPipelineArtifact@1 + displayName: Download x64 Artifacts + inputs: + artifactName: $(BuildConfiguration)_x64 + downloadPath: $(Build.SourcesDirectory)\x64 + + - task: DownloadPipelineArtifact@1 + displayName: Download arm64 Artifacts + inputs: + artifactName: $(BuildConfiguration)_arm64 + downloadPath: $(Build.SourcesDirectory)\arm64 + + - task: CmdLine@2 + displayName: Parse PatchVersion + inputs: + script: 'for /f "tokens=3,4 delims=." %%i in ("$(Build.BuildNumber)") do @echo ##vso[task.setvariable variable=PatchVersion;]%%i%%j ' + failOnStderr: true + + - task: CmdLine@2 + displayName: Copy compiler contents for internal signing + inputs: + script: | + md $(Build.SourcesDirectory)\x86\tempsign + echo Build Sources Directory: + dir $(Build.SourcesDirectory) + echo x86 + dir $(Build.SourcesDirectory)\x86 + echo cppwinrt + dir $(Build.SourcesDirectory)\x86\cppwinrt + xcopy $(Build.SourcesDirectory)\x86\cppwinrt\*.* $(Build.SourcesDirectory)\x86\tempsign /icefzy + + - task: EsrpCodeSigning@2 + displayName: Sign Compiler vPack for internal use + inputs: + ConnectedServiceName: bf601a97-455d-4977-b248-07b90c96eed9 + FolderPath: $(Build.SourcesDirectory)\x86\tempsign + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "KeyCode" : "CP-458204", + "OperationCode" : "SigntoolSign", + "Parameters" : { + "OpusName" : "Windows Build Tools Internal", + "OpusInfo" : "http://www.microsoft.com", + "FileDigest" : "/fd \"SHA256\"", + "PageHash" : "/NPH", + "TimeStamp" : "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + }, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-458204", + "OperationCode" : "SigntoolVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + + - task: PkgESVPack@12 + displayName: 'Publish Compiler VPack ' + inputs: + serviceType: drop + versionAs: parts + sourceDirectory: $(Build.SourcesDirectory)\x86\tempsign + description: C++/WinRT Compiler + pushPkgName: CppWinRT.Compiler + target: $(OSBuildToolsRoot)\cppwinrt + provData: false + majorVer: $(MajorVersion) + minorVer: $(MinorVersion) + patchVer: $(PatchVersion) + prereleaseVer: $(Build.SourceBranchName).x86.$(BuildConfiguration).$(Build.BuildNumber).$(Build.SourceVersion) + signSbom: false + + - task: CmdLine@2 + displayName: Delete internal compiler copy + inputs: + script: | + rd $(Build.SourcesDirectory)\x86\tempsign /q /s + + - task: CopyFiles@2 + displayName: Stage CppWinRT.Compiler.man + inputs: + SourceFolder: $(XES_VPACKMANIFESTDIRECTORY) + Contents: $(XES_VPACKMANIFESTNAME) + TargetFolder: $(Build.ArtifactStagingDirectory) + + - task: CmdLine@2 + displayName: Stage MSBuild vpack + inputs: + script: "set TargetDir=$(Build.SourcesDirectory)\\msbuild\nrd /s /q %TargetDir% >nul 2>&1\nmd %TargetDir%\ncd %TargetDir%\n\ncopy $(Build.SourcesDirectory)\\vsix\\Microsoft.Cpp.CppWinRT.props\ncopy $(Build.SourcesDirectory)\\nuget\\Microsoft.Windows.CppWinRT.props Microsoft.Cpp.CppWinRTEnabled.props \ncopy $(Build.SourcesDirectory)\\nuget\\Microsoft.Windows.CppWinRT.targets Microsoft.Cpp.CppWinRTEnabled.targets\ncopy $(Build.SourcesDirectory)\\nuget\\CppWinrtRules.Project.xml CppWinrtRules.Project.xml\necho d | xcopy $(Build.SourcesDirectory)\\x86\\cppwinrt_fast_forwarder.lib build\\native\\lib\\i386\necho d | xcopy $(Build.SourcesDirectory)\\x86\\cppwinrt_fast_forwarder.lib build\\native\\lib\\Win32\necho d | xcopy $(Build.SourcesDirectory)\\x64\\cppwinrt_fast_forwarder.lib build\\native\\lib\\amd64\necho d | xcopy $(Build.SourcesDirectory)\\x64\\cppwinrt_fast_forwarder.lib build\\native\\lib\\x64\necho d | xcopy $(Build.SourcesDirectory)\\arm64\\cppwinrt_fast_forwarder.lib build\\native\\lib\\arm64\n" + failOnStderr: true + + - task: PkgESVPack@12 + displayName: Publish MSBuild VPack + inputs: + serviceType: drop + versionAs: parts + sourceDirectory: $(Build.SourcesDirectory)\msbuild + description: C++/WinRT MSBuild + pushPkgName: CppWinRT.MSBuild + target: $(OSBuildToolsRoot)\cppwinrt + provData: false + majorVer: $(MajorVersion) + minorVer: $(MinorVersion) + patchVer: $(PatchVersion) + prereleaseVer: $(Build.SourceBranchName).$(Build.BuildNumber).$(Build.SourceVersion) + signSbom: false + + - task: CopyFiles@2 + displayName: Stage CppWinRT.MSBuild.man + inputs: + SourceFolder: $(XES_VPACKMANIFESTDIRECTORY) + Contents: $(XES_VPACKMANIFESTNAME) + TargetFolder: $(Build.ArtifactStagingDirectory) + + - task: CmdLine@2 + displayName: Stage OSBuildTools.Manifest Update + enabled: False + inputs: + script: | + copy $(Build.SourcesDirectory)\src\package\cppwinrt\vpack\GitCheckin.json + copy $(Build.SourcesDirectory)\vpack\*.man OSBuildTools.Manifest.Update + type OSBuildTools.Manifest.Update + workingDirectory: $(Build.ArtifactStagingDirectory) + failOnStderr: true + + - task: PublishPipelineArtifact@0 + displayName: Publish Update Manifests + inputs: + artifactName: VPack + targetPath: $(Build.ArtifactStagingDirectory) + +- job: BuildExternal + displayName: Build External Packages (NuGet, VSIX) + cancelTimeoutInMinutes: 1 + dependsOn: BuildBinaries + condition: and(succeeded(), eq(variables.manualRelease, 'true')) + pool: + name: Azure Pipelines + vmImage: 'windows-2022' + steps: + - checkout: self + clean: true + persistCredentials: True + + - task: NuGetToolInstaller@1 + displayName: Use NuGet 6.0.2 + continueOnError: True + inputs: + versionSpec: 6.0.2 + + - task: NuGetCommand@2 + displayName: NuGet restore + inputs: + command: 'restore' + feedsToUse: config + nugetConfigPath: NuGet.config + + - task: DownloadPipelineArtifact@1 + displayName: Download x86 Artifacts + inputs: + artifactName: $(BuildConfiguration)_x86 + downloadPath: $(Build.SourcesDirectory)\x86 + + - task: DownloadPipelineArtifact@1 + displayName: Download x64 Artifacts + inputs: + artifactName: $(BuildConfiguration)_x64 + downloadPath: $(Build.SourcesDirectory)\x64 + + - task: DownloadPipelineArtifact@1 + displayName: Download arm64 Artifacts + inputs: + artifactName: $(BuildConfiguration)_arm64 + downloadPath: $(Build.SourcesDirectory)\arm64 + + - task: EsrpCodeSigning@2 + displayName: ESRP CodeSigning NatVis + inputs: + ConnectedServiceName: 81cc6790-027c-4ef3-928d-65e8b96a691a + FolderPath: $(Build.SourcesDirectory) + Pattern: | + x86\cppwinrt\cppwinrt.exe + x86\Component\cppwinrtvisualizer.dll + x64\Component\cppwinrtvisualizer.dll + arm64\Component\cppwinrtvisualizer.dll + x86\Standalone\cppwinrtvisualizer.dll + x64\Standalone\cppwinrtvisualizer.dll + UseMinimatch: true + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "Microsoft" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "http://www.microsoft.com" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd sha256" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "signtool.exe", + "toolVersion": "6.2.9304.0" + } + ] + + - task: CmdLine@2 + displayName: Stage Signed Binaries + inputs: + script: | + echo F|xcopy /S /Q /Y /F x86\cppwinrt\cppwinrt.exe $(Build.ArtifactStagingDirectory)\x86\cppwinrt.exe + echo F|xcopy /S /Q /Y /F x86\Component\cppwinrtvisualizer.dll $(Build.ArtifactStagingDirectory)\x86\Component\cppwinrtvisualizer.dll + echo F|xcopy /S /Q /Y /F x64\Component\cppwinrtvisualizer.dll $(Build.ArtifactStagingDirectory)\x64\Component\cppwinrtvisualizer.dll + echo F|xcopy /S /Q /Y /F arm64\Component\cppwinrtvisualizer.dll $(Build.ArtifactStagingDirectory)\arm64\Component\cppwinrtvisualizer.dll + echo F|xcopy /S /Q /Y /F x86\Standalone\cppwinrtvisualizer.dll $(Build.ArtifactStagingDirectory)\x86\Standalone\cppwinrtvisualizer.dll + echo F|xcopy /S /Q /Y /F x64\Standalone\cppwinrtvisualizer.dll $(Build.ArtifactStagingDirectory)\x64\Standalone\cppwinrtvisualizer.dll + echo F|xcopy /S /Q /Y /F arm64\Standalone\cppwinrtvisualizer.dll $(Build.ArtifactStagingDirectory)\arm64\Standalone\cppwinrtvisualizer.dll + workingDirectory: $(Build.SourcesDirectory) + failOnStderr: true + + - task: CmdLine@2 + displayName: Stage cppwinrtvisualizer.vsdconfig + inputs: + script: | + copy $(Build.SourcesDirectory)\x86\Component\cppwinrtvisualizer.vsdconfig x86\Component\cppwinrtvisualizer.vsdconfig + copy $(Build.SourcesDirectory)\x86\Standalone\cppwinrtvisualizer.vsdconfig x86\Standalone\cppwinrtvisualizer.vsdconfig + workingDirectory: $(Build.ArtifactStagingDirectory) + failOnStderr: true + + - task: NuGetCommand@2 + displayName: Build NuGet + inputs: + command: pack + searchPatternPack: nuget/Microsoft.Windows.CppWinRT.nuspec + versioningScheme: byBuildNumber + buildProperties: 'target_version=$(Build.BuildNumber);cppwinrt_exe=$(Build.ArtifactStagingDirectory)\x86\cppwinrt.exe;cppwinrt_fast_fwd_x86=$(Build.SourcesDirectory)\x86\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=$(Build.SourcesDirectory)\x64\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=$(Build.SourcesDirectory)\arm64\cppwinrt_fast_forwarder.lib ' + + - task: ComponentGovernanceComponentDetection@0 + displayName: Component Detection + + - task: EsrpCodeSigning@2 + displayName: ESRP CodeSigning Nuget Package + inputs: + ConnectedServiceName: 81cc6790-027c-4ef3-928d-65e8b96a691a + FolderPath: $(Build.ArtifactStagingDirectory) + Pattern: Microsoft.Windows.CppWinRT.*.nupkg + UseMinimatch: true + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "KeyCode" : "CP-401405", + "OperationCode" : "NuGetSign", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-401405", + "OperationCode" : "NuGetVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + + - task: PkgESNuGetPublisher@0 + displayName: Publish NuGet Package + inputs: + searchPattern: $(System.ArtifactsDirectory)\Microsoft.Windows.CppWinRT.$(Build.BuildNumber).nupkg + nuGetFeedType: internal + feedName: https://microsoft.pkgs.visualstudio.com/_packaging/CppWinRT/nuget/v3/index.json + + - task: VSBuild@1 + displayName: Build Component VSIXes + inputs: + solution: vsix/vsix.sln + msbuildArgs: /p:Deployment=Component,CppWinRTVersion=$(Build.BuildNumber),NatvisDirx86=$(Build.ArtifactStagingDirectory)\x86\Component\,NatvisDirx64=$(Build.ArtifactStagingDirectory)\x64\Component\,NatvisDirarm64=$(Build.ArtifactStagingDirectory)\arm64\Component\,NupkgDir=$(Build.ArtifactStagingDirectory) /restore + platform: Any CPU + configuration: Release + + - task: ExtractFiles@1 + displayName: Extract Component VSIX files for signing + inputs: + archiveFilePatterns: $(Build.SourcesDirectory)\vsix\Dev17\bin\Release\Component\Microsoft.Windows.CppWinRT.Dev17.vsix + destinationFolder: $(Agent.TempDirectory)\Microsoft.Windows.CppWinRT.Dev17.vsix + overwriteExistingFiles: true + + - task: EsrpCodeSigning@2 + displayName: ESRP CodeSign VSIX contents + inputs: + ConnectedServiceName: 81cc6790-027c-4ef3-928d-65e8b96a691a + FolderPath: $(Agent.TempDirectory)\Microsoft.Windows.CppWinRT.Dev17.vsix + Pattern: '**/Microsoft.Windows.CppWinRT.*.dll' + UseMinimatch: true + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "Microsoft" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "http://www.microsoft.com" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd sha256" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "signtool.exe", + "toolVersion": "6.2.9304.0" + } + ] + - task: ArchiveFiles@2 + displayName: Repack signed VSIX contents + inputs: + rootFolderOrFile: $(Agent.TempDirectory)\Microsoft.Windows.CppWinRT.Dev17.vsix + includeRootFolder: false + archiveFile: $(Build.SourcesDirectory)\vsix\Dev17\bin\Release\Component\Microsoft.Windows.CppWinRT.Dev17.vsix + + - task: VSBuild@1 + displayName: Build Standalone VSIXes + inputs: + solution: vsix/vsix.sln + msbuildArgs: /p:Deployment=Standalone,CppWinRTVersion=$(Build.BuildNumber),NatvisDirx86=$(Build.ArtifactStagingDirectory)\x86\Standalone\,NatvisDirx64=$(Build.ArtifactStagingDirectory)\x64\Standalone\,NatvisDirarm64=$(Build.ArtifactStagingDirectory)\arm64\Standalone\,NupkgDir=$(Build.ArtifactStagingDirectory) /restore + platform: x86 + configuration: Release + + - task: EsrpCodeSigning@2 + displayName: ESRP CodeSigning VSIX + inputs: + ConnectedServiceName: 81cc6790-027c-4ef3-928d-65e8b96a691a + FolderPath: $(Build.SourcesDirectory)\vsix\ + Pattern: | + Dev16\bin\Release\Component\Microsoft.Windows.CppWinRT.vsix + Dev16\bin\Release\Standalone\Microsoft.Windows.CppWinRT.vsix + Dev17\bin\Release\Component\Microsoft.Windows.CppWinRT.Dev17.vsix + Dev17\bin\Release\Standalone\Microsoft.Windows.CppWinRT.Dev17.vsix + UseMinimatch: true + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "KeyCode" : "CP-233016", + "OperationCode" : "OpcSign", + "Parameters" : { + "FileDigest" : "/fd SHA256" + }, + "ToolName" : "sign", + "ToolVersion" : "1.0" + }, + { + "KeyCode" : "CP-233016", + "OperationCode" : "OpcVerify", + "Parameters" : {}, + "ToolName" : "sign", + "ToolVersion" : "1.0" + } + ] + + - task: CmdLine@2 + displayName: Stage Component VSIX (Dev17) + inputs: + script: | + echo F|xcopy /S /Q /Y /F Microsoft.Windows.CppWinRT.Dev17.vsix $(Build.ArtifactStagingDirectory)\Component\Dev17\Microsoft.Windows.CppWinRT.Dev17.vsix + echo F|xcopy /S /Q /Y /F Microsoft.Windows.CppWinRT.Dev17.json $(Build.ArtifactStagingDirectory)\Component\Dev17\Microsoft.Windows.CppWinRT.Dev17.json + echo F|xcopy /S /Q /Y /F Microsoft.Windows.CppWinRT.Dev17.pdb $(Build.ArtifactStagingDirectory)\Component\Dev17\Microsoft.Windows.CppWinRT.Dev17.pdb + workingDirectory: $(Build.SourcesDirectory)\vsix\Dev17\bin\Release\Component + failOnStderr: true + + - task: CopyFiles@2 + displayName: Stage Component VSIX Manifest (Dev17) + inputs: + SourceFolder: $(Build.SourcesDirectory)\vsix + Contents: | + extension.manifest.json + overview.md + TargetFolder: $(Build.ArtifactStagingDirectory)\Component\Dev17 + OverWrite: true + + - task: CmdLine@2 + displayName: Stage Standalone VSIX (Dev16) + inputs: + script: echo F|xcopy /S /Q /Y /F Microsoft.Windows.CppWinRT.vsix $(Build.ArtifactStagingDirectory)\Standalone\Dev16\Microsoft.Windows.CppWinRT.vsix + workingDirectory: $(Build.SourcesDirectory)\vsix\Dev16\bin\$(BuildConfiguration)\Standalone + failOnStderr: true + + - task: CopyFiles@2 + displayName: Stage Standalone VSIX Manifest (Dev16) + inputs: + SourceFolder: $(Build.SourcesDirectory)\vsix + Contents: | + extension.manifest.json + overview.md + TargetFolder: $(Build.ArtifactStagingDirectory)\Standalone\Dev16 + OverWrite: true + + - task: CmdLine@2 + displayName: Stage Standalone VSIX (Dev17) + inputs: + script: echo F|xcopy /S /Q /Y /F Microsoft.Windows.CppWinRT.Dev17.vsix $(Build.ArtifactStagingDirectory)\Standalone\Dev17\Microsoft.Windows.CppWinRT.Dev17.vsix + workingDirectory: $(Build.SourcesDirectory)\vsix\Dev17\bin\$(BuildConfiguration)\Standalone + failOnStderr: true + + - task: CopyFiles@2 + displayName: Stage Standalone VSIX Manifest (Dev17) + inputs: + SourceFolder: $(Build.SourcesDirectory)\vsix + Contents: | + extension.manifest.json + overview.md + TargetFolder: $(Build.ArtifactStagingDirectory)\Standalone\Dev17 + OverWrite: true + + - task: ManifestGeneratorTask@0 + displayName: SBOM for Dev16 + inputs: + BuildDropPath: $(Build.ArtifactStagingDirectory)\Standalone\Dev16 + + - task: ManifestGeneratorTask@0 + displayName: SBOM for Dev17 Standalone + inputs: + BuildDropPath: $(Build.ArtifactStagingDirectory)\Standalone\Dev17 + + - task: ManifestGeneratorTask@0 + displayName: SBOM for Dev17 Component + inputs: + BuildDropPath: $(Build.ArtifactStagingDirectory)\Component\Dev17 + + - task: PublishPipelineArtifact@0 + displayName: Publish VSIX + inputs: + artifactName: Publish + targetPath: $(Build.ArtifactStagingDirectory) + + - task: PublishSymbols@2 + displayName: Publish Component VSIX symbols + inputs: + SymbolsFolder: $(Build.ArtifactStagingDirectory) + SearchPattern: '**/Microsoft.Windows.CppWinRT.Dev17.pdb' + SymbolServerType: TeamServices + SymbolsProduct: CppWinRT +... diff --git a/.pipelines/jobs/OneBranchBuild.yml b/.pipelines/jobs/OneBranchBuild.yml new file mode 100644 index 000000000..dfee85edf --- /dev/null +++ b/.pipelines/jobs/OneBranchBuild.yml @@ -0,0 +1,147 @@ +parameters: + - name: BuildConfiguration + type: string + - name: BuildVersion + type: string + - name: OutputDirectory + type: string + default: '$(Build.SourcesDirectory)\out' + - name: OfficialBuild + type: boolean + default: false + +jobs: +- job: + pool: + type: windows + strategy: + matrix: + x86: + BuildPlatform: 'x86' + x64: + BuildPlatform: 'x64' + arm64: + BuildPlatform: 'arm64' + + variables: + ob_outputDirectory: ${{ parameters.OutputDirectory }} + ob_artifactSuffix: $(BuildPlatform) + StagingFolder: $(ob_outputDirectory) + + ${{ if eq(parameters.OfficialBuild, 'false') }}: + ob_sdl_codeSignValidation_excludes: '-|**\*.exe;-|**\*.dll' + + ob_sdl_prefast_enabled: true + ob_sdl_prefast_runDuring: "Guardian" + ob_sdl_checkCompliantCompilerWarnings: true + + ob_symbolsPublishing_enabled: ${{ parameters.OfficialBuild }} + ob_symbolsPublishing_symbolsFolder: '$(ob_outputDirectory)' + ob_symbolsPublishing_searchPattern: '**\*.pdb' + ob_symbolsPublishing_indexSources: true + + steps: + - task: UseDotNet@2 + continueOnError: true + inputs: + packageType: 'runtime' + version: '6.x' + performMultiLevelLookup: true + + - task: NuGetCommand@2 + displayName: NuGet restore cppwinrt.sln + inputs: + command: 'restore' + restoreSolution: '$(Build.SourcesDirectory)\cppwinrt.sln' + feedsToUse: config + nugetConfigPath: NuGet.config + + - task: VSBuild@1 + displayName: Build fast_fwd + inputs: + solution: $(Build.SourcesDirectory)\cppwinrt.sln + msbuildArgs: /t:fast_fwd /m /p:CppWinRTBuildVersion=${{ parameters.BuildVersion }},clean_intermediate_files=true + platform: $(BuildPlatform) + configuration: ${{ parameters.BuildConfiguration }} + + - task: CopyFiles@2 + displayName: Stage cppwinrt_fast_forwarder.lib + inputs: + SourceFolder: $(Build.SourcesDirectory)\_build\$(BuildPlatform)\$(BuildConfiguration) + Contents: cppwinrt_fast_forwarder.lib + TargetFolder: $(StagingFolder) + + - task: NuGetCommand@2 + displayName: NuGet restore cppwinrtvisualizer.sln + inputs: + command: 'restore' + restoreSolution: '$(Build.SourcesDirectory)\natvis\cppwinrtvisualizer.sln' + feedsToUse: config + nugetConfigPath: NuGet.config + + - task: VSBuild@1 + displayName: Build Component visualizer + condition: or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'arm64')) + inputs: + solution: $(Build.SourcesDirectory)\natvis\cppwinrtvisualizer.sln + msbuildArgs: /m /p:Deployment=Component,CppWinRTBuildVersion=${{ parameters.BuildVersion }},clean_intermediate_files=true + platform: $(BuildPlatform) + configuration: ${{ parameters.BuildConfiguration }} + + - task: VSBuild@1 + displayName: Build Standalone visualizer + condition: or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'arm64')) + inputs: + solution: $(Build.SourcesDirectory)\natvis\cppwinrtvisualizer.sln + msbuildArgs: /m /p:Deployment=Standalone,CppWinRTBuildVersion=${{ parameters.BuildVersion }},clean_intermediate_files=true + platform: $(BuildPlatform) + configuration: ${{ parameters.BuildConfiguration }} + + - task: CopyFiles@2 + displayName: Stage Component cppwinrtvisualizer.* + condition: or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'arm64')) + inputs: + SourceFolder: $(Build.SourcesDirectory)\natvis\$(BuildPlatform)\$(BuildConfiguration)\Component + Contents: | + cppwinrtvisualizer.dll + cppwinrtvisualizer.pdb + cppwinrtvisualizer.vsdconfig + TargetFolder: $(StagingFolder)\Component + + - task: CopyFiles@2 + displayName: Stage Standalone cppwinrtvisualizer.* + condition: or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64'), eq(variables['BuildPlatform'], 'arm64')) + inputs: + SourceFolder: $(Build.SourcesDirectory)\natvis\$(BuildPlatform)\$(BuildConfiguration)\Standalone + Contents: | + cppwinrtvisualizer.dll + cppwinrtvisualizer.pdb + cppwinrtvisualizer.vsdconfig + TargetFolder: $(StagingFolder)\Standalone + + - task: VSBuild@1 + displayName: Build cppwinrt + condition: or(eq(variables['BuildPlatform'], 'x86'), eq(variables['BuildPlatform'], 'x64')) + inputs: + solution: $(Build.SourcesDirectory)\cppwinrt.sln + msbuildArgs: /t:cppwinrt /m /p:CppWinRTBuildVersion=${{ parameters.BuildVersion }},clean_intermediate_files=true + platform: $(BuildPlatform) + configuration: ${{ parameters.BuildConfiguration }} + + - task: CopyFiles@2 + displayName: Stage cppwinrt.* + inputs: + SourceFolder: $(Build.SourcesDirectory)\_build\$(BuildPlatform)\$(BuildConfiguration) + Contents: | + cppwinrt.exe + cppwinrt.pdb + TargetFolder: $(StagingFolder)\cppwinrt + + - task: onebranch.pipeline.signing@1 + displayName: '🔒 Onebranch Signing for cppwinrt binaries' + condition: eq(${{ parameters.OfficialBuild }}, 'true') + inputs: + command: sign + signing_profile: external_distribution + files_to_sign: '**/*.dll;**/*.exe' + search_root: $(StagingFolder) diff --git a/.pipelines/jobs/OneBranchNuGet.yml b/.pipelines/jobs/OneBranchNuGet.yml new file mode 100644 index 000000000..36ec3144b --- /dev/null +++ b/.pipelines/jobs/OneBranchNuGet.yml @@ -0,0 +1,75 @@ +# Build the NuGet package +parameters: + - name: BuildConfiguration + type: string + - name: NugetPackageVersion + type: string + - name: OfficialBuild + type: boolean + default: false + +jobs: + - job: + pool: + type: windows + + variables: + ob_outputDirectory: '$(Build.SourcesDirectory)\out' + PackageVersion: ${{ parameters.NugetPackageVersion }} + + ob_sdl_prefast_enabled: true + ob_sdl_prefast_runDuring: 'Guardian' + ob_sdl_checkCompliantCompilerWarnings: true + + steps: + - task: UseDotNet@2 + continueOnError: true + inputs: + packageType: 'runtime' + version: '6.x' + performMultiLevelLookup: true + + - task: NuGetToolInstaller@1 + displayName: Use NuGet 6.0.2 + continueOnError: True + inputs: + versionSpec: 6.0.2 + + - task: DownloadPipelineArtifact@1 + displayName: 'Download x86 artifacts' + inputs: + artifactName: 'drop_build_x86' + targetPath: '$(Build.SourcesDirectory)/x86' + + - task: DownloadPipelineArtifact@1 + displayName: 'Download x64 artifacts' + inputs: + artifactName: 'drop_build_x64' + targetPath: '$(Build.SourcesDirectory)/x64' + + - task: DownloadPipelineArtifact@1 + displayName: 'Download arm64 artifacts' + inputs: + artifactName: 'drop_build_arm64' + targetPath: '$(Build.SourcesDirectory)/arm64' + + - task: NuGetCommand@2 + displayName: 'Build NuGet package' + inputs: + command: 'custom' + arguments: 'pack nuget/Microsoft.Windows.CppWinRT.nuspec -NonInteractive -OutputDirectory $(ob_outputDirectory)\packages -Properties Configuration=release;cppwinrt_exe=$(Build.SourcesDirectory)\x86\cppwinrt\cppwinrt.exe;cppwinrt_fast_fwd_x86=$(Build.SourcesDirectory)\x86\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=$(Build.SourcesDirectory)\x64\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=$(Build.SourcesDirectory)\arm64\cppwinrt_fast_forwarder.lib;target_version=$(PackageVersion) -Version $(PackageVersion) -Verbosity Detailed' + + - task: onebranch.pipeline.signing@1 + displayName: '🔒 Onebranch Signing for NuGet package' + condition: eq(${{ parameters.OfficialBuild }}, 'true') + inputs: + command: sign + signing_profile: external_distribution + files_to_sign: 'Microsoft.Windows.CppWinRT.*.nupkg' + search_root: $(ob_outputDirectory)\packages + + - task: NuGetCommand@2 + displayName: 'Publish NuGet package' + inputs: + command: 'custom' + arguments: 'push $(ob_outputDirectory)\packages\Microsoft.Windows.CppWinRT.$(PackageVersion).nupkg -NonInteractive -Source https://microsoft.pkgs.visualstudio.com/_packaging/CppWinRT/nuget/v3/index.json -ApiKey VSTS' diff --git a/.pipelines/jobs/OneBranchTest.yml b/.pipelines/jobs/OneBranchTest.yml new file mode 100644 index 000000000..2fb3a4bd1 --- /dev/null +++ b/.pipelines/jobs/OneBranchTest.yml @@ -0,0 +1,123 @@ +parameters: + - name: BuildConfiguration + type: string + - name: BuildVersion + type: string + +jobs: +- job: + pool: + type: windows + isCustom: true + name: 'Azure Pipelines' + vmImage: 'windows-2022' # (or 2019) + strategy: + matrix: + test.x86: + TestExe: 'test' + TestProject: 'test' + BuildPlatform: 'x86' + test_nocoro.x86: + TestExe: 'test_nocoro' + TestProject: 'test_nocoro' + BuildPlatform: 'x86' + test_cpp20.x86: + TestExe: 'test_cpp20' + TestProject: 'test_cpp20' + BuildPlatform: 'x86' + test_cpp20_no_sourcelocation.x86: + TestExe: 'test_cpp20_no_sourcelocation' + TestProject: 'test_cpp20_no_sourcelocation' + BuildPlatform: 'x86' + test_fast.x86: + TestExe: 'test_fast' + TestProject: 'test_fast' + BuildPlatform: 'x86' + test_slow.x86: + TestExe: 'test_slow' + TestProject: 'test_slow' + BuildPlatform: 'x86' + test_old.x86: + TestExe: 'test_old' + TestProject: 'old_tests\test_old' + BuildPlatform: 'x86' + test_module_lock_custom.x86: + TestExe: 'test_module_lock_custom' + TestProject: 'test_module_lock_custom' + BuildPlatform: 'x86' + test_module_lock_none.x86: + TestExe: 'test_module_lock_none' + TestProject: 'test_module_lock_none' + BuildPlatform: 'x86' + + variables: + ob_outputDirectory: $(Build.SourcesDirectory)\out + ob_artifactSuffix: $(TestExe).$(BuildPlatform) + ob_sdl_codeSignValidation_excludes: '-|**\*.exe;-|**\*.dll' + + ob_sdl_prefast_enabled: true + ob_sdl_prefast_runDuring: 'Build' + ob_sdl_checkCompliantCompilerWarnings: true + + BuildPath: '$(Build.SourcesDirectory)/_build/$(BuildPlatform)/${{ parameters.BuildConfiguration }}' + + steps: + - task: UseDotNet@2 + continueOnError: true + inputs: + packageType: 'runtime' + version: '6.x' + performMultiLevelLookup: true + + - task: DownloadPipelineArtifact@2 + displayName: 'Download cppwinrt executable' + inputs: + artifactName: 'drop_build_$(BuildPlatform)' + targetPath: '$(Pipeline.Workspace)' + + - task: CopyFiles@2 + displayName: 'Patch cppwinrt executable into build directory' + inputs: + sourceFolder: '$(Pipeline.Workspace)' + Contents: '**\cppwinrt.exe' + TargetFolder: $(BuildPath) + flattenFolders: true + + - task: NuGetCommand@2 + displayName: NuGet restore cppwinrt.sln + inputs: + command: 'restore' + restoreSolution: '$(Build.SourcesDirectory)\cppwinrt.sln' + feedsToUse: config + nugetConfigPath: NuGet.config + + - task: PowerShell@2 + displayName: Remove cppwinrt dependency from test projects + inputs: + targetType: inline + script: | + # Hack-ish: We already have a built exe, so we want to avoid rebuilding cppwinrt + mv cppwinrt.sln cppwinrt.sln.orig + Get-Content cppwinrt.sln.orig | + Where-Object { -not $_.Contains("{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}") } | + Set-Content cppwinrt.sln + "Modified contents" + Get-Content cppwinrt.sln + + - task: CmdLine@2 + displayName: Run cppwinrt to build projection + inputs: + script: $(BuildPath)\cppwinrt.exe -in local -out $(BuildPath) -verbose + + - task: VSBuild@1 + displayName: Build test + inputs: + solution: $(Build.SourcesDirectory)\cppwinrt.sln + msbuildArgs: /t:test\$(TestProject) /m /p:CppWinRTBuildVersion=${{ parameters.BuildVersion }},clean_intermediate_files=true /bl:$(ob_outputDirectory)\output.binlog + platform: $(BuildPlatform) + configuration: ${{ parameters.BuildConfiguration }} + + - task: CmdLine@2 + displayName: Run test + inputs: + script: $(BuildPath)\$(TestExe).exe diff --git a/.pipelines/jobs/OneBranchVsix.yml b/.pipelines/jobs/OneBranchVsix.yml new file mode 100644 index 000000000..696b7e292 --- /dev/null +++ b/.pipelines/jobs/OneBranchVsix.yml @@ -0,0 +1,149 @@ +parameters: + - name: BuildConfiguration + type: string + - name: BuildVersion + type: string + - name: NugetPackageVersion + type: string + - name: OfficialBuild + type: boolean + default: false + +jobs: +- job: + pool: + type: windows + strategy: + matrix: + Standalone: + Deployment: 'Standalone' + VsVersion: 'Dev17' + VsixFilename: Microsoft.Windows.CppWinRT.$(VsVersion) + Component: + Deployment: 'Component' + VsVersion: 'Dev17' + VsixFilename: Microsoft.Windows.CppWinRT.$(VsVersion) + Dev16: + Deployment: 'Standalone' + VsVersion: 'Dev16' + VsixFilename: Microsoft.Windows.CppWinRT + + variables: + ob_outputDirectory: $(Build.SourcesDirectory)\out + ob_artifactSuffix: $(VsVersion)_$(Deployment) + + BuildFolder: $(Build.SourcesDirectory)\vsix\$(VsVersion)\bin\${{ parameters.BuildConfiguration }}\$(Deployment) + + ob_symbolsPublishing_enabled: true + ob_symbolsPublishing_symbolsFolder: '$(ob_outputDirectory)' + ob_symbolsPublishing_searchPattern: '**\*.pdb' + ob_symbolsPublishing_indexSources: true + + ob_sdl_prefast_enabled: true + ob_sdl_prefast_runDuring: 'Build' + ob_sdl_checkCompliantCompilerWarnings: true + + steps: + - task: UseDotNet@2 + continueOnError: true + inputs: + packageType: 'sdk' + version: '6.x' + performMultiLevelLookup: true + + - task: NuGetToolInstaller@1 + displayName: Use NuGet 6.0.2 + continueOnError: True + inputs: + versionSpec: 6.0.2 + + - task: NuGetCommand@2 + displayName: NuGet restore + inputs: + command: 'restore' + restoreSolution: '$(Build.SourcesDirectory)\vsix\vsix.sln' + feedsToUse: config + nugetConfigPath: NuGet.config + + - task: DownloadPipelineArtifact@2 + displayName: 'Download x86 binaries' + inputs: + artifactName: 'drop_build_x86' + targetPath: '$(Build.SourcesDirectory)\x86' + + - task: DownloadPipelineArtifact@2 + displayName: 'Download x64 binaries' + inputs: + artifactName: 'drop_build_x64' + targetPath: '$(Build.SourcesDirectory)\x64' + + - task: DownloadPipelineArtifact@2 + displayName: 'Download arm64 binaries' + inputs: + artifactName: 'drop_build_arm64' + targetPath: '$(Build.SourcesDirectory)\arm64' + + - task: DownloadPipelineArtifact@2 + displayName: 'Download NuGet' + inputs: + artifactName: 'drop_NuGet_' + targetPath: '$(Pipeline.Workspace)\nuget' + + - task: VSBuild@1 + displayName: Build VSIX + inputs: + solution: $(Build.SourcesDirectory)\vsix\vsix.sln + msbuildArgs: /t:vsix_$(VsVersion) /m /p:CppWinRTVersion=${{ parameters.BuildVersion }},NugetPackageVersion=${{ parameters.NugetPackageVersion }},clean_intermediate_files=true,Deployment=$(Deployment),NatvisDirx86=$(Build.SourcesDirectory)\x86\$(Deployment)\,NatvisDirx64=$(Build.SourcesDirectory)\x64\$(Deployment)\,NatvisDirarm64=$(Build.SourcesDirectory)\arm64\$(Deployment)\,NupkgDir=$(Pipeline.Workspace)\nuget\packages /bl:$(ob_outputDirectory)\output.binlog + platform: 'Any CPU' + configuration: ${{ parameters.BuildConfiguration }} + + - task: ExtractFiles@1 + displayName: Extract VSIX contents for signing + inputs: + archiveFilePatterns: '$(BuildFolder)\$(VsixFilename).vsix' + destinationFolder: '$(Agent.TempDirectory)\$(VsixFilename)' + overwriteExistingFiles: true + + - task: onebranch.pipeline.signing@1 + displayName: '🔒 Onebranch Signing for VSIX contents' + condition: eq(${{ parameters.OfficialBuild }}, 'true') + inputs: + command: sign + signing_profile: external_distribution + files_to_sign: '**\*.dll' + search_root: '$(Agent.TempDirectory)\$(VsixFilename)' + + - task: ArchiveFiles@2 + displayName: 'Repack signed VSIX contents' + inputs: + rootFolderOrFile: '$(Agent.TempDirectory)\$(VsixFilename)' + includeRootFolder: false + archiveFile: '$(ob_outputDirectory)\$(VsixFilename).vsix' + + - task: onebranch.pipeline.signing@1 + displayName: '🔒 Onebranch Signing for VSIX' + condition: eq(${{ parameters.OfficialBuild }}, 'true') + inputs: + command: sign + signing_profile: external_distribution + files_to_sign: '$(VsixFilename).vsix' + search_root: '$(ob_outputDirectory)' + + - task: CopyFiles@2 + displayName: Stage VSIX Manifest + inputs: + SourceFolder: '$(Build.SourcesDirectory)\vsix' + Contents: | + extension.manifest.json + overview.md + TargetFolder: '$(ob_outputDirectory)' + + - task: CopyFiles@2 + displayName: Stage VSIX json and symbols + inputs: + SourceFolder: $(Buildfolder) + Contents: | + $(VsixFilename).pdb + $(VsixFilename).json + TargetFolder: '$(ob_outputDirectory)' + diff --git a/.pipelines/sync-mirror.yml b/.pipelines/sync-mirror.yml new file mode 100644 index 000000000..f7be6296d --- /dev/null +++ b/.pipelines/sync-mirror.yml @@ -0,0 +1,67 @@ +# Sync branches in a mirror repository to a base repo by running this pipeline +# from the mirror repo, and supplying the base repo as a parameter +name: $(BuildDefinitionName)_$(date:yyMMdd)$(rev:.r) + +parameters: + - name: "SourceToTargetBranches" + type: object + default: + master: master + - name: "SourceRepository" + type: string + default: "https://github.com/microsoft/cppwinrt.git" + +resources: + repositories: + - repository: 1ESPipelineTemplates + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates + parameters: + pool: + name: Azure-Pipelines-1ESPT-ExDShared + image: windows-2022 + os: windows + customBuildTags: + - ES365AIMigrationTooling + stages: + - stage: stage + jobs: + - job: SyncMirror + strategy: + matrix: + ${{ each branches in parameters.SourceToTargetBranches }}: + ${{ branches.key }}: + SourceBranch: ${{ branches.key }} + TargetBranch: ${{ branches.value }} + dependsOn: [] + steps: + - checkout: self + persistCredentials: true + + - task: PowerShell@2 + inputs: + targetType: 'inline' + script: | + Write-Host "SourceBranch " + "$(SourceBranch)" + Write-Host "TargetBranch " + "$(TargetBranch)" + + $repo = "${{ parameters.SourceRepository }}" + git remote add sourcerepo $repo + git remote + + $target = "$(TargetBranch)" + git fetch origin $target + git checkout $target + git pull origin $target + + $source = "$(SourceBranch)" + git fetch sourcerepo $source + git pull sourcerepo $source + + - task: CmdLine@2 + inputs: + script: | + git push diff --git a/.pipelines/variables/OneBranchVariables.yml b/.pipelines/variables/OneBranchVariables.yml new file mode 100644 index 000000000..ff7a98adb --- /dev/null +++ b/.pipelines/variables/OneBranchVariables.yml @@ -0,0 +1,16 @@ +parameters: +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: false + +variables: + system.debug: ${{ parameters.debug }} + ENABLE_PRS_DELAYSIGN: 1 + NUGET_XMLDOC_MODE: none + + # Docker image which is used to build the project https://aka.ms/obpipelines/containers + WindowsContainerImage: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' + + Codeql.Enabled: true # CodeQL once every 3 days on the default branch for all languages its applicable to in that pipeline. + GDN_USE_DOTNET: true \ No newline at end of file diff --git a/.pipelines/variables/version.yml b/.pipelines/variables/version.yml new file mode 100644 index 000000000..46a535ee0 --- /dev/null +++ b/.pipelines/variables/version.yml @@ -0,0 +1,17 @@ +parameters: + - name: OfficialBuild + type: boolean + default: false + +variables: + MajorVersion: "3" + MinorVersion: "0" + VersionDate: $[format('{0:yyMMdd}', pipeline.startTime)] + VersionCounter: $[counter(variables['VersionDate'], 1)] + BuildVersion: $(MajorVersion).$(MinorVersion).$(VersionDate).$(VersionCounter) + PatchVersion: $(VersionDate)$(VersionCounter) + + ${{ if eq(parameters.OfficialBuild, true) }}: + NugetPackageVersion: $(BuildVersion) + ${{ else }}: + NugetPackageVersion: $(BuildVersion)-unofficial diff --git a/.runsettings b/.runsettings new file mode 100644 index 000000000..5f10e44f8 --- /dev/null +++ b/.runsettings @@ -0,0 +1,24 @@ + + + + .\TestResults + 60000 + true + + + + + + + Single + (?i:Test) + true + on + true + Verbose + AdditionalInfo + ShortInfo + , + 20000 + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..b0089e7ad --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,208 @@ +# This CMake build file is intended for use with the llvm-mingw toolchain: +# https://github.com/mstorsjo/llvm-mingw +# +# It also works for building natively on Linux, or cross-building from Linux +# for running on Windows with a mingw-w64 toolchain. +# +# It most probably doesn't work with MSVC. + +cmake_minimum_required(VERSION 3.16) + +project(cppwinrt LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CPPWINRT_BUILD_VERSION "999.999.999.999" CACHE STRING "The version string used for cppwinrt.") +if(CPPWINRT_BUILD_VERSION STREQUAL "999.999.999.999" OR CPPWINRT_BUILD_VERSION STREQUAL "0.0.0.0") + message(WARNING "CPPWINRT_BUILD_VERSION has been set to a dummy version string. Do not use in production!") +endif() +message(STATUS "Using version string: ${CPPWINRT_BUILD_VERSION}") + +if(WIN32) + # WinMD uses CreateFile2 which requires Windows 8. + add_compile_definitions(_WIN32_WINNT=0x0602) +endif() + + +# === prebuild: Generator tool for strings.cpp, strings.h, version.rc === + +if(CMAKE_CROSSCOMPILING) + include(ExternalProject) + ExternalProject_Add(cppwinrt-prebuild + SOURCE_DIR "${PROJECT_SOURCE_DIR}/prebuild" + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= "-DCPPWINRT_BUILD_VERSION=${CPPWINRT_BUILD_VERSION}" + ) + ExternalProject_Get_Property(cppwinrt-prebuild INSTALL_DIR) + set(PREBUILD_TOOL "${INSTALL_DIR}/bin/cppwinrt-prebuild") + unset(INSTALL_DIR) +else() + add_subdirectory(prebuild) + set(PREBUILD_TOOL cppwinrt-prebuild) +endif() + + +# === Step to create autogenerated files === + +file(GLOB PREBUILD_STRINGS_FILES + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + strings/*.h +) +add_custom_command( + OUTPUT + ${PROJECT_BINARY_DIR}/strings.cpp + ${PROJECT_BINARY_DIR}/version.rc + COMMAND "${PREBUILD_TOOL}" ARGS "${PROJECT_SOURCE_DIR}/strings" "${PROJECT_BINARY_DIR}" + DEPENDS + cppwinrt-prebuild + ${PREBUILD_STRINGS_FILES} + VERBATIM +) + + +# === cppwinrt === + +set(CPPWINRT_SRCS + cppwinrt/main.cpp + "${PROJECT_BINARY_DIR}/strings.cpp" +) + +set(CPPWINRT_HEADERS + cppwinrt/pch.h + cppwinrt/cmd_reader.h + cppwinrt/code_writers.h + cppwinrt/component_writers.h + cppwinrt/file_writers.h + cppwinrt/helpers.h + cppwinrt/pch.h + cppwinrt/settings.h + cppwinrt/task_group.h + cppwinrt/text_writer.h + cppwinrt/type_writers.h +) + +if(WIN32) + add_custom_command( + OUTPUT + "${PROJECT_BINARY_DIR}/app.manifest" + COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/cppwinrt/app.manifest" "${PROJECT_BINARY_DIR}/app.manifest" + DEPENDS "${PROJECT_SOURCE_DIR}/cppwinrt/app.manifest" + VERBATIM + ) + # Do the configure_file dance so that app.manifest.rc don't get modified every + # single time the project is reconfigured and trigger a rebuild. + file(WRITE "${PROJECT_BINARY_DIR}/app.manifest.rc.in" "1 24 \"app.manifest\"\n") + configure_file( + "${PROJECT_BINARY_DIR}/app.manifest.rc.in" + "${PROJECT_BINARY_DIR}/app.manifest.rc" + COPYONLY + ) + + set(CPPWINRT_RESOURCES + "${PROJECT_BINARY_DIR}/app.manifest" + "${PROJECT_BINARY_DIR}/app.manifest.rc" + "${PROJECT_BINARY_DIR}/version.rc" + ) +endif() + +add_executable(cppwinrt ${CPPWINRT_SRCS} ${CPPWINRT_RESOURCES} ${CPPWINRT_HEADERS}) +target_compile_definitions(cppwinrt PRIVATE CPPWINRT_VERSION_STRING="${CPPWINRT_BUILD_VERSION}") +target_include_directories(cppwinrt PRIVATE ${PROJECT_BINARY_DIR}) + +if(WIN32) + target_link_libraries(cppwinrt shlwapi) +endif() + +install(TARGETS cppwinrt) + + +# HACK: Handle the xmllite import lib. +# mingw-w64 before commit 5ac1a2c is missing the import lib for xmllite. This +# checks whether the current build environment provides libxmllite.a, and +# generates the import lib if needed. + +set(XMLLITE_LIBRARY xmllite) +if(MINGW) + function(TestLinkXmlLite OUTPUT_VARNAME) + include(CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_LIBRARIES xmllite) + check_cxx_source_compiles(" +#include +int main() { + CreateXmlReader(__uuidof(IXmlReader), nullptr, nullptr); +} + " ${OUTPUT_VARNAME}) + endfunction() + + function(TestIsI386 OUTPUT_VARNAME) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" +#if !defined(__i386__) && !defined(_M_IX86) +# error Not i386 +#endif +int main() {} + " ${OUTPUT_VARNAME}) + endfunction() + + TestLinkXmlLite(HAS_LIBXMLLITE) + if(NOT HAS_LIBXMLLITE) + TestIsI386(TARGET_IS_I386) + if(TARGET_IS_I386) + set(XMLLITE_DEF_FILE xmllite_i386) + else() + set(XMLLITE_DEF_FILE xmllite) + endif() + include(CMakeFindBinUtils) + add_custom_command( + OUTPUT + "${PROJECT_BINARY_DIR}/libxmllite.a" + COMMAND "${CMAKE_DLLTOOL}" -k -d "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def" -l "${PROJECT_BINARY_DIR}/libxmllite.a" + DEPENDS "${PROJECT_SOURCE_DIR}/mingw-support/${XMLLITE_DEF_FILE}.def" + VERBATIM + ) + add_custom_target(gen-libxmllite + DEPENDS "${PROJECT_BINARY_DIR}/libxmllite.a" + ) + set(XMLLITE_LIBRARY "${PROJECT_BINARY_DIR}/libxmllite.a") + add_dependencies(cppwinrt gen-libxmllite) + endif() +endif() +if(WIN32) + target_link_libraries(cppwinrt "${XMLLITE_LIBRARY}") +endif() + + +# === winmd: External header-only library for reading winmd files === + +set(EXTERNAL_WINMD_INCLUDE_DIR "" CACHE PATH "Path to the include dir of an\ + external copy of the winmd library headers. Leave empty (default) to have\ + it downloaded as ExternalProject during build.") + +if(EXTERNAL_WINMD_INCLUDE_DIR STREQUAL "") + message(STATUS "The winmd library will be downloaded using ExternalProject.") + include(ExternalProject) + ExternalProject_Add(winmd + GIT_REPOSITORY https://github.com/microsoft/winmd.git + GIT_TAG 0f1eae3bfa63fa2ba3c2912cbfe72a01db94cc5a + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + UPDATE_COMMAND "" + ) + add_dependencies(cppwinrt winmd) + ExternalProject_Get_Property(winmd SOURCE_DIR) + set(winmd_INCLUDE_DIR "${SOURCE_DIR}/src") +else() +message(STATUS "Using winmd library headers at ${EXTERNAL_WINMD_INCLUDE_DIR}") + set(winmd_INCLUDE_DIR "${EXTERNAL_WINMD_INCLUDE_DIR}") +endif() +target_include_directories(cppwinrt PRIVATE "${winmd_INCLUDE_DIR}") + + +if(WIN32 AND NOT CMAKE_CROSSCOMPILING) + include(CTest) + if(BUILD_TESTING) + add_subdirectory(test) + endif() +endif() diff --git a/Directory.Build.Props b/Directory.Build.Props new file mode 100644 index 000000000..5972803c0 --- /dev/null +++ b/Directory.Build.Props @@ -0,0 +1,83 @@ + + + + + + + v143 + v145 + 10.0 + 10.0.18362.0 + + + + + + ClangCL + + 20 + + false + + + + 999.999.999.999 + $(Platform) + x86 + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\ + $(SolutionDir)_build\$(CppWinRTPlatform)\$(Configuration)\temp\$(MSBuildProjectName)\ + $(OutDir) + $(SolutionDir)_build\x86\$(Configuration)\ + + + + + Level4 + true + true + true + stdcpp17 + stdcpp20 + Use + pch.h + CPPWINRT_VERSION_STRING="$(CppWinRTBuildVersion)";%(PreprocessorDefinitions) + CATCH_CONFIG_COLOUR_ANSI;%(PreprocessorDefinitions) + true + /bigobj + /await:strict %(AdditionalOptions) + -Wno-unused-command-line-argument -fno-delayed-template-parsing -mcx16 + + + onecore.lib + + + CPPWINRT_VERSION_STRING="$(CppWinRTBuildVersion)";%(PreprocessorDefinitions) + + + + + + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 000000000..1d77adffd --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,12 @@ + + + true + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 51044dead..19e1493dc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -[![Build status](https://dev.azure.com/microsoft/Dart/_apis/build/status/cppwinrt%20internal%20build)](https://dev.azure.com/microsoft/Dart/_build/latest?definitionId=31784) - # The C++/WinRT language projection C++/WinRT is an entirely standard C++ language projection for Windows Runtime (WinRT) APIs, implemented as a header-file-based library, and designed to provide you with first-class access to the modern Windows API. With C++/WinRT, you can author and consume Windows Runtime APIs using any standards-compliant C++17 compiler. @@ -13,24 +11,31 @@ C++/WinRT is an entirely standard C++ language projection for Windows Runtime (W Don't build C++/WinRT yourself - just download the latest version here: https://aka.ms/cppwinrt/nuget +## Working on the compiler + If you really want to build it yourself, the simplest way to do so is to run the `build_test_all.cmd` script in the root directory. Developers needing to work on the C++/WinRT compiler itself should go through the following steps to arrive at an efficient inner loop: * Open a dev command prompt pointing at the root of the repo. * Open the `cppwinrt.sln` solution. -* Build the x64 Release configuration of the `prebuild` and `cppwinrt` projects only. Do not attempt to build anything else just yet. -* Run `build_projection.cmd` in the dev command prompt. -* Switch to the x64 Debug configuration in Visual Studio and build all projects as needed. +* Choose a configuration (x64, x86, Release, Debug) and build projects as needed. + +If you are working on an ARM64 specific issue from an x64 or x86 host, you will need to instead: + +* Open the `cppwinrt.sln` solution +* Build the x86 version of the "cppwinrt" project first +* Switch to your preferred configuration and build the test binaries and run them in your test environment -# Contributing +## Comparing Outputs -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. +Comparing the output of the prior release and your current changes will help show the impact of any updates. Starting from +a dev command prompt at the root of the repo _after_ following the above build instructions: -When you submit a pull request, a CLA bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. +* Run `build_projection.cmd` in the dev command prompt +* Run `build_prior_projection.cmd` in the dev command prompt as well +* Run `prepare_versionless_diffs.cmd` which removes version stamps on both current and prior projection +* Use a directory-level differencing tool to compare `_build\$(arch)\$(flavor)\winrt` and `_reference\$(arch)\$(flavor)\winrt` -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +## Testing +This repository uses the [Catch2](https://github.com/catchorg/Catch2) testing framework. +- From a Visual Studio command line, you should run `build_tests_all.cmd` to build and run the tests. To Debug the tests, you can debug the associated `_build\$(arch)\$(flavor)\.exe` under the debugger of your choice. +- Optionally, you can install the [Catch2Adapter](https://marketplace.visualstudio.com/items?itemName=JohnnyHendriks.ext01) to run the tests from Visual Studio. \ No newline at end of file diff --git a/build_nuget.cmd b/build_nuget.cmd index 068e1dfd0..99e193311 100644 --- a/build_nuget.cmd +++ b/build_nuget.cmd @@ -1,13 +1,12 @@ rem @echo off set target_version=%1 -if "%target_version%"=="" set target_version=1.2.3.4 +if "%target_version%"=="" set target_version=999.999.999.999 call msbuild /m /p:Configuration=Release,Platform=x86,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd call msbuild /m /p:Configuration=Release,Platform=x64,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd -call msbuild /m /p:Configuration=Release,Platform=arm,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd call msbuild /m /p:Configuration=Release,Platform=arm64,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd call msbuild /m /p:Configuration=Release,Platform=x86,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:cppwinrt -nuget pack nuget\Microsoft.Windows.CppWinRT.nuspec -Properties cppwinrt_exe=%cd%\_build\x86\Release\cppwinrt.exe;cppwinrt_fast_fwd_x86=%cd%\_build\x86\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=%cd%\_build\x64\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm=%cd%\_build\arm\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=%cd%\_build\arm64\Release\cppwinrt_fast_forwarder.lib +nuget pack nuget\Microsoft.Windows.CppWinRT.nuspec -Properties target_version=%target_version%;cppwinrt_exe=%cd%\_build\x86\Release\cppwinrt.exe;cppwinrt_fast_fwd_x86=%cd%\_build\x86\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=%cd%\_build\x64\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=%cd%\_build\arm64\Release\cppwinrt_fast_forwarder.lib diff --git a/build_prior_projection.cmd b/build_prior_projection.cmd new file mode 100644 index 000000000..9d10f3eaa --- /dev/null +++ b/build_prior_projection.cmd @@ -0,0 +1,49 @@ +@echo off + +setlocal ENABLEDELAYEDEXPANSION + +set target_platform=%1 +set target_configuration=%2 +if "%target_platform%"=="" set target_platform=x64 + +if /I "%target_platform%" equ "all" ( + if "%target_configuration%"=="" ( + set target_configuration=all + ) + call %0 x86 !target_configuration! + call %0 x64 !target_configuration! + call %0 arm64 !target_configuration! + goto :eof +) + +if /I "%target_configuration%" equ "all" ( + call %0 %target_platform% Debug + call %0 %target_platform% Release + goto :eof +) + +if "%target_configuration%"=="" ( + set target_configuration=Debug +) + +set reference_output=%~p0\_reference\%target_platform%\%target_configuration% +if exist "%reference_output%" ( + echo Removing existing reference projections + rmdir /s /q "%reference_output%" +) + +if not exist ".\.nuget" mkdir ".\.nuget" +if not exist ".\.nuget\nuget.exe" powershell -Command "$ProgressPreference = 'SilentlyContinue' ; Invoke-WebRequest https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile .\.nuget\nuget.exe" + +mkdir %reference_output%\package +.\.nuget\nuget.exe install Microsoft.Windows.CppWinRT -o %reference_output%\package +set reference_cppwinrt= +for /F "delims=" %%a in ('dir /s /b %reference_output%\package\cppwinrt.exe') DO set reference_cppwinrt=%%a +if "%reference_cppwinrt%"=="" ( + echo Could not find the reference cppwinrt.exe under %reference_output%\package + goto :EOF +) + +echo Generating reference projection from %reference_cppwinrt% to %reference_output%\cppwinrt +%reference_cppwinrt% -in local -out %reference_output% -verbose +echo. diff --git a/build_projection.cmd b/build_projection.cmd index 9480b5ec0..140e6c7f8 100644 --- a/build_projection.cmd +++ b/build_projection.cmd @@ -12,7 +12,6 @@ if /I "%target_platform%" equ "all" ( ) call %0 x86 !target_configuration! call %0 x64 !target_configuration! - call %0 arm !target_configuration! call %0 arm64 !target_configuration! goto :eof ) @@ -27,6 +26,13 @@ if "%target_configuration%"=="" ( set target_configuration=Debug ) +set cppwinrt_exe=%~p0\_build\x64\Release\cppwinrt.exe + +if not exist "%cppwinrt_exe%" ( + echo Remember to build the "prebuild" and then "cppwinrt" projects for Release x64 first + goto :eof +) + echo Building projection into %target_platform% %target_configuration% -%~p0\_build\x64\Release\cppwinrt.exe -in local -out %~p0\_build\%target_platform%\%target_configuration% -verbose +%cppwinrt_exe% -in local -out %~p0\_build\%target_platform%\%target_configuration% -verbose echo. diff --git a/build_test_all.cmd b/build_test_all.cmd index 13a68f6c9..c9beb852c 100644 --- a/build_test_all.cmd +++ b/build_test_all.cmd @@ -3,13 +3,14 @@ set target_platform=%1 set target_configuration=%2 set target_version=%3 +set clean_intermediate_files=%4 if "%target_platform%"=="" set target_platform=x64 if "%target_configuration%"=="" set target_configuration=Release -if "%target_version%"=="" set target_version=1.2.3.4 +if "%target_version%"=="" set target_version=999.999.999.999 if not exist ".\.nuget" mkdir ".\.nuget" -if not exist ".\.nuget\nuget.exe" powershell -Command "Invoke-WebRequest https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile .\.nuget\nuget.exe" +if not exist ".\.nuget\nuget.exe" powershell -Command "$ProgressPreference = 'SilentlyContinue' ; Invoke-WebRequest https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -OutFile .\.nuget\nuget.exe" call .nuget\nuget.exe restore cppwinrt.sln" call .nuget\nuget.exe restore natvis\cppwinrtvisualizer.sln @@ -17,22 +18,24 @@ call .nuget\nuget.exe restore test\nuget\NugetTest.sln call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd -if "%target_platform%"=="arm" goto :eof +call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%,Deployment=Component;CppWinRTBuildVersion=%target_version% natvis\cppwinrtvisualizer.sln +call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%,Deployment=Standalone;CppWinRTBuildVersion=%target_version% natvis\cppwinrtvisualizer.sln + if "%target_platform%"=="arm64" goto :eof call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:cppwinrt -_build\%target_platform%\%target_configuration%\cppwinrt.exe -in local -out _build\%target_platform%\%target_configuration% -verbose -call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%,Deployment=Component;CppWinRTBuildVersion=%target_version% natvis\cppwinrtvisualizer.sln -call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%,Deployment=Standalone;CppWinRTBuildVersion=%target_version% natvis\cppwinrtvisualizer.sln + call msbuild /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% test\nuget\NugetTest.sln call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test +call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_nocoro call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_cpp20 -call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_win7 +call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_cpp20_no_sourcelocation call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_fast call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_slow call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_module_lock_custom call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_module_lock_none +call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\test_module_lock_none call msbuild /m /p:Configuration=%target_configuration%,Platform=%target_platform%,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:test\old_tests\test_old call run_tests.cmd %target_platform% %target_configuration% diff --git a/build_vsix.cmd b/build_vsix.cmd index ba2f75f31..0a47f6bd6 100644 --- a/build_vsix.cmd +++ b/build_vsix.cmd @@ -6,7 +6,7 @@ set target_version=%2 set target_deployment=%3 if "%target_configuration%"=="" set target_configuration=Release -if "%target_version%"=="" set target_version=1.2.3.4 +if "%target_version%"=="" set target_version=999.999.999.999 if "%target_deployment%"=="" set target_deployment=Standalone if not exist ".\.nuget" mkdir ".\.nuget" @@ -19,18 +19,18 @@ call .nuget\nuget.exe restore test\nuget\NugetTest.sln rem Build fast forwarder libs or all arches call msbuild /m /p:Configuration=%target_configuration%,Platform=x86,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd call msbuild /m /p:Configuration=%target_configuration%,Platform=x64,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd -call msbuild /m /p:Configuration=%target_configuration%,Platform=arm,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd call msbuild /m /p:Configuration=%target_configuration%,Platform=arm64,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd rem Build cppwinrt.exe for x86 only call msbuild /m /p:Configuration=%target_configuration%,Platform=x86,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:cppwinrt -rem Build cppwinrt visualizer dll for x86 and x64 +rem Build cppwinrt visualizer dll for x86, x64, and arm64 call msbuild /p:Configuration=%target_configuration%,Platform=x64,Deployment=%target_deployment%,CppWinRTBuildVersion=%target_version% natvis\cppwinrtvisualizer.sln call msbuild /p:Configuration=%target_configuration%,Platform=x86,Deployment=%target_deployment%,CppWinRTBuildVersion=%target_version% natvis\cppwinrtvisualizer.sln +call msbuild /p:Configuration=%target_configuration%,Platform=arm64,Deployment=%target_deployment%,CppWinRTBuildVersion=%target_version% natvis\cppwinrtvisualizer.sln rem Build nuget -.nuget\nuget.exe pack nuget\Microsoft.Windows.CppWinRT.nuspec -NonInteractive -OutputDirectory %this_dir%_build -Properties Configuration=%target_configuration%;cppwinrt_exe=%this_dir%_build\x86\%target_configuration%\cppwinrt.exe;cppwinrt_fast_fwd_x86=%this_dir%_build\x86\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=%this_dir%_build\x64\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm=%this_dir%_build\arm\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=%this_dir%_build\arm64\%target_configuration%\cppwinrt_fast_forwarder.lib -version %target_version% -Verbosity Detailed +.nuget\nuget.exe pack nuget\Microsoft.Windows.CppWinRT.nuspec -NonInteractive -OutputDirectory %this_dir%_build -Properties Configuration=%target_configuration%;cppwinrt_exe=%this_dir%_build\x86\%target_configuration%\cppwinrt.exe;cppwinrt_fast_fwd_x86=%this_dir%_build\x86\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=%this_dir%_build\x64\%target_configuration%\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=%this_dir%_build\arm64\%target_configuration%\cppwinrt_fast_forwarder.lib;target_version=%target_version% -version %target_version% -Verbosity Detailed rem Build vsix -call msbuild /restore /p:Configuration=%target_configuration%,Platform="Any CPU",Deployment=%target_deployment%,CppWinRTVersion=%target_version%,NatvisDirx86=%this_dir%natvis\x86\%target_configuration%\%target_deployment%,NatvisDirx64=%this_dir%natvis\x64\%target_configuration%\%target_deployment%,NupkgDir=%this_dir%_build vsix\vsix.sln +call msbuild /restore /p:Configuration=%target_configuration%,Platform="Any CPU",Deployment=%target_deployment%,CppWinRTVersion=%target_version%,NugetPackageVersion=%target_version%,NatvisDirx86=%this_dir%natvis\x86\%target_configuration%\%target_deployment%,NatvisDirx64=%this_dir%natvis\x64\%target_configuration%\%target_deployment%,NatvisDirarm64=%this_dir%natvis\arm64\%target_configuration%\%target_deployment%,NupkgDir=%this_dir%_build vsix\vsix.sln diff --git a/cppwinrt.props b/cppwinrt.props deleted file mode 100644 index 943cbc823..000000000 --- a/cppwinrt.props +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - v141 - 10.0.17763.0 - - - - v142 - 10.0 - - - - v143 - 10.0 - - - - - - clang-cl.exe - C:\Program Files\LLVM\bin - - - - - - 2.3.4.5 - $(Platform) - x86 - $(SolutionDir)_build\$(CmakePlatform)\$(Configuration) - $(CmakeOutDir)\ - $(SolutionDir)_build\x86\$(Configuration)\ - $(CmakeOutDir)\ - - - - - Level4 - true - true - stdcpp17 - stdcpplatest - Use - pch.h - CPPWINRT_VERSION_STRING="$(CppWinRTBuildVersion)";%(PreprocessorDefinitions) - true - /bigobj - /await %(AdditionalOptions) - -Wno-unused-command-line-argument -fno-delayed-template-parsing -Xclang -fcoroutines-ts -mcx16 - - - onecore.lib - - - CPPWINRT_VERSION_STRING="$(CppWinRTBuildVersion)";%(PreprocessorDefinitions) - - - - diff --git a/cppwinrt.sln b/cppwinrt.sln index e3ce40f95..700e9f5ea 100644 --- a/cppwinrt.sln +++ b/cppwinrt.sln @@ -1,7 +1,7 @@ īģŋ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28606.126 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33829.357 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cppwinrt", "cppwinrt\cppwinrt.vcxproj", "{D613FB39-5035-4043-91E2-BAB323908AF4}" ProjectSection(ProjectDependencies) = postProject @@ -24,6 +24,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Component", "test\old_tests EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Composable", "test\old_tests\Composable\Composable.vcxproj", "{152E4C6E-9A9D-4D5A-B38D-4905D173649A}" ProjectSection(ProjectDependencies) = postProject + {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject @@ -34,23 +35,26 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component", "test\test EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test\test.vcxproj", "{D2961EA1-A8CA-4A62-B760-948403DC8494}" ProjectSection(ProjectDependencies) = postProject + {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} {F1C915B3-2C64-4992-AFB7-7F035B1A7607} = {F1C915B3-2C64-4992-AFB7-7F035B1A7607} - {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_folders", "test\test_component_folders\test_component_folders.vcxproj", "{85695954-3800-4558-9857-966E69E9F9EC}" ProjectSection(ProjectDependencies) = postProject + {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_no_pch", "test\test_component_no_pch\test_component_no_pch.vcxproj", "{F1C915B3-2C64-4992-AFB7-7F035B1A7607}" ProjectSection(ProjectDependencies) = postProject + {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_base", "test\test_component_base\test_component_base.vcxproj", "{13333A6F-6A4A-48CD-865C-0F65135EB018}" ProjectSection(ProjectDependencies) = postProject + {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject @@ -61,6 +65,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_derived", "t EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_component_fast", "test\test_component_fast\test_component_fast.vcxproj", "{0E0ACA62-A92F-44CF-BD41-AEB541946DF8}" ProjectSection(ProjectDependencies) = postProject + {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject @@ -76,388 +81,353 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_slow", "test\test_slow EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_fast_fwd", "test\test_fast_fwd\test_fast_fwd.vcxproj", "{303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}" ProjectSection(ProjectDependencies) = postProject - {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} {0E0ACA62-A92F-44CF-BD41-AEB541946DF8} = {0E0ACA62-A92F-44CF-BD41-AEB541946DF8} + {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fast_fwd", "fast_fwd\fast_fwd.vcxproj", "{A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scratch", "scratch\scratch.vcxproj", "{E893622C-47DE-4F83-B422-0A26711590A4}" + ProjectSection(ProjectDependencies) = postProject + {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_module_lock_none", "test\test_module_lock_none\test_module_lock_none.vcxproj", "{D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}" ProjectSection(ProjectDependencies) = postProject - {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} - {13333A6F-6A4A-48CD-865C-0F65135EB018} = {13333A6F-6A4A-48CD-865C-0F65135EB018} {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E} = {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E} + {13333A6F-6A4A-48CD-865C-0F65135EB018} = {13333A6F-6A4A-48CD-865C-0F65135EB018} + {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_module_lock_custom", "test\test_module_lock_custom\test_module_lock_custom.vcxproj", "{08C40663-B6A3-481E-8755-AE32BAD99501}" ProjectSection(ProjectDependencies) = postProject + {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3C7EA5F8-6E8C-4376-B499-2CAF596384B0}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_win7", "test\test_win7\test_win7.vcxproj", "{2EF696B9-7F4A-410F-AE5C-5301565C0F08}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20", "test\test_cpp20\test_cpp20.vcxproj", "{5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}" ProjectSection(ProjectDependencies) = postProject + {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} - {F1C915B3-2C64-4992-AFB7-7F035B1A7607} = {F1C915B3-2C64-4992-AFB7-7F035B1A7607} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20_no_sourcelocation", "test\test_cpp20_no_sourcelocation\test_cpp20_no_sourcelocation.vcxproj", "{D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}" + ProjectSection(ProjectDependencies) = postProject {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} + {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20", "test\test_cpp20\test_cpp20.vcxproj", "{5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_nocoro", "test\test_nocoro\test_nocoro.vcxproj", "{9E392830-805A-4AAF-932D-C493143EFACA}" ProjectSection(ProjectDependencies) = postProject {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20_module", "test\test_cpp20_module\test_cpp20_module.vcxproj", "{B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}" + ProjectSection(ProjectDependencies) = postProject + {D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D15C8430-A7CD-4616-BD84-243B26A9F1C2}" + ProjectSection(SolutionItems) = preProject + build_nuget.cmd = build_nuget.cmd + build_prior_projection.cmd = build_prior_projection.cmd + build_projection.cmd = build_projection.cmd + build_test_all.cmd = build_test_all.cmd + build_vsix.cmd = build_vsix.cmd + compile_tests.cmd = compile_tests.cmd + prepare_versionless_diffs.cmd = prepare_versionless_diffs.cmd + README.md = README.md + run_tests.cmd = run_tests.cmd + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Release|ARM = Release|ARM Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|ARM.ActiveCfg = Debug|ARM - {D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|ARM.Build.0 = Debug|ARM {D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|ARM64.ActiveCfg = Debug|ARM64 {D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|ARM64.Build.0 = Debug|ARM64 {D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|x64.ActiveCfg = Debug|x64 {D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|x64.Build.0 = Debug|x64 {D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|x86.ActiveCfg = Debug|Win32 {D613FB39-5035-4043-91E2-BAB323908AF4}.Debug|x86.Build.0 = Debug|Win32 - {D613FB39-5035-4043-91E2-BAB323908AF4}.Release|ARM.ActiveCfg = Release|ARM - {D613FB39-5035-4043-91E2-BAB323908AF4}.Release|ARM.Build.0 = Release|ARM {D613FB39-5035-4043-91E2-BAB323908AF4}.Release|ARM64.ActiveCfg = Release|ARM64 {D613FB39-5035-4043-91E2-BAB323908AF4}.Release|ARM64.Build.0 = Release|ARM64 {D613FB39-5035-4043-91E2-BAB323908AF4}.Release|x64.ActiveCfg = Release|x64 {D613FB39-5035-4043-91E2-BAB323908AF4}.Release|x64.Build.0 = Release|x64 {D613FB39-5035-4043-91E2-BAB323908AF4}.Release|x86.ActiveCfg = Release|Win32 {D613FB39-5035-4043-91E2-BAB323908AF4}.Release|x86.Build.0 = Release|Win32 - {FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|ARM.ActiveCfg = Debug|ARM - {FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|ARM.Build.0 = Debug|ARM {FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|ARM64.Build.0 = Debug|ARM64 {FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|x64.ActiveCfg = Debug|x64 {FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|x64.Build.0 = Debug|x64 {FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|x86.ActiveCfg = Debug|Win32 {FB239623-7D19-4025-BCEA-B43298D4A315}.Debug|x86.Build.0 = Debug|Win32 - {FB239623-7D19-4025-BCEA-B43298D4A315}.Release|ARM.ActiveCfg = Release|ARM - {FB239623-7D19-4025-BCEA-B43298D4A315}.Release|ARM.Build.0 = Release|ARM {FB239623-7D19-4025-BCEA-B43298D4A315}.Release|ARM64.ActiveCfg = Release|ARM64 {FB239623-7D19-4025-BCEA-B43298D4A315}.Release|ARM64.Build.0 = Release|ARM64 {FB239623-7D19-4025-BCEA-B43298D4A315}.Release|x64.ActiveCfg = Release|x64 {FB239623-7D19-4025-BCEA-B43298D4A315}.Release|x64.Build.0 = Release|x64 {FB239623-7D19-4025-BCEA-B43298D4A315}.Release|x86.ActiveCfg = Release|Win32 {FB239623-7D19-4025-BCEA-B43298D4A315}.Release|x86.Build.0 = Release|Win32 - {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|ARM.ActiveCfg = Debug|ARM - {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|ARM.Build.0 = Debug|ARM {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|ARM64.ActiveCfg = Debug|ARM64 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|ARM64.Build.0 = Debug|ARM64 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|x64.ActiveCfg = Debug|x64 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|x64.Build.0 = Debug|x64 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|x86.ActiveCfg = Debug|Win32 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Debug|x86.Build.0 = Debug|Win32 - {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|ARM.ActiveCfg = Release|ARM - {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|ARM.Build.0 = Release|ARM {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|ARM64.ActiveCfg = Release|ARM64 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|ARM64.Build.0 = Release|ARM64 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|x64.ActiveCfg = Release|x64 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|x64.Build.0 = Release|x64 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|x86.ActiveCfg = Release|Win32 {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9}.Release|x86.Build.0 = Release|Win32 - {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|ARM.ActiveCfg = Debug|ARM - {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|ARM.Build.0 = Debug|ARM {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|ARM64.ActiveCfg = Debug|ARM64 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|ARM64.Build.0 = Debug|ARM64 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|x64.ActiveCfg = Debug|x64 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|x64.Build.0 = Debug|x64 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|x86.ActiveCfg = Debug|Win32 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Debug|x86.Build.0 = Debug|Win32 - {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|ARM.ActiveCfg = Release|ARM - {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|ARM.Build.0 = Release|ARM {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|ARM64.ActiveCfg = Release|ARM64 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|ARM64.Build.0 = Release|ARM64 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|x64.ActiveCfg = Release|x64 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|x64.Build.0 = Release|x64 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|x86.ActiveCfg = Release|Win32 {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}.Release|x86.Build.0 = Release|Win32 - {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|ARM.ActiveCfg = Debug|ARM - {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|ARM.Build.0 = Debug|ARM {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|ARM64.ActiveCfg = Debug|ARM64 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|ARM64.Build.0 = Debug|ARM64 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|x64.ActiveCfg = Debug|x64 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|x64.Build.0 = Debug|x64 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|x86.ActiveCfg = Debug|Win32 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Debug|x86.Build.0 = Debug|Win32 - {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|ARM.ActiveCfg = Release|ARM - {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|ARM.Build.0 = Release|ARM {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|ARM64.ActiveCfg = Release|ARM64 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|ARM64.Build.0 = Release|ARM64 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|x64.ActiveCfg = Release|x64 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|x64.Build.0 = Release|x64 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|x86.ActiveCfg = Release|Win32 {152E4C6E-9A9D-4D5A-B38D-4905D173649A}.Release|x86.Build.0 = Release|Win32 - {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|ARM.ActiveCfg = Debug|ARM - {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|ARM.Build.0 = Debug|ARM {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|ARM64.Build.0 = Debug|ARM64 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|x64.ActiveCfg = Debug|x64 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|x64.Build.0 = Debug|x64 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|x86.ActiveCfg = Debug|Win32 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Debug|x86.Build.0 = Debug|Win32 - {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|ARM.ActiveCfg = Release|ARM - {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|ARM.Build.0 = Release|ARM {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|ARM64.ActiveCfg = Release|ARM64 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|ARM64.Build.0 = Release|ARM64 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|x64.ActiveCfg = Release|x64 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|x64.Build.0 = Release|x64 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|x86.ActiveCfg = Release|Win32 {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}.Release|x86.Build.0 = Release|Win32 - {D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|ARM.ActiveCfg = Debug|ARM - {D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|ARM.Build.0 = Debug|ARM {D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|ARM64.ActiveCfg = Debug|ARM64 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|ARM64.Build.0 = Debug|ARM64 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|x64.ActiveCfg = Debug|x64 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|x64.Build.0 = Debug|x64 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|x86.ActiveCfg = Debug|Win32 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Debug|x86.Build.0 = Debug|Win32 - {D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|ARM.ActiveCfg = Release|ARM - {D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|ARM.Build.0 = Release|ARM {D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|ARM64.ActiveCfg = Release|ARM64 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|ARM64.Build.0 = Release|ARM64 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|x64.ActiveCfg = Release|x64 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|x64.Build.0 = Release|x64 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|x86.ActiveCfg = Release|Win32 {D2961EA1-A8CA-4A62-B760-948403DC8494}.Release|x86.Build.0 = Release|Win32 - {85695954-3800-4558-9857-966E69E9F9EC}.Debug|ARM.ActiveCfg = Debug|ARM - {85695954-3800-4558-9857-966E69E9F9EC}.Debug|ARM.Build.0 = Debug|ARM {85695954-3800-4558-9857-966E69E9F9EC}.Debug|ARM64.ActiveCfg = Debug|ARM64 {85695954-3800-4558-9857-966E69E9F9EC}.Debug|ARM64.Build.0 = Debug|ARM64 {85695954-3800-4558-9857-966E69E9F9EC}.Debug|x64.ActiveCfg = Debug|x64 {85695954-3800-4558-9857-966E69E9F9EC}.Debug|x64.Build.0 = Debug|x64 {85695954-3800-4558-9857-966E69E9F9EC}.Debug|x86.ActiveCfg = Debug|Win32 {85695954-3800-4558-9857-966E69E9F9EC}.Debug|x86.Build.0 = Debug|Win32 - {85695954-3800-4558-9857-966E69E9F9EC}.Release|ARM.ActiveCfg = Release|ARM - {85695954-3800-4558-9857-966E69E9F9EC}.Release|ARM.Build.0 = Release|ARM {85695954-3800-4558-9857-966E69E9F9EC}.Release|ARM64.ActiveCfg = Release|ARM64 {85695954-3800-4558-9857-966E69E9F9EC}.Release|ARM64.Build.0 = Release|ARM64 {85695954-3800-4558-9857-966E69E9F9EC}.Release|x64.ActiveCfg = Release|x64 {85695954-3800-4558-9857-966E69E9F9EC}.Release|x64.Build.0 = Release|x64 {85695954-3800-4558-9857-966E69E9F9EC}.Release|x86.ActiveCfg = Release|Win32 {85695954-3800-4558-9857-966E69E9F9EC}.Release|x86.Build.0 = Release|Win32 - {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|ARM.ActiveCfg = Debug|ARM - {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|ARM.Build.0 = Debug|ARM {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|ARM64.Build.0 = Debug|ARM64 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|x64.ActiveCfg = Debug|x64 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|x64.Build.0 = Debug|x64 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|x86.ActiveCfg = Debug|Win32 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Debug|x86.Build.0 = Debug|Win32 - {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|ARM.ActiveCfg = Release|ARM - {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|ARM.Build.0 = Release|ARM {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|ARM64.ActiveCfg = Release|ARM64 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|ARM64.Build.0 = Release|ARM64 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|x64.ActiveCfg = Release|x64 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|x64.Build.0 = Release|x64 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|x86.ActiveCfg = Release|Win32 {F1C915B3-2C64-4992-AFB7-7F035B1A7607}.Release|x86.Build.0 = Release|Win32 - {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|ARM.ActiveCfg = Debug|ARM - {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|ARM.Build.0 = Debug|ARM {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|ARM64.ActiveCfg = Debug|ARM64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|ARM64.Build.0 = Debug|ARM64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x64.ActiveCfg = Debug|x64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x64.Build.0 = Debug|x64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x86.ActiveCfg = Debug|Win32 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Debug|x86.Build.0 = Debug|Win32 - {13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|ARM.ActiveCfg = Release|ARM - {13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|ARM.Build.0 = Release|ARM {13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|ARM64.ActiveCfg = Release|ARM64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|ARM64.Build.0 = Release|ARM64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|x64.ActiveCfg = Release|x64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|x64.Build.0 = Release|x64 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|x86.ActiveCfg = Release|Win32 {13333A6F-6A4A-48CD-865C-0F65135EB018}.Release|x86.Build.0 = Release|Win32 - {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|ARM.ActiveCfg = Debug|ARM - {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|ARM.Build.0 = Debug|ARM {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|ARM64.ActiveCfg = Debug|ARM64 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|ARM64.Build.0 = Debug|ARM64 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|x64.ActiveCfg = Debug|x64 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|x64.Build.0 = Debug|x64 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|x86.ActiveCfg = Debug|Win32 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Debug|x86.Build.0 = Debug|Win32 - {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|ARM.ActiveCfg = Release|ARM - {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|ARM.Build.0 = Release|ARM {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|ARM64.ActiveCfg = Release|ARM64 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|ARM64.Build.0 = Release|ARM64 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|x64.ActiveCfg = Release|x64 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|x64.Build.0 = Release|x64 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|x86.ActiveCfg = Release|Win32 {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E}.Release|x86.Build.0 = Release|Win32 - {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|ARM.ActiveCfg = Debug|ARM - {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|ARM.Build.0 = Debug|ARM {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|ARM64.ActiveCfg = Debug|ARM64 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|ARM64.Build.0 = Debug|ARM64 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|x64.ActiveCfg = Debug|x64 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|x64.Build.0 = Debug|x64 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|x86.ActiveCfg = Debug|Win32 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Debug|x86.Build.0 = Debug|Win32 - {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|ARM.ActiveCfg = Release|ARM - {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|ARM.Build.0 = Release|ARM {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|ARM64.ActiveCfg = Release|ARM64 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|ARM64.Build.0 = Release|ARM64 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|x64.ActiveCfg = Release|x64 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|x64.Build.0 = Release|x64 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|x86.ActiveCfg = Release|Win32 {0E0ACA62-A92F-44CF-BD41-AEB541946DF8}.Release|x86.Build.0 = Release|Win32 - {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|ARM.ActiveCfg = Debug|ARM - {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|ARM.Build.0 = Debug|ARM {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|ARM64.ActiveCfg = Debug|ARM64 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|ARM64.Build.0 = Debug|ARM64 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|x64.ActiveCfg = Debug|x64 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|x64.Build.0 = Debug|x64 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|x86.ActiveCfg = Debug|Win32 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Debug|x86.Build.0 = Debug|Win32 - {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|ARM.ActiveCfg = Release|ARM - {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|ARM.Build.0 = Release|ARM {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|ARM64.ActiveCfg = Release|ARM64 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|ARM64.Build.0 = Release|ARM64 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|x64.ActiveCfg = Release|x64 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|x64.Build.0 = Release|x64 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|x86.ActiveCfg = Release|Win32 {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484}.Release|x86.Build.0 = Release|Win32 - {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|ARM.ActiveCfg = Debug|ARM - {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|ARM.Build.0 = Debug|ARM {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|ARM64.ActiveCfg = Debug|ARM64 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|ARM64.Build.0 = Debug|ARM64 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|x64.ActiveCfg = Debug|x64 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|x64.Build.0 = Debug|x64 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|x86.ActiveCfg = Debug|Win32 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Debug|x86.Build.0 = Debug|Win32 - {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|ARM.ActiveCfg = Release|ARM - {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|ARM.Build.0 = Release|ARM {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|ARM64.ActiveCfg = Release|ARM64 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|ARM64.Build.0 = Release|ARM64 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|x64.ActiveCfg = Release|x64 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|x64.Build.0 = Release|x64 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|x86.ActiveCfg = Release|Win32 {B68C61C6-4699-41E6-A158-EA1BE029E7A0}.Release|x86.Build.0 = Release|Win32 - {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|ARM.ActiveCfg = Debug|ARM - {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|ARM.Build.0 = Debug|ARM {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|ARM64.ActiveCfg = Debug|ARM64 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|ARM64.Build.0 = Debug|ARM64 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|x64.ActiveCfg = Debug|x64 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|x64.Build.0 = Debug|x64 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|x86.ActiveCfg = Debug|Win32 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Debug|x86.Build.0 = Debug|Win32 - {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|ARM.ActiveCfg = Release|ARM - {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|ARM.Build.0 = Release|ARM {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|ARM64.ActiveCfg = Release|ARM64 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|ARM64.Build.0 = Release|ARM64 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|x64.ActiveCfg = Release|x64 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|x64.Build.0 = Release|x64 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|x86.ActiveCfg = Release|Win32 {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074}.Release|x86.Build.0 = Release|Win32 - {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|ARM.ActiveCfg = Debug|ARM - {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|ARM.Build.0 = Debug|ARM {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|ARM64.Build.0 = Debug|ARM64 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|x64.ActiveCfg = Debug|x64 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|x64.Build.0 = Debug|x64 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|x86.ActiveCfg = Debug|Win32 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Debug|x86.Build.0 = Debug|Win32 - {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|ARM.ActiveCfg = Release|ARM - {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|ARM.Build.0 = Release|ARM {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|ARM64.ActiveCfg = Release|ARM64 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|ARM64.Build.0 = Release|ARM64 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|x64.ActiveCfg = Release|x64 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|x64.Build.0 = Release|x64 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|x86.ActiveCfg = Release|Win32 {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459}.Release|x86.Build.0 = Release|Win32 - {E893622C-47DE-4F83-B422-0A26711590A4}.Debug|ARM.ActiveCfg = Debug|ARM - {E893622C-47DE-4F83-B422-0A26711590A4}.Debug|ARM.Build.0 = Debug|ARM {E893622C-47DE-4F83-B422-0A26711590A4}.Debug|ARM64.ActiveCfg = Debug|ARM64 {E893622C-47DE-4F83-B422-0A26711590A4}.Debug|ARM64.Build.0 = Debug|ARM64 {E893622C-47DE-4F83-B422-0A26711590A4}.Debug|x64.ActiveCfg = Debug|x64 {E893622C-47DE-4F83-B422-0A26711590A4}.Debug|x64.Build.0 = Debug|x64 {E893622C-47DE-4F83-B422-0A26711590A4}.Debug|x86.ActiveCfg = Debug|Win32 {E893622C-47DE-4F83-B422-0A26711590A4}.Debug|x86.Build.0 = Debug|Win32 - {E893622C-47DE-4F83-B422-0A26711590A4}.Release|ARM.ActiveCfg = Release|ARM - {E893622C-47DE-4F83-B422-0A26711590A4}.Release|ARM.Build.0 = Release|ARM {E893622C-47DE-4F83-B422-0A26711590A4}.Release|ARM64.ActiveCfg = Release|ARM64 {E893622C-47DE-4F83-B422-0A26711590A4}.Release|ARM64.Build.0 = Release|ARM64 {E893622C-47DE-4F83-B422-0A26711590A4}.Release|x64.ActiveCfg = Release|x64 {E893622C-47DE-4F83-B422-0A26711590A4}.Release|x64.Build.0 = Release|x64 {E893622C-47DE-4F83-B422-0A26711590A4}.Release|x86.ActiveCfg = Release|Win32 {E893622C-47DE-4F83-B422-0A26711590A4}.Release|x86.Build.0 = Release|Win32 - {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|ARM.ActiveCfg = Debug|ARM - {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|ARM.Build.0 = Debug|ARM {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|ARM64.ActiveCfg = Debug|ARM64 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|ARM64.Build.0 = Debug|ARM64 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|x64.ActiveCfg = Debug|x64 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|x64.Build.0 = Debug|x64 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|x86.ActiveCfg = Debug|Win32 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Debug|x86.Build.0 = Debug|Win32 - {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|ARM.ActiveCfg = Release|ARM - {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|ARM.Build.0 = Release|ARM {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|ARM64.ActiveCfg = Release|ARM64 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|ARM64.Build.0 = Release|ARM64 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|x64.ActiveCfg = Release|x64 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|x64.Build.0 = Release|x64 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|x86.ActiveCfg = Release|Win32 {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3}.Release|x86.Build.0 = Release|Win32 - {08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|ARM.ActiveCfg = Debug|ARM - {08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|ARM.Build.0 = Debug|ARM {08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|ARM64.ActiveCfg = Debug|ARM64 {08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|ARM64.Build.0 = Debug|ARM64 {08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|x64.ActiveCfg = Debug|x64 {08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|x64.Build.0 = Debug|x64 {08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|x86.ActiveCfg = Debug|Win32 {08C40663-B6A3-481E-8755-AE32BAD99501}.Debug|x86.Build.0 = Debug|Win32 - {08C40663-B6A3-481E-8755-AE32BAD99501}.Release|ARM.ActiveCfg = Release|ARM - {08C40663-B6A3-481E-8755-AE32BAD99501}.Release|ARM.Build.0 = Release|ARM {08C40663-B6A3-481E-8755-AE32BAD99501}.Release|ARM64.ActiveCfg = Release|ARM64 {08C40663-B6A3-481E-8755-AE32BAD99501}.Release|ARM64.Build.0 = Release|ARM64 {08C40663-B6A3-481E-8755-AE32BAD99501}.Release|x64.ActiveCfg = Release|x64 {08C40663-B6A3-481E-8755-AE32BAD99501}.Release|x64.Build.0 = Release|x64 {08C40663-B6A3-481E-8755-AE32BAD99501}.Release|x86.ActiveCfg = Release|Win32 {08C40663-B6A3-481E-8755-AE32BAD99501}.Release|x86.Build.0 = Release|Win32 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Debug|ARM.ActiveCfg = Debug|ARM - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Debug|ARM.Build.0 = Debug|ARM - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Debug|ARM64.Build.0 = Debug|ARM64 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Debug|x64.ActiveCfg = Debug|x64 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Debug|x64.Build.0 = Debug|x64 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Debug|x86.ActiveCfg = Debug|Win32 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Debug|x86.Build.0 = Debug|Win32 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|ARM.ActiveCfg = Release|ARM - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|ARM.Build.0 = Release|ARM - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|ARM64.ActiveCfg = Release|ARM64 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|ARM64.Build.0 = Release|ARM64 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|x64.ActiveCfg = Release|x64 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|x64.Build.0 = Release|x64 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|x86.ActiveCfg = Release|Win32 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08}.Release|x86.Build.0 = Release|Win32 - {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|ARM.ActiveCfg = Debug|ARM - {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|ARM.Build.0 = Debug|ARM {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|ARM64.ActiveCfg = Debug|ARM64 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|ARM64.Build.0 = Debug|ARM64 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|x64.ActiveCfg = Debug|x64 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|x64.Build.0 = Debug|x64 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|x86.ActiveCfg = Debug|Win32 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Debug|x86.Build.0 = Debug|Win32 - {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|ARM.ActiveCfg = Release|ARM - {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|ARM.Build.0 = Release|ARM {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|ARM64.ActiveCfg = Release|ARM64 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|ARM64.Build.0 = Release|ARM64 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|x64.ActiveCfg = Release|x64 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|x64.Build.0 = Release|x64 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|x86.ActiveCfg = Release|Win32 {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}.Release|x86.Build.0 = Release|Win32 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Debug|ARM64.Build.0 = Debug|ARM64 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Debug|x64.ActiveCfg = Debug|x64 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Debug|x64.Build.0 = Debug|x64 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Debug|x86.ActiveCfg = Debug|Win32 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Debug|x86.Build.0 = Debug|Win32 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|ARM64.ActiveCfg = Release|ARM64 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|ARM64.Build.0 = Release|ARM64 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|x64.ActiveCfg = Release|x64 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|x64.Build.0 = Release|x64 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|x86.ActiveCfg = Release|Win32 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}.Release|x86.Build.0 = Release|Win32 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|ARM64.Build.0 = Debug|ARM64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|x64.ActiveCfg = Debug|x64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|x64.Build.0 = Debug|x64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|x86.ActiveCfg = Debug|Win32 + {9E392830-805A-4AAF-932D-C493143EFACA}.Debug|x86.Build.0 = Debug|Win32 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|ARM64.ActiveCfg = Release|ARM64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|ARM64.Build.0 = Release|ARM64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x64.ActiveCfg = Release|x64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x64.Build.0 = Release|x64 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x86.ActiveCfg = Release|Win32 + {9E392830-805A-4AAF-932D-C493143EFACA}.Release|x86.Build.0 = Release|Win32 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|ARM64.Build.0 = Debug|ARM64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|x64.ActiveCfg = Debug|x64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|x64.Build.0 = Debug|x64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|x86.ActiveCfg = Debug|Win32 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Debug|x86.Build.0 = Debug|Win32 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|ARM64.ActiveCfg = Release|ARM64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|ARM64.Build.0 = Release|ARM64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|x64.ActiveCfg = Release|x64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|x64.Build.0 = Release|x64 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|x86.ActiveCfg = Release|Win32 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -479,8 +449,10 @@ Global {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {08C40663-B6A3-481E-8755-AE32BAD99501} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} - {2EF696B9-7F4A-410F-AE5C-5301565C0F08} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} + {9E392830-805A-4AAF-932D-C493143EFACA} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72} = {3C7EA5F8-6E8C-4376-B499-2CAF596384B0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2783B8FD-EA3B-4D6B-9F81-662D289E02AA} diff --git a/cppwinrt/app.manifest b/cppwinrt/app.manifest index 16b477c20..69b366b27 100644 --- a/cppwinrt/app.manifest +++ b/cppwinrt/app.manifest @@ -3,6 +3,7 @@ true + UTF-8 \ No newline at end of file diff --git a/cppwinrt/cmd_reader.h b/cppwinrt/cmd_reader.h index e50f66036..e2787b7d4 100644 --- a/cppwinrt/cmd_reader.h +++ b/cppwinrt/cmd_reader.h @@ -3,7 +3,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -12,12 +14,16 @@ #include #include #include -#include + +#if defined(_WIN32) || defined(_WIN64) +#include #include -#include +#include +#endif namespace cppwinrt { +#if defined(_WIN32) || defined(_WIN64) struct registry_key { HKEY handle{}; @@ -71,17 +77,31 @@ namespace cppwinrt } } + enum class xml_requirement + { + required = 0, + optional + }; + inline void add_files_from_xml( std::set& files, std::string const& sdk_version, std::filesystem::path const& xml_path, - std::filesystem::path const& sdk_path) + std::filesystem::path const& sdk_path, + xml_requirement xml_path_requirement) { com_ptr stream; - check_xml(SHCreateStreamOnFileW( + auto streamResult = SHCreateStreamOnFileW( xml_path.c_str(), - STGM_READ, &stream.ptr)); + STGM_READ, &stream.ptr); + if (xml_path_requirement == xml_requirement::optional && + (streamResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || + streamResult == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND))) + { + return; + } + check_xml(streamResult); com_ptr reader; @@ -181,11 +201,10 @@ namespace cppwinrt inline std::string get_module_path() { std::string path(100, '?'); - DWORD actual_size{}; while (true) { - actual_size = GetModuleFileNameA(nullptr, path.data(), 1 + static_cast(path.size())); + DWORD actual_size = GetModuleFileNameA(nullptr, path.data(), 1 + static_cast(path.size())); if (actual_size < 1 + path.size()) { @@ -219,12 +238,12 @@ namespace cppwinrt } auto key = open_sdk(); - uint32_t index{}; + std::uint32_t index{}; std::array subkey; std::array version_parts{}; std::string result; - while (0 == RegEnumKeyA(key.handle, index++, subkey.data(), static_cast(subkey.size()))) + while (0 == RegEnumKeyA(key.handle, index++, subkey.data(), static_cast(subkey.size()))) { if (!std::regex_match(subkey.data(), match, rx)) { @@ -240,7 +259,7 @@ namespace cppwinrt char* next_part = subkey.data(); bool force_newer = false; - for (size_t i = 0; ; ++i) + for (std::size_t i = 0; ; ++i) { auto version_part = strtoul(next_part, &next_part, 10); @@ -278,6 +297,7 @@ namespace cppwinrt return result; } +#endif /* defined(_WIN32) || defined(_WIN64) */ [[noreturn]] inline void throw_invalid(std::string const& message) { @@ -293,19 +313,19 @@ namespace cppwinrt struct option { - static constexpr uint32_t no_min = 0; - static constexpr uint32_t no_max = UINT_MAX; + static constexpr std::uint32_t no_min = 0; + static constexpr std::uint32_t no_max = (std::numeric_limits::max)(); std::string_view name; - uint32_t min{ no_min }; - uint32_t max{ no_max }; + std::uint32_t min{ no_min }; + std::uint32_t max{ no_max }; std::string_view arg{}; std::string_view desc{}; }; struct reader { - template + template reader(C const argc, V const argv, const option(& options)[numOptions]) { #ifdef _DEBUG @@ -427,13 +447,17 @@ namespace cppwinrt } if (path == "local") { +#if defined(_WIN32) || defined(_WIN64) std::array local{}; #ifdef _WIN64 - ExpandEnvironmentStringsA("%windir%\\System32\\WinMetadata", local.data(), static_cast(local.size())); + ExpandEnvironmentStringsA("%windir%\\System32\\WinMetadata", local.data(), static_cast(local.size())); #else - ExpandEnvironmentStringsA("%windir%\\SysNative\\WinMetadata", local.data(), static_cast(local.size())); + ExpandEnvironmentStringsA("%windir%\\SysNative\\WinMetadata", local.data(), static_cast(local.size())); #endif add_directory(local.data()); +#else /* defined(_WIN32) || defined(_WIN64) */ + throw_invalid("Spec '", path, "' not supported outside of Windows"); +#endif /* defined(_WIN32) || defined(_WIN64) */ continue; } @@ -441,7 +465,11 @@ namespace cppwinrt if (path == "sdk" || path == "sdk+") { +#if defined(_WIN32) || defined(_WIN64) sdk_version = get_sdk_version(); +#else /* defined(_WIN32) || defined(_WIN64) */ + throw_invalid("Spec '", path, "' not supported outside of Windows"); +#endif /* defined(_WIN32) || defined(_WIN64) */ } else { @@ -456,13 +484,14 @@ namespace cppwinrt if (!sdk_version.empty()) { +#if defined(_WIN32) || defined(_WIN64) auto sdk_path = get_sdk_path(); auto xml_path = sdk_path; xml_path /= L"Platforms\\UAP"; xml_path /= sdk_version; xml_path /= L"Platform.xml"; - add_files_from_xml(files, sdk_version, xml_path, sdk_path); + add_files_from_xml(files, sdk_version, xml_path, sdk_path, xml_requirement::required); if (path.back() != '+') { @@ -474,8 +503,12 @@ namespace cppwinrt xml_path = item.path() / sdk_version; xml_path /= L"SDKManifest.xml"; - add_files_from_xml(files, sdk_version, xml_path, sdk_path); + // Not all Extension SDKs include an SDKManifest.xml file; ignore those which do not (e.g. WindowsIoT). + add_files_from_xml(files, sdk_version, xml_path, sdk_path, xml_requirement::optional); } +#else /* defined(_WIN32) || defined(_WIN64) */ + throw_invalid("Spec '", path, "' not supported outside of Windows"); +#endif /* defined(_WIN32) || defined(_WIN64) */ continue; } @@ -517,7 +550,11 @@ namespace cppwinrt template void extract_option(std::string_view arg, O const& options, L& last) { - if (arg[0] == '-' || arg[0] == '/') + if (arg[0] == '-' +#if defined(_WIN32) || defined(_WIN64) + || arg[0] == '/' +#endif + ) { arg.remove_prefix(1); last = find(options, arg); @@ -550,7 +587,7 @@ namespace cppwinrt std::filesystem::path response_path{ std::string{ arg } }; std::string extension = response_path.extension().generic_string(); std::transform(extension.begin(), extension.end(), extension.begin(), - [](auto c) { return static_cast(::tolower(c)); }); + [](auto c) { return static_cast(std::tolower(c)); }); // Check if misuse of @ prefix, so if directory or metadata file instead of response file. if (is_directory(response_path) || extension == ".winmd") @@ -561,12 +598,12 @@ namespace cppwinrt std::ifstream response_file(absolute(response_path)); while (getline(response_file, line_buf)) { - size_t argc = 0; + std::size_t argc = 0; std::vector argv; parse_command_line(line_buf.data(), argv, &argc); - for (size_t i = 0; i < argc; i++) + for (std::size_t i = 0; i < argc; i++) { extract_option(argv[i], options, last); } @@ -574,7 +611,7 @@ namespace cppwinrt } template - static void parse_command_line(Character* cmdstart, std::vector& argv, size_t* argument_count) + static void parse_command_line(Character* cmdstart, std::vector& argv, std::size_t* argument_count) { std::string arg; @@ -588,7 +625,7 @@ namespace cppwinrt first_arg = true; *argument_count = 0; - for (;;) + while (true) { if (*p) { @@ -606,7 +643,7 @@ namespace cppwinrt if (*p == '\0') break; - for (;;) + while (true) { copy_character = true; diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 9d4b98e23..a9aa5bc78 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -5,9 +5,9 @@ namespace cppwinrt struct finish_with { writer& w; - void (*finisher)(writer&); + std::function finisher; - finish_with(writer& w, void (*finisher)(writer&)) : w(w), finisher(finisher) {} + finish_with(writer& w, std::function finisher) : w(w), finisher(std::move(finisher)) {} finish_with(finish_with const&)= delete; void operator=(finish_with const&) = delete; @@ -24,10 +24,8 @@ namespace cppwinrt { w.write(R"(// C++/WinRT v% -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -)", CPPWINRT_VERSION_STRING); +% +)", CPPWINRT_VERSION_STRING, settings.license_template); } else { @@ -37,6 +35,35 @@ namespace cppwinrt } } + static void write_endif(writer& w, std::string_view macro = {}) + { + if (macro.empty()) + { + w.write("#endif\n"); + } + else + { + w.write("#endif // %\n", macro); + } + } + + // When modules are enabled, wraps a block of #include directives in + // #ifndef WINRT_IMPL_BUILD_MODULE ... #endif so that in module builds (where + // WINRT_IMPL_BUILD_MODULE is defined in the global module fragment), textual + // includes are suppressed — dependencies come via import instead. + [[nodiscard]] static finish_with wrap_module_aware_includes_guard(writer& w, bool modules_enabled) + { + if (modules_enabled) + { + w.write("#ifndef WINRT_IMPL_BUILD_MODULE\n"); + return { w, [](writer& w) { write_endif(w, "WINRT_IMPL_BUILD_MODULE"); } }; + } + else + { + return { w, write_nothing }; + } + } + static void write_version_assert(writer& w) { w.write_root_include("base"); @@ -54,14 +81,6 @@ namespace cppwinrt w.write(format); } - static void write_endif(writer& w) - { - auto format = R"(#endif -)"; - - w.write(format); - } - static void write_close_file_guard(writer& w) { write_endif(w); @@ -107,7 +126,7 @@ namespace cppwinrt w.write(format); - return { w, write_endif }; + return { w, [](writer& w) { write_endif(w, "WINRT_LEAN_AND_MEAN"); } }; } else { @@ -122,7 +141,17 @@ namespace cppwinrt w.write(format, macro); - return { w, write_endif }; + return { w, [macro = std::string(macro)](writer& w) { write_endif(w, macro); } }; + } + + [[nodiscard]] static finish_with wrap_ifndef(writer& w, std::string_view macro) + { + auto format = R"(#ifndef % +)"; + + w.write(format, macro); + + return { w, [macro = std::string(macro)](writer& w) { write_endif(w, macro); } }; } static void write_parent_depends(writer& w, cache const& c, std::string_view const& type_namespace) @@ -168,7 +197,7 @@ namespace cppwinrt [[nodiscard]] static finish_with wrap_impl_namespace(writer& w) { - auto format = R"(namespace winrt::impl + auto format = R"(WINRT_EXPORT namespace winrt::impl { )"; @@ -197,6 +226,17 @@ namespace cppwinrt return { w, write_close_namespace }; } + [[nodiscard]] static finish_with wrap_type_namespace_without_export(writer& w, std::string_view const& ns) + { + auto format = R"(namespace winrt::@ +{ +)"; + + w.write(format, ns); + + return { w, write_close_namespace }; + } + static void write_enum_field(writer& w, Field const& field) { auto format = R"( % = %, @@ -348,7 +388,7 @@ namespace cppwinrt return; } - auto format = R"( template <%> struct __declspec(empty_bases) %; + auto format = R"( template <%> struct WINRT_IMPL_EMPTY_BASES %; )"; w.write(format, @@ -361,17 +401,17 @@ namespace cppwinrt using std::get; w.write_printf("0x%08X,0x%04X,0x%04X,{ 0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X,0x%02X }", - get(get(args[0].value).value), - get(get(args[1].value).value), - get(get(args[2].value).value), - get(get(args[3].value).value), - get(get(args[4].value).value), - get(get(args[5].value).value), - get(get(args[6].value).value), - get(get(args[7].value).value), - get(get(args[8].value).value), - get(get(args[9].value).value), - get(get(args[10].value).value)); + get(get(args[0].value).value), + get(get(args[1].value).value), + get(get(args[2].value).value), + get(get(args[3].value).value), + get(get(args[4].value).value), + get(get(args[5].value).value), + get(get(args[6].value).value), + get(get(args[7].value).value), + get(get(args[8].value).value), + get(get(args[9].value).value), + get(get(args[10].value).value)); } static void write_guid_comment(writer& w, std::vector const& args) @@ -379,17 +419,17 @@ namespace cppwinrt using std::get; w.write_printf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", - get(get(args[0].value).value), - get(get(args[1].value).value), - get(get(args[2].value).value), - get(get(args[3].value).value), - get(get(args[4].value).value), - get(get(args[5].value).value), - get(get(args[6].value).value), - get(get(args[7].value).value), - get(get(args[8].value).value), - get(get(args[9].value).value), - get(get(args[10].value).value)); + get(get(args[0].value).value), + get(get(args[1].value).value), + get(get(args[2].value).value), + get(get(args[3].value).value), + get(get(args[4].value).value), + get(get(args[5].value).value), + get(get(args[6].value).value), + get(get(args[7].value).value), + get(get(args[8].value).value), + get(get(args[9].value).value), + get(get(args[10].value).value)); } static void write_category(writer& w, TypeDef const& type, std::string_view const& category) @@ -417,7 +457,7 @@ namespace cppwinrt static void write_generic_names(writer& w, std::pair const& params) { - bool first{ true }; + bool first = true; for (auto&& param : params) { @@ -563,15 +603,15 @@ namespace cppwinrt if (param.Flags().In()) { - format = "uint32_t%, %"; + format = "std::uint32_t%, %"; } else if (param_signature->ByRef()) { - format = "uint32_t*%, %*"; + format = "std::uint32_t*%, %*"; } else { - format = "uint32_t%, %"; + format = "std::uint32_t%, %"; } w.write(format, bind(param), bind(param_signature->Type())); @@ -607,7 +647,7 @@ namespace cppwinrt if (type.is_szarray()) { - w.write("uint32_t* __%Size, %**", method_signature.return_param_name(), type); + w.write("std::uint32_t* __%Size, %**", method_signature.return_param_name(), type); } else { @@ -621,10 +661,15 @@ namespace cppwinrt } } - static void write_abi_args(writer& w, method_signature const& method_signature) + static void write_abi_args(writer& w, method_signature const& method_signature, bool start_comma) { separator s{ w }; + if (start_comma) + { + s(); + } + for (auto&& [param, param_signature] : method_signature.params()) { s(); @@ -745,7 +790,7 @@ namespace cppwinrt break; } - auto format = R"( virtual int32_t __stdcall %(%) noexcept = 0; + auto format = R"( virtual std::int32_t __stdcall %(%) noexcept = 0; )"; for (auto&& method : info.type.MethodList()) @@ -765,7 +810,7 @@ namespace cppwinrt { auto format = R"( template <> struct abi<%> { - struct __declspec(novtable) type : inspectable_abi + struct WINRT_IMPL_ABI_DECL type : inspectable_abi { )"; @@ -775,7 +820,7 @@ namespace cppwinrt { auto format = R"( template <%> struct abi<%> { - struct __declspec(novtable) type : inspectable_abi + struct WINRT_IMPL_ABI_DECL type : inspectable_abi { )"; @@ -785,7 +830,7 @@ namespace cppwinrt } - auto format = R"( virtual int32_t __stdcall %(%) noexcept = 0; + auto format = R"( virtual std::int32_t __stdcall %(%) noexcept = 0; )"; auto abi_guard = w.push_abi_types(true); @@ -816,9 +861,9 @@ namespace cppwinrt { auto format = R"( template <%> struct abi<%> { - struct __declspec(novtable) type : unknown_abi + struct WINRT_IMPL_ABI_DECL type : unknown_abi { - virtual int32_t __stdcall Invoke(%) noexcept = 0; + virtual std::int32_t __stdcall Invoke(%) noexcept = 0; }; }; )"; @@ -992,9 +1037,8 @@ namespace cppwinrt auto method_name = get_name(method); auto type = method.Parent(); - w.write(" %WINRT_IMPL_AUTO(%) %(%) const%;\n", + w.write(" %auto %(%) const%;\n", is_get_overload(method) ? "[[nodiscard]] " : "", - signature.return_signature(), method_name, bind(signature), is_noexcept(method) ? " noexcept" : ""); @@ -1002,7 +1046,7 @@ namespace cppwinrt if (is_add_overload(method)) { auto format = R"( using %_revoker = impl::event_revoker<%, &impl::abi_t<%>::remove_%>; - [[nodiscard]] %_revoker %(auto_revoke_t, %) const; + [[nodiscard]] auto %(auto_revoke_t, %) const; )"; w.write(format, @@ -1011,7 +1055,6 @@ namespace cppwinrt type, method_name, method_name, - method_name, bind(signature)); } } @@ -1053,7 +1096,7 @@ namespace cppwinrt if (category == param_category::array_type) { auto format = R"( - uint32_t %_impl_size{}; + std::uint32_t %_impl_size{}; %* %{};)"; auto abi_guard = w.push_abi_types(true); @@ -1133,46 +1176,50 @@ namespace cppwinrt if (is_remove_overload(method)) { // we intentionally ignore errors when unregistering event handlers to be consistent with event_revoker - format = R"( template WINRT_IMPL_AUTO(%) consume_%::%(%) const noexcept + // + // The `noexcept` versions will crash if check_hresult throws but that is no different than previous + // behavior where it would not check the cast result and nullptr crash. At least the exception will terminate + // immediately while preserving the error code and local variables. + format = R"( template auto consume_%::%(%) const noexcept {% - WINRT_IMPL_SHIM(%)->%(%);% + consume_noexcept_remove_overload<%, D>(static_cast(this), &abi_t<%>::%%);% } )"; } else { - format = R"( template WINRT_IMPL_AUTO(%) consume_%::%(%) const noexcept + format = R"( template auto consume_%::%(%) const noexcept {% - WINRT_VERIFY_(0, WINRT_IMPL_SHIM(%)->%(%));% + consume_noexcept<%, D>(static_cast(this), &abi_t<%>::%%);% } )"; } } else { - format = R"( template WINRT_IMPL_AUTO(%) consume_%::%(%) const + format = R"( template auto consume_%::%(%) const {% - check_hresult(WINRT_IMPL_SHIM(%)->%(%));% + consume_general<%, D>(static_cast(this), &abi_t<%>::%%);% } )"; } w.write(format, bind(generics), - signature.return_signature(), type_impl_name, bind(generics), method_name, bind(signature), bind(signature, false), type, + type, get_abi_name(method), - bind(signature), + bind(signature, true), bind(signature)); if (is_add_overload(method)) { - format = R"( template typename consume_%::%_revoker consume_%::%(auto_revoke_t, %) const + format = R"( template auto consume_%::%(auto_revoke_t, %) const { return impl::make_event_revoker(this, %(%)); } @@ -1183,9 +1230,6 @@ namespace cppwinrt type_impl_name, bind(generics), method_name, - type_impl_name, - bind(generics), - method_name, bind(signature), method_name, method_name, @@ -1199,22 +1243,13 @@ namespace cppwinrt method_signature signature{ method }; auto async_types_guard = w.push_async_types(signature.is_async()); - // - // Note: this use of a lambda is a workaround for a Visual C++ compiler bug: - // https://developercommunity.visualstudio.com/content/problem/554130/incorrect-code-gen-when-invoking-a-conversion-oper.html - // Once fixed, revert the function body back to this: - // - // return static_cast<% const&>(*this).%(%); - // - - std::string_view format = R"( inline WINRT_IMPL_AUTO(%) %::%(%) const% + std::string_view format = R"( inline auto %::%(%) const% { - return [&](% const& winrt_impl_base) { return winrt_impl_base.%(%); }(*this); + return static_cast<% const&>(*this).%(%); } )"; w.write(format, - signature.return_signature(), class_type.TypeName(), method_name, bind(signature), @@ -1225,15 +1260,13 @@ namespace cppwinrt if (is_add_overload(method)) { - format = R"( inline %::%_revoker %::%(auto_revoke_t, %) const + format = R"( inline auto %::%(auto_revoke_t, %) const { return impl::make_event_revoker(this, %(%)); } )"; w.write(format, - class_type.TypeName(), - method_name, class_type.TypeName(), method_name, bind(signature), @@ -1326,7 +1359,7 @@ namespace cppwinrt w.write(R"( auto data() const { - uint8_t* data{}; + std::uint8_t* data{}; static_cast(*this).template as()->Buffer(&data); return data; } @@ -1337,8 +1370,8 @@ namespace cppwinrt w.write(R"( auto data() const { - uint8_t* data{}; - uint32_t capacity{}; + std::uint8_t* data{}; + std::uint32_t capacity{}; check_hresult(static_cast(*this).template as()->GetBuffer(&data, &capacity)); return data; } @@ -1442,24 +1475,36 @@ namespace cppwinrt else if (type_name == "Windows.Foundation.IAsyncAction") { w.write(R"( auto get() const; + // Synchronously waits without asserting that the calling thread is not an STA. + // Use only when the STA is not presenting UI and blocking is known to be safe. + auto get_unchecked() const; auto wait_for(Windows::Foundation::TimeSpan const& timeout) const; )"); } else if (type_name == "Windows.Foundation.IAsyncOperation`1") { w.write(R"( auto get() const; + // Synchronously waits without asserting that the calling thread is not an STA. + // Use only when the STA is not presenting UI and blocking is known to be safe. + auto get_unchecked() const; auto wait_for(Windows::Foundation::TimeSpan const& timeout) const; )"); } else if (type_name == "Windows.Foundation.IAsyncActionWithProgress`1") { w.write(R"( auto get() const; + // Synchronously waits without asserting that the calling thread is not an STA. + // Use only when the STA is not presenting UI and blocking is known to be safe. + auto get_unchecked() const; auto wait_for(Windows::Foundation::TimeSpan const& timeout) const; )"); } else if (type_name == "Windows.Foundation.IAsyncOperationWithProgress`2") { w.write(R"( auto get() const; + // Synchronously waits without asserting that the calling thread is not an STA. + // Use only when the STA is not presenting UI and blocking is known to be safe. + auto get_unchecked() const; auto wait_for(Windows::Foundation::TimeSpan const& timeout) const; )"); } @@ -1489,7 +1534,7 @@ namespace cppwinrt using iterator_concept = std::input_iterator_tag; using iterator_category = std::input_iterator_tag; using value_type = T; - using difference_type = ptrdiff_t; + using difference_type = std::ptrdiff_t; using pointer = void; using reference = T; )"); @@ -1500,7 +1545,7 @@ namespace cppwinrt using iterator_concept = std::input_iterator_tag; using iterator_category = std::input_iterator_tag; using value_type = Windows::Foundation::IInspectable; - using difference_type = ptrdiff_t; + using difference_type = std::ptrdiff_t; using pointer = void; using reference = Windows::Foundation::IInspectable; )"); @@ -1842,18 +1887,48 @@ namespace cppwinrt { auto param_name = param.Name(); - w.write("\n if (%) *% = detach_abi(winrt_impl_%);", param_name, param_name, param_name); + w.write("\n if (%) *% = detach_abi(winrt_impl_%);", param_name, param_name, param_name); } } } - static void write_produce_method(writer& w, MethodDef const& method) + static void write_produce_upcall_TryLookup(writer& w, std::string_view const& upcall, method_signature const& method_signature) + { + auto name = method_signature.return_param_name(); + + w.write("auto out_param_val = %(%, trylookup_from_abi);", + upcall, + bind(method_signature)); + w.write(R"( + if (out_param_val.has_value()) + { + *% = detach_from<%>(std::move(*out_param_val)); + } + else + { + return impl::error_out_of_bounds; + } +)", + name, method_signature.return_signature()); + + for (auto&& [param, param_signature] : method_signature.params()) + { + if (param.Flags().Out() && !param_signature->Type().is_szarray() && is_object(param_signature->Type())) + { + auto param_name = param.Name(); + + w.write("\n if (%) *% = detach_abi(winrt_impl_%);", param_name, param_name, param_name); + } + } + } + + static void write_produce_method(writer& w, MethodDef const& method, TypeDef const& type) { std::string_view format; if (is_noexcept(method)) { - format = R"( int32_t __stdcall %(%) noexcept final + format = R"( std::int32_t __stdcall %(%) noexcept final { % typename D::abi_guard guard(this->shim()); % @@ -1863,7 +1938,7 @@ namespace cppwinrt } else { - format = R"( int32_t __stdcall %(%) noexcept final try + format = R"( std::int32_t __stdcall %(%) noexcept final try { % typename D::abi_guard guard(this->shim()); % @@ -1876,13 +1951,45 @@ namespace cppwinrt method_signature signature{ method }; auto async_types_guard = w.push_async_types(signature.is_async()); std::string upcall = "this->shim()."; - upcall += get_name(method); + auto name = get_name(method); + upcall += name; - w.write(format, - get_abi_name(method), - bind(signature), - bind(signature), - bind(upcall, signature)); + auto typeName = type.TypeName(); + if (((typeName == "IMapView`2") || (typeName == "IMap`2")) + && (name == "Lookup")) + { + // Special-case IMap*::Lookup to look for a TryLookup here, to avoid extranous throw/originates + std::string tryLookupUpCall = "this->shim().TryLookup"; + format = R"( std::int32_t __stdcall %(%) noexcept final try + { +% typename D::abi_guard guard(this->shim()); + if constexpr (has_TryLookup_v) + { + % + } + else + { + % + } + return 0; + } + catch (...) { return to_hresult(); } +)"; + w.write(format, + get_abi_name(method), + bind(signature), + bind(signature), // clear_abi + bind(tryLookupUpCall, signature), + bind(upcall, signature)); + } + else + { + w.write(format, + get_abi_name(method), + bind(signature), + bind(signature), + bind(upcall, signature)); + } } static void write_fast_produce_methods(writer& w, TypeDef const& default_interface) @@ -1925,7 +2032,7 @@ namespace cppwinrt break; } - w.write_each(info.type.MethodList()); + w.write_each(info.type.MethodList(), info.type); } } @@ -1947,7 +2054,7 @@ namespace cppwinrt bind(generics), type, type, - bind_each(type.MethodList()), + bind_each(type.MethodList(), type), bind(type)); } @@ -1979,7 +2086,7 @@ namespace cppwinrt static void write_dispatch_overridable(writer& w, TypeDef const& class_type) { auto format = R"(template -struct __declspec(empty_bases) produce_dispatch_to_overridable +struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable : produce_dispatch_to_overridable_base { %}; @@ -1999,7 +2106,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable static void write_interface_override_method(writer& w, MethodDef const& method, std::string_view const& interface_name) { - auto format = R"( template WINRT_IMPL_AUTO(%) %T::%(%) const% + auto format = R"( template auto %T::%(%) const% { return shim().template try_as<%>().%(%); } @@ -2009,7 +2116,6 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable auto method_name = get_name(method); w.write(format, - signature.return_signature(), interface_name, method_name, bind(signature), @@ -2029,7 +2135,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable w.write_each(info.type.MethodList(), name); } - }; + } } static void write_class_override_implements(writer& w, get_interfaces_t const& interfaces) @@ -2053,21 +2159,44 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable static void write_class_override_requires(writer& w, get_interfaces_t const& interfaces) { - bool found{}; - for (auto&& [name, info] : interfaces) { - if (!info.overridable) + if (!info.overridable && !info.is_protected) { w.write(", %", name); - found = true; } } } + static void write_class_override_protected_requires(writer& w, get_interfaces_t const& interfaces) + { + bool first = true; + + for (auto&& [name, info] : interfaces) + { + if (info.is_protected) + { + if (first) + { + first = false; + w.write(",\n protected impl::require'); + } + } + static void write_class_override_defaults(writer& w, get_interfaces_t const& interfaces) { - bool first{ true }; + bool first = true; for (auto&& [name, info] : interfaces) { @@ -2096,6 +2225,22 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable } } + static void write_class_override_friends(writer& w, get_interfaces_t const& interfaces) + { + for (auto&& [name, info] : interfaces) + { + if (info.is_protected) + { + w.write("\n friend impl::consume_t;", name); + w.write("\n friend impl::require_one;", name); + } + else if (info.overridable) + { + w.write("\n friend impl::produce;", name); + } + } + } + static void write_call_factory(writer& w, TypeDef const& type, TypeDef const& factory) { std::string factory_name; @@ -2218,13 +2363,13 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable static void write_class_override_usings(writer& w, get_interfaces_t const& required_interfaces) { - std::map> method_usage; + std::map> method_usage; - for (auto&& [interface_name, info] : required_interfaces) + for (auto&& interface_desc : required_interfaces) { - for (auto&& method : info.type.MethodList()) + for (auto&& method : interface_desc.second.type.MethodList()) { - method_usage[get_name(method)].insert(interface_name); + method_usage[get_name(method)].insert(interface_desc); } } @@ -2235,9 +2380,11 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable continue; } - for (auto&& interface_name : interfaces) + for (auto&& [interface_name, info] : interfaces) { - w.write(" using impl::consume_t::%;\n", + w.write(info.overridable + ? " using %T::%;\n" + : " using impl::consume_t::%;\n", interface_name, method_name); } @@ -2266,10 +2413,10 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable auto format = R"( template struct %T : implements, - impl::require, + impl::require%, impl::base% { - using composable = %; + using composable = %;% protected: %% }; )"; @@ -2281,10 +2428,12 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable type_name, bind(interfaces), bind(interfaces), + bind(interfaces), type_name, bind(type), bind(interfaces), type_name, + bind(interfaces), bind(type, factories), bind(interfaces)); } @@ -2349,18 +2498,21 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable for (auto&& [interface_name, info] : get_interfaces(w, type)) { - if (info.defaulted && !info.base) + if (!info.is_protected && !info.overridable) { - for (auto&& method : info.type.MethodList()) + if (info.defaulted && !info.base) { - method_usage[get_name(method)].insert(default_interface_name); + for (auto&& method : info.type.MethodList()) + { + method_usage[get_name(method)].insert(default_interface_name); + } } - } - else - { - for (auto&& method : info.type.MethodList()) + else { - method_usage[get_name(method)].insert(interface_name); + for (auto&& method : info.type.MethodList()) + { + method_usage[get_name(method)].insert(interface_name); + } } } } @@ -2399,7 +2551,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable if (empty(generics)) { - auto format = R"( struct __declspec(empty_bases) % : + auto format = R"( struct WINRT_IMPL_EMPTY_BASES % : winrt::Windows::Foundation::IInspectable, impl::consume_t<%>% { @@ -2422,7 +2574,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable type_name = remove_tick(type_name); auto format = R"( template <%> - struct __declspec(empty_bases) % : + struct WINRT_IMPL_EMPTY_BASES % : winrt::Windows::Foundation::IInspectable, impl::consume_t<%>% {% @@ -2468,7 +2620,9 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable template %(F* function); template %(O* object, M method); template %(com_ptr&& object, M method); - template %(weak_ref&& object, M method); + template %(weak_ref&& object, LM&& lambda_or_method); + template %(std::shared_ptr&& object, M method); + template %(std::weak_ptr&& object, LM&& lambda_or_method); auto operator()(%) const; }; )"; @@ -2485,6 +2639,8 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable type_name, type_name, type_name, + type_name, + type_name, bind(signature)); } @@ -2494,7 +2650,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable { delegate(H&& handler) : implements_delegate<%, H>(std::forward(handler)) {} - int32_t __stdcall Invoke(%) noexcept final try + std::int32_t __stdcall Invoke(%) noexcept final try { % % return 0; @@ -2542,8 +2698,22 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable %([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); }) { } - template <%> template %<%>::%(weak_ref&& object, M method) : - %([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } }) + template <%> template %<%>::%(weak_ref&& object, LM&& lambda_or_method) : + %([o = std::move(object), lm = std::forward(lambda_or_method)](auto&&... args) { if (auto s = o.get()) { + if constexpr (std::is_member_function_pointer_v) ((*s).*(lm))(args...); + else lm(args...); + } }) + { + } + template <%> template %<%>::%(std::shared_ptr&& object, M method) : + %([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); }) + { + } + template <%> template %<%>::%(std::weak_ptr&& object, LM&& lambda_or_method) : + %([o = std::move(object), lm = std::forward(lambda_or_method)](auto&&... args) { if (auto s = o.lock()) { + if constexpr (std::is_member_function_pointer_v) ((*s).*(lm))(args...); + else lm(args...); + } }) { } template <%> auto %<%>::operator()(%) const @@ -2585,11 +2755,21 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable bind(generics), type_name, bind_list(", ", generics), + type_name, + type_name, + bind(generics), + type_name, + bind_list(", ", generics), + type_name, + type_name, + bind(generics), + type_name, + bind_list(", ", generics), bind(signature), bind(signature, true), type_name, bind_list(", ", generics), - bind(signature), + bind(signature, false), bind(signature)); } else @@ -2610,8 +2790,22 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable %([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); }) { } - template %::%(weak_ref&& object, M method) : - %([o = std::move(object), method](auto&&... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } }) + template %::%(weak_ref&& object, LM&& lambda_or_method) : + %([o = std::move(object), lm = std::forward(lambda_or_method)](auto&&... args) { if (auto s = o.get()) { + if constexpr (std::is_member_function_pointer_v) ((*s).*(lm))(args...); + else lm(args...); + } }) + { + } + template %::%(std::shared_ptr&& object, M method) : + %([o = std::move(object), method](auto&&... args) { return ((*o).*(method))(args...); }) + { + } + template %::%(std::weak_ptr&& object, LM&& lambda_or_method) : + %([o = std::move(object), lm = std::forward(lambda_or_method)](auto&&... args) { if (auto s = o.lock()) { + if constexpr (std::is_member_function_pointer_v) ((*s).*(lm))(args...); + else lm(args...); + } }) { } inline auto %::operator()(%) const @@ -2638,24 +2832,30 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable type_name, type_name, type_name, + type_name, + type_name, + type_name, + type_name, + type_name, + type_name, bind(signature), bind(signature, true), type_name, - bind(signature), + bind(signature, false), bind(signature)); } } static void write_struct_field(writer& w, std::pair const& field) { - w.write(" @ %;\n", + w.write(" @ % {};\n", field.second, field.first); } static void write_struct_equality(writer& w, std::vector> const& fields) { - for (size_t i = 0; i != fields.size(); ++i) + for (std::size_t i = 0; i != fields.size(); ++i) { w.write(" left.% == right.%", fields[i].first, fields[i].first); @@ -2731,9 +2931,9 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable return false; }; - for (size_t left = 0; left < structs.size(); ++left) + for (std::size_t left = 0; left < structs.size(); ++left) { - for (size_t right = left + 1; right < structs.size(); ++right) + for (std::size_t right = left + 1; right < structs.size(); ++right) { if (depends(w, structs[left], structs[right])) { @@ -2770,7 +2970,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable for (auto&& field : type.fields) { - if (field.second.find(':') == std::string::npos) + if (field.second.find(':') == std::string::npos || starts_with(field.second, "std::")) { continue; } @@ -2787,11 +2987,11 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable static void write_class_requires(writer& w, TypeDef const& type) { - bool first{ true }; + bool first = true; for (auto&& [interface_name, info] : get_interfaces(w, type)) { - if (!info.defaulted || info.base) + if ((!info.defaulted || info.base) && (!info.is_protected && !info.overridable)) { if (first) { @@ -2811,7 +3011,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable static void write_fast_class_requires(writer& w, TypeDef const& type) { - bool first{ true }; + bool first = true; for (auto&& [interface_name, info] : get_interfaces(w, type)) { @@ -2835,7 +3035,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable static void write_class_base(writer& w, TypeDef const& type) { - bool first{ true }; + bool first = true; for (auto&& base : get_bases(type)) { @@ -3004,13 +3204,15 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable return; } + auto is_opt_type = settings.component_opt && settings.component_filter.includes(type); + for (auto&& method : factory.second.type.MethodList()) { method_signature signature{ method }; auto method_name = get_name(method); auto async_types_guard = w.push_async_types(signature.is_async()); - if (settings.component_opt && settings.component_filter.includes(type)) + if (is_opt_type) { w.write(" %static % %(%);\n", is_get_overload(method) ? "[[nodiscard]] " : "", @@ -3028,18 +3230,33 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable if (is_add_overload(method)) { - auto format = R"( using %_revoker = impl::factory_event_revoker<%, &impl::abi_t<%>::remove_%>; - [[nodiscard]] static %_revoker %(auto_revoke_t, %); + { + auto format = R"( using %_revoker = impl::factory_event_revoker<%, &impl::abi_t<%>::remove_%>; )"; + w.write(format, + method_name, + factory.second.type, + factory.second.type, + method_name); + } - w.write(format, - method_name, - factory.second.type, - factory.second.type, - method_name, - method_name, - method_name, - bind(signature)); + if (is_opt_type) + { + auto format = R"( [[nodiscard]] static %_revoker %(auto_revoke_t, %); +)"; + w.write(format, + method_name, + method_name, + bind(signature)); + } + else + { + auto format = R"( [[nodiscard]] static auto %(auto_revoke_t, %); +)"; + w.write(format, + method_name, + bind(signature)); + } } } } @@ -3068,21 +3285,21 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable if (is_add_overload(method)) { - auto format = R"( inline %::%_revoker %::%(auto_revoke_t, %) + auto format = R"( inline auto %::%(auto_revoke_t, %) { auto f = get_activation_factory<%, %>(); - return { f, f.%(%) }; + return %::%_revoker{ f, f.%(%) }; } )"; w.write(format, - type_name, - method_name, type_name, method_name, bind(signature), type_name, factory, + type_name, + method_name, method_name, bind(signature)); } @@ -3151,7 +3368,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable auto type_name = type.TypeName(); auto factories = get_factories(w, type); - auto format = R"( struct __declspec(empty_bases) % : %%% + auto format = R"( struct WINRT_IMPL_EMPTY_BASES % : %%% { %(std::nullptr_t) noexcept {} %(void* ptr, take_ownership_from_abi_t) noexcept : %(ptr, take_ownership_from_abi) {} @@ -3176,7 +3393,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable auto type_name = type.TypeName(); auto factories = get_factories(w, type); - auto format = R"( struct __declspec(empty_bases) % : %% + auto format = R"( struct WINRT_IMPL_EMPTY_BASES % : %% { %(std::nullptr_t) noexcept {} %(void* ptr, take_ownership_from_abi_t) noexcept : %(ptr, take_ownership_from_abi) {} @@ -3259,7 +3476,9 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable w.write(strings::base_reference_produce); w.write(strings::base_deferral); w.write(strings::base_coroutine_foundation); + w.write(strings::base_stringable_to_hstring); w.write(strings::base_stringable_format); + w.write(strings::base_stringable_streams); } else if (namespace_name == "Windows.Foundation.Collections") { @@ -3277,10 +3496,6 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable { w.write(strings::base_coroutine_system); } - else if (namespace_name == "Microsoft.System") - { - w.write(strings::base_coroutine_system_winui); - } else if (namespace_name == "Windows.UI.Core") { w.write(strings::base_coroutine_ui_core); @@ -3289,6 +3504,14 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable { w.write(strings::base_xaml_typename); } + else if (namespace_name == "Windows.UI.Xaml.Markup") + { + w.write(strings::base_xaml_component_connector); + } + else if (namespace_name == "Microsoft.UI.Xaml.Markup") + { + w.write(strings::base_xaml_component_connector_winui); + } } static void write_namespace_special_1(writer& w, std::string_view const& namespace_name) diff --git a/cppwinrt/component_writers.h b/cppwinrt/component_writers.h index f562dabef..94e20e53e 100644 --- a/cppwinrt/component_writers.h +++ b/cppwinrt/component_writers.h @@ -27,7 +27,7 @@ namespace cppwinrt } } - bool first{ true }; + bool first = true; for (auto&& name : interfaces) { @@ -45,7 +45,7 @@ namespace cppwinrt static void write_component_class_base(writer& w, TypeDef const& type) { - bool first{ true }; + bool first = true; for (auto&& base : get_bases(type)) { @@ -136,7 +136,10 @@ namespace cppwinrt static void write_module_g_cpp(writer& w, std::vector const& classes) { - w.write_root_include("base"); + if (!settings.modules) + { + w.write_root_include("base"); + } auto format = R"(% bool __stdcall %_can_unload_now() noexcept { @@ -172,9 +175,12 @@ void* __stdcall %_get_activation_factory([[maybe_unused]] std::wstring_view cons } format = R"( -int32_t __stdcall WINRT_CanUnloadNow() noexcept +std::int32_t __stdcall WINRT_CanUnloadNow() noexcept { #ifdef _WRL_MODULE_H_ +#ifdef _MSC_VER +#pragma warning(suppress: 4324) // structure was padded due to alignment specifier +#endif if (!::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().Terminate()) { return 1; @@ -184,7 +190,7 @@ int32_t __stdcall WINRT_CanUnloadNow() noexcept return %_can_unload_now() ? 0 : 1; } -int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept try +std::int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept try { std::wstring_view const name{ *reinterpret_cast(&classId) }; *factory = %_get_activation_factory(name); @@ -195,6 +201,7 @@ int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noex } #ifdef _WRL_MODULE_H_ +#pragma warning(suppress: 4324) // structure was padded due to alignment specifier return ::Microsoft::WRL::Module<::Microsoft::WRL::InProc>::GetModule().GetActivationFactory(static_cast(classId), reinterpret_cast<::IActivationFactory**>(factory)); #else return winrt::hresult_class_not_available(name).to_abi(); @@ -289,7 +296,7 @@ catch (...) { return winrt::to_hresult(); } bind(signature)); } - void write_component_static_forwarder(writer& w, MethodDef const& method) + static void write_component_static_forwarder(writer& w, MethodDef const& method) { auto format = R"( auto %(%) { @@ -393,7 +400,7 @@ catch (...) { return winrt::to_hresult(); } return; } - auto wrap_type = wrap_type_namespace(w, type_namespace); + auto wrap_type = wrap_type_namespace_without_export(w, type_namespace); for (auto&&[factory_name, factory] : get_factories(w, type)) { @@ -521,7 +528,7 @@ catch (...) { return winrt::to_hresult(); } auto format = R"( %::%_revoker %::%(auto_revoke_t, %) { auto f = make().as<%>(); - return { f, f.%(%) }; + return %::%_revoker{ f, f.%(%) }; } )"; @@ -534,6 +541,8 @@ catch (...) { return winrt::to_hresult(); } type_namespace, type_name, factory_name, + type_name, + method_name, method_name, bind(signature)); } @@ -634,15 +643,15 @@ catch (...) { return winrt::to_hresult(); } } )"; - size_t offset = get_bases(type).size(); + std::size_t offset = get_bases(type).size(); auto interfaces = get_interfaces(w, type); for (auto&& [name, info] : interfaces) { if (!info.base && info.is_default) { - auto methods = info.type.MethodList(); - offset += methods.second - methods.first; + auto [first, second] = info.type.MethodList(); + offset += second - first; break; } } @@ -679,7 +688,7 @@ catch (...) { return winrt::to_hresult(); } if (has_base) { auto format = R"( - int32_t query_interface_tearoff(guid const& id, void** result) const noexcept override + std::int32_t query_interface_tearoff(guid const& id, void** result) const noexcept override {% return B::query_interface_tearoff(id, result); } @@ -695,7 +704,7 @@ catch (...) { return winrt::to_hresult(); } } auto format = R"( - int32_t query_interface_tearoff(guid const& id, void** result) const noexcept override + std::int32_t query_interface_tearoff(guid const& id, void** result) const noexcept override {% return impl::error_no_interface; } @@ -741,14 +750,14 @@ catch (...) { return winrt::to_hresult(); } auto format = R"(namespace winrt::@::implementation { template - struct __declspec(empty_bases) %_base : implements%%% + struct WINRT_IMPL_EMPTY_BASES %_base : implements%%%% { using base_type = %_base; using class_type = @::%; using implements_type = typename %_base::implements_type; using implements_type::implements_type; - % - hstring GetRuntimeClassName() const + %% + hstring GetRuntimeClassName() const override { return L"%.%"; } @@ -762,6 +771,8 @@ catch (...) { return winrt::to_hresult(); } std::string base_type_argument; std::string no_module_lock; std::string external_requires; + std::string external_protected_requires; + std::string friends; if (base_type) { @@ -771,8 +782,10 @@ catch (...) { return winrt::to_hresult(); } { composable_base_name = w.write_temp("using composable_base = %;", base_type); auto base_interfaces = get_interfaces(w, base_type); - uint32_t base_interfaces_count{}; + std::uint32_t base_interfaces_count{}; + std::uint32_t protected_base_interfaces_count{}; external_requires = ",\n impl::require(type), bind(type), type_name, @@ -820,6 +860,7 @@ catch (...) { return winrt::to_hresult(); } type_name, type_name, composable_base_name, + friends, type_namespace, type_name, bind(type), @@ -833,7 +874,7 @@ catch (...) { return winrt::to_hresult(); } auto format = R"(namespace winrt::@::factory_implementation { template - struct __declspec(empty_bases) %T : implements + struct WINRT_IMPL_EMPTY_BASES %T : implements { using instance_type = @::%; @@ -860,7 +901,9 @@ catch (...) { return winrt::to_hresult(); } { auto format = R"( #if defined(WINRT_FORCE_INCLUDE_%_XAML_G_H) || __has_include("%.xaml.g.h") + #include "%.xaml.g.h" + #else namespace winrt::@::implementation @@ -873,7 +916,7 @@ namespace winrt::@::implementation )"; std::string upper(type_name); - std::transform(upper.begin(), upper.end(), upper.begin(), [](char c) {return static_cast(::toupper(c)); }); + std::transform(upper.begin(), upper.end(), upper.begin(), [](char c) {return static_cast(std::toupper(c)); }); auto include_path = get_generated_component_filename(type); @@ -1200,7 +1243,7 @@ namespace winrt::@::implementation static void write_component_fast_abi_thunk(writer& w) { - for (uint32_t slot = 6; slot < 1024; ++slot) + for (std::uint32_t slot = 6; slot < 1024; ++slot) { auto format = R"( extern "C" void __stdcall winrt_ff_thunk%(); )"; @@ -1211,7 +1254,7 @@ namespace winrt::@::implementation static void write_component_fast_abi_vtable(writer& w) { - for (uint32_t slot = 6; slot < 1024; ++slot) + for (std::uint32_t slot = 6; slot < 1024; ++slot) { auto format = R"( #if WINRT_FAST_ABI_SIZE > % diff --git a/cppwinrt/cppwinrt.vcxproj b/cppwinrt/cppwinrt.vcxproj index 653480c81..b8beed890 100644 --- a/cppwinrt/cppwinrt.vcxproj +++ b/cppwinrt/cppwinrt.vcxproj @@ -2,10 +2,6 @@ - - Debug - ARM - Debug ARM64 @@ -14,10 +10,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -54,9 +46,9 @@ + - @@ -80,6 +72,8 @@ + + @@ -88,6 +82,8 @@ + + @@ -122,17 +118,12 @@ 15.0 {D613FB39-5035-4043-91E2-BAB323908AF4} cppwinrt - 10.0 - + Application true - - Application - true - Application true @@ -142,11 +133,6 @@ false true - - Application - false - true - Application false @@ -169,18 +155,12 @@ - - - - - - @@ -191,42 +171,13 @@ - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - Disabled ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreadedDebug - - - Console - - - $(OutputPath)prebuild.exe ..\strings $(OutputPath) - - - - - - - - - Disabled - ..\inc;$(OutputPath);$(WinMDPackageDir); - MultiThreadedDebug + Level4 + true Console @@ -244,12 +195,14 @@ Disabled ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreadedDebug + Level4 + true Console - $(OutputPath)prebuild.exe ..\strings $(OutputPath) + $(CppWinRTDir)prebuild.exe ..\strings $(OutputPath) @@ -261,6 +214,8 @@ Disabled ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreadedDebug + Level4 + true Console @@ -272,9 +227,6 @@ - - app.manifest;%(AdditionalManifestFiles) - @@ -283,28 +235,9 @@ true ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreaded - - - Console - true - true - /DEBUGTYPE:CV,FIXUP %(AdditionalOptions) - - - $(OutputPath)prebuild.exe ..\strings $(OutputPath) - - - - - - - - - MaxSpeed - true - true - ..\inc;$(OutputPath);$(WinMDPackageDir); - MultiThreaded + Guard + Level4 + true Console @@ -327,6 +260,9 @@ true ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreaded + Guard + Level4 + true Console @@ -335,7 +271,7 @@ /DEBUGTYPE:CV,FIXUP %(AdditionalOptions) - $(OutputPath)prebuild.exe ..\strings $(OutputPath) + $(CppWinRTDir)prebuild.exe ..\strings $(OutputPath) @@ -349,6 +285,9 @@ true ..\inc;$(OutputPath);$(WinMDPackageDir); MultiThreaded + Guard + Level4 + true Console diff --git a/cppwinrt/cppwinrt.vcxproj.filters b/cppwinrt/cppwinrt.vcxproj.filters index dfe1488ee..96129ab20 100644 --- a/cppwinrt/cppwinrt.vcxproj.filters +++ b/cppwinrt/cppwinrt.vcxproj.filters @@ -64,9 +64,6 @@ strings - - strings - strings @@ -163,9 +160,6 @@ strings - - strings - strings @@ -175,6 +169,24 @@ strings + + strings + + + strings + + + strings + + + strings + + + strings + + + strings + diff --git a/cppwinrt/file_writers.h b/cppwinrt/file_writers.h index 5168d8d7f..fd9833cb1 100644 --- a/cppwinrt/file_writers.h +++ b/cppwinrt/file_writers.h @@ -9,9 +9,16 @@ namespace cppwinrt w.write(strings::base_version_odr, CPPWINRT_VERSION_STRING); { auto wrap_file_guard = wrap_open_file_guard(w, "BASE"); + auto wrap_import = wrap_ifndef(w, "WINRT_IMPORT_MODULE"); - w.write(strings::base_includes); - w.write(strings::base_macros); + { + auto wrap_includes = wrap_module_aware_includes_guard(w, true); + w.write(strings::base_includes); + w.write(strings::base_detect_numerics); + w.write(strings::base_include_numerics); + } + w.write_root_include("base_macros"); + w.write(strings::base_source_location); w.write(strings::base_types); w.write(strings::base_extern); w.write(strings::base_meta); @@ -65,7 +72,15 @@ namespace cppwinrt w.flush_to_file(settings.output_folder + "winrt/fast_forward.h"); } - static void write_namespace_0_h(std::string_view const& ns, cache::namespace_members const& members) + static void collect_writer_deps(writer const& w, std::set& out) + { + for (auto&& [dep_ns, _] : w.depends) + { + out.insert(std::string(dep_ns)); + } + } + + static void write_namespace_0_h(std::string_view const& ns, cache::namespace_members const& members, std::set* out_deps = nullptr) { writer w; w.type_namespace = ns; @@ -77,6 +92,7 @@ namespace cppwinrt w.write_each(members.classes); w.write_each(members.structs); w.write_each(members.delegates); + w.write_each(members.contracts); } { auto wrap_impl = wrap_impl_namespace(w); @@ -89,11 +105,13 @@ namespace cppwinrt // Class names are always required for activation. // Class, enum, and struct names are required for producing GUIDs for generic types. // Interface and delegates names are required for Xaml compatibility. + // Contract names are used by IsApiContractPresent. w.write_each(members.classes); w.write_each(members.enums); w.write_each(members.structs); w.write_each(members.interfaces); w.write_each(members.delegates); + w.write_each(members.contracts); w.write_each(members.interfaces); w.write_each(members.delegates); @@ -115,10 +133,11 @@ namespace cppwinrt w.write_each(depends.second); } + if (out_deps) collect_writer_deps(w, *out_deps); w.save_header('0'); } - static void write_namespace_1_h(std::string_view const& ns, cache::namespace_members const& members) + static void write_namespace_1_h(std::string_view const& ns, cache::namespace_members const& members, std::set* out_deps = nullptr) { writer w; w.type_namespace = ns; @@ -134,16 +153,20 @@ namespace cppwinrt write_preamble(w); write_open_file_guard(w, ns, '1'); - for (auto&& depends : w.depends) { - w.write_depends(depends.first, '0'); - } + auto wrap_includes = wrap_module_aware_includes_guard(w, true); + for (auto&& depends : w.depends) + { + w.write_depends(depends.first, '0'); + } - w.write_depends(w.type_namespace, '0'); + w.write_depends(w.type_namespace, '0'); + } + if (out_deps) collect_writer_deps(w, *out_deps); w.save_header('1'); } - static void write_namespace_2_h(std::string_view const& ns, cache::namespace_members const& members) + static void write_namespace_2_h(std::string_view const& ns, cache::namespace_members const& members, std::set* out_deps = nullptr) { writer w; w.type_namespace = ns; @@ -164,16 +187,20 @@ namespace cppwinrt char const impl = promote ? '2' : '1'; - for (auto&& depends : w.depends) { - w.write_depends(depends.first, impl); - } + auto wrap_includes = wrap_module_aware_includes_guard(w, true); + for (auto&& depends : w.depends) + { + w.write_depends(depends.first, impl); + } - w.write_depends(w.type_namespace, '1'); + w.write_depends(w.type_namespace, '1'); + } + if (out_deps) collect_writer_deps(w, *out_deps); w.save_header('2'); } - static void write_namespace_h(cache const& c, std::string_view const& ns, cache::namespace_members const& members) + static void write_namespace_h(cache const& c, std::string_view const& ns, cache::namespace_members const& members, std::set* out_deps = nullptr) { writer w; w.type_namespace = ns; @@ -213,18 +240,28 @@ namespace cppwinrt write_namespace_special(w, ns); write_close_file_guard(w); + // The #ifndef WINRT_IMPORT_MODULE / #endif pair spans across w.swap(). + // The body is written first (above), then swap() prepends the header prefix (below). + // In the final output, #ifndef opens before the includes and #endif closes after + // the file guard, mirroring the write_open_file_guard / write_close_file_guard pair. + w.write("#endif // WINRT_IMPORT_MODULE\n"); w.swap(); write_preamble(w); write_open_file_guard(w, ns); - write_version_assert(w); - write_parent_depends(w, c, ns); - - for (auto&& depends : w.depends) + w.write("#ifndef WINRT_IMPORT_MODULE\n\n"); { - w.write_depends(depends.first, '2'); - } + auto wrap_includes = wrap_module_aware_includes_guard(w, true); + write_version_assert(w); + write_parent_depends(w, c, ns); - w.write_depends(w.type_namespace, '2'); + for (auto&& depends : w.depends) + { + w.write_depends(depends.first, '2'); + } + + w.write_depends(w.type_namespace, '2'); + } + if (out_deps) collect_writer_deps(w, *out_deps); w.save_header(); } @@ -233,6 +270,28 @@ namespace cppwinrt writer w; write_preamble(w); write_pch(w); + + if (settings.modules) + { + // In module builds, import std and winrt_base instead of #include "winrt/base.h". + // std is needed for std::wstring_view, std::equal, std::int32_t used in + // the activation factory lookup code. + w.write("\nimport std;\n"); + w.write("import winrt_base;\n"); + + // Collect all unique namespaces from the component classes + std::set namespaces; + for (auto&& type : classes) + { + namespaces.insert(std::string(type.TypeNamespace())); + } + for (auto&& ns : namespaces) + { + w.write("import winrt.%;\n", ns); + } + w.write("\n"); + } + write_module_g_cpp(w, classes); w.flush_to_file(settings.output_folder + "module.g.cpp"); } @@ -247,9 +306,19 @@ namespace cppwinrt write_preamble(w); write_include_guard(w); - for (auto&& depends : w.depends) { - w.write_depends(depends.first); + auto wrap = wrap_ifdef(w, "WINRT_IMPORT_MODULE"); + w.write_root_include("base_macros"); + for (auto&& depends : w.depends) + { + w.write("import winrt.%;\n", depends.first); + } + w.write("#else // WINRT_IMPORT_MODULE\n"); + + for (auto&& depends : w.depends) + { + w.write_depends(depends.first); + } } auto filename = settings.output_folder + get_generated_component_filename(type) + ".g.h"; @@ -313,7 +382,269 @@ namespace cppwinrt writer w; write_pch(w); + + if (settings.modules) + { + // The .g.h handles its own imports, but the implementation .h + // needs the types available in scope, so we import them here. + writer dep_scanner; + dep_scanner.add_depends(type); + write_component_g_h(dep_scanner, type); + + w.write("\n#define WINRT_IMPORT_MODULE\n"); + for (auto&& depends : dep_scanner.depends) + { + w.write("import winrt.%;\n", depends.first); + } + w.write("\n"); + } + write_component_cpp(w, type); w.flush_to_file(path); } + + // --- Per-namespace C++20 module interface unit (.ixx) writers --- + + // Emits the common global module fragment used by all generated .ixx files. + // Defines WINRT_IMPL_BUILD_MODULE so generated headers switch WINRT_EXPORT + // to 'export extern "C++"' and suppress textual #includes of dependencies + // (dependencies arrive via module imports instead). + // Includes minimal headers needed for macros, intrinsics, and debug assertions. + static void write_module_preamble(writer& w) + { + write_preamble(w); + w.write(strings::base_module_ixx_preamble); + w.write_root_include("base_macros"); + } + + // Emits $(out)/winrt/base_macros.h + // This header provides the core macros shared between header and module builds. + // In header builds, base.h includes base_macros.h inline (via the prebuild-embedded string). + // In module builds, each .ixx file includes this in its global module fragment. + static void write_macros_h() + { + writer w; + write_preamble(w); + w.write(strings::base_macros, CPPWINRT_VERSION_STRING); + w.flush_to_file(settings.output_folder + "winrt/base_macros.h"); + } + + static void write_base_ixx() + { + writer w; + write_module_preamble(w); + w.write(strings::base_module_base_ixx); + w.write(strings::base_detect_numerics); + w.write("\n"); + w.write_root_include("base"); + w.flush_to_file(settings.output_folder + "winrt/winrt_base.ixx"); + } + + static void write_numerics_ixx() + { + writer w; + write_module_preamble(w); + // GMF: detect numerics and pre-include directxmath so it's not pulled + // into the module purview by windowsnumerics.impl.h + w.write(strings::base_detect_numerics); + { + auto wrap = wrap_ifdef(w, "WINRT_IMPL_NUMERICS"); + w.write("#include \n"); + } + w.write(strings::base_module_numerics_ixx); + // Module declaration + w.write("\nexport module winrt_numerics;\n"); + // Include windowsnumerics.impl.h in the module purview (exports the types). + // directxmath.h is already included in the GMF above, so the #include inside + // base_include_numerics is a no-op (header guard). + { + auto wrap = wrap_ifdef(w, "_MSC_VER"); + w.write("#pragma warning(push)\n"); + w.write("#pragma warning(disable : 5244)\n"); + } + w.write(strings::base_include_numerics); + { + auto wrap = wrap_ifdef(w, "_MSC_VER"); + w.write("#pragma warning(pop)\n"); + } + w.flush_to_file(settings.output_folder + "winrt/winrt_numerics.ixx"); + } + + // Emits a per-namespace module interface unit for namespaces that are NOT + // part of a dependency cycle (standalone module). + // Output: $(out)/winrt/winrt..ixx (export module winrt.;) + // + // The generated .ixx: + // 1. Starts with the global module fragment (WINRT_IMPL_BUILD_MODULE, minimal includes) + // 2. Declares 'export module winrt.;' + // 3. Imports std and re-exports winrt_base + // 4. Imports each dependent namespace module (computed from type references in headers) + // 5. Includes the impl headers (*.0.h, *.1.h, *.2.h) and public header (.h) + // in the module purview, where WINRT_EXPORT causes declarations to be exported + static void write_namespace_ixx( + std::string_view const& ns, + std::set const& deps) + { + writer w; + write_module_preamble(w); + + // Module declaration + w.write("export module winrt.%;\n\n", ns); + + // Document dependencies + w.write("// Module dependencies:\n"); + w.write("// - std\n"); + w.write("// - winrt_base (re-exported)\n"); + if (deps.empty()) + { + w.write("// - (no additional namespace imports)\n"); + } + else + { + for (auto& dep : deps) + { + w.write("// - winrt.%\n", dep); + } + } + w.write("\n"); + + // Import std and base + w.write("import std;\n"); + w.write("export import winrt_base;\n"); + + // Import dependency namespace modules + for (auto& dep : deps) + { + w.write("import winrt.%;\n", dep); + } + + // Version mismatch check: ensure this namespace module was generated by the + // same version of cppwinrt.exe as the winrt_base module it imports. + // winrt::cppwinrt_version is exported from winrt_base; CPPWINRT_VERSION is + // the macro from this module's own base_macros.h in the global module fragment. + w.write("\nstatic_assert(winrt::check_version(winrt::cppwinrt_version, CPPWINRT_VERSION), \"Mismatched C++/WinRT headers.\");\n\n"); + + // Include namespace headers in module purview + w.write_depends(ns, '0'); + w.write_depends(ns, '1'); + w.write_depends(ns, '2'); + w.write_root_include(ns); + + w.flush_to_file(settings.output_folder + "winrt/winrt." + std::string(ns) + ".ixx"); + } + + // Emits the SCC (Strongly Connected Component) owner module interface unit. + // When multiple namespaces form a dependency cycle, they cannot each have their + // own independent module (circular imports are illegal in C++20 modules). + // Instead, one namespace is chosen as the "owner" (alphabetically first in the SCC), + // and ALL cyclic namespaces' declarations are consolidated into this single module. + // The other namespaces in the SCC get thin re-export stubs (see write_namespace_reexport_ixx). + // + // Output: $(out)/winrt/winrt..ixx (export module winrt.;) + // + // The owner module: + // 1. Imports external dependencies (deps outside the SCC) + // 2. Forward-declares all projected types for ALL SCC namespaces before any + // impl headers — this breaks the type reference cycles + // 3. Includes impl headers in stable phase order: all *.0.h, then all *.1.h, + // then all *.2.h, then all public headers — preserving the original header + // layering while keeping SCC compilation deterministic + static void write_namespace_scc_owner_ixx( + cache const& c, + std::string_view const& owner, + std::vector const& scc_members, + std::set const& external_deps) + { + writer w; + write_module_preamble(w); + + // Module declaration (owner namespace) + w.write("// This module is an SCC owner (cycle breaker). The following namespaces\n"); + w.write("// form a dependency cycle and are consolidated into this single module:\n"); + for (auto& ns : scc_members) + { + w.write("// - %\n", ns); + } + w.write("// Other SCC namespaces are emitted as re-export stubs.\n\n"); + w.write("export module winrt.%;\n\n", owner); + + // Import std and base + w.write("import std;\n"); + w.write("export import winrt_base;\n"); + + // Import external dependency modules (outside the SCC) + for (auto& dep : external_deps) + { + w.write("import winrt.%;\n", dep); + } + + // Version mismatch check: ensure this namespace module was generated by the + // same version of cppwinrt.exe as the winrt_base module it imports. + // winrt::cppwinrt_version is exported from winrt_base; CPPWINRT_VERSION is + // the macro from this module's own base_macros.h in the global module fragment. + w.write("\nstatic_assert(winrt::check_version(winrt::cppwinrt_version, CPPWINRT_VERSION), \"Mismatched C++/WinRT headers.\");\n"); + + // Forward declarations for all projected types in this SCC. + // This is required because SCC members have cyclic type references, + // and generated headers suppress dependent #includes when WINRT_IMPL_BUILD_MODULE + // is defined. Forward declarations provide the names needed before definitions. + for (auto& ns : scc_members) + { + auto found = c.namespaces().find(ns); + if (found == c.namespaces().end()) + { + continue; + } + auto& members = found->second; + + auto wrap_type = wrap_type_namespace(w, ns); + w.write_each(members.enums); + w.write_each(members.interfaces); + w.write_each(members.classes); + w.write_each(members.structs); + w.write_each(members.delegates); + w.write_each(members.contracts); + } + + // Include all SCC members' headers in stable phase order. + // All *.0.h (forward decls + ABIs), then all *.1.h (interfaces), + // then all *.2.h (delegates/structs/classes), then all public headers. + // This preserves the original header layering while keeping compilation deterministic. + for (auto& ns : scc_members) + { + w.write_depends(ns, '0'); + } + for (auto& ns : scc_members) + { + w.write_depends(ns, '1'); + } + for (auto& ns : scc_members) + { + w.write_depends(ns, '2'); + } + for (auto& ns : scc_members) + { + w.write_root_include(ns); + } + + w.flush_to_file(settings.output_folder + "winrt/winrt." + std::string(owner) + ".ixx"); + } + + // Emits a thin re-export stub module for SCC non-owner namespaces. + // This allows 'import winrt.;' to work even though the actual declarations + // live in the SCC owner module. The stub simply re-exports the owner. + // Output: $(out)/winrt/winrt..ixx (export module winrt.; export import winrt.;) + static void write_namespace_reexport_ixx( + std::string_view const& ns, + std::string_view const& owner) + { + writer w; + write_preamble(w); + w.write("\n// NOTE: This module does not define declarations of its own.\n"); + w.write("// It re-exports all declarations from the 'winrt.%' module. This is used to break cycles in the\n", owner); + w.write("// WinRT namespace module dependency graph (SCC owner consolidation).\n\n"); + w.write("export module winrt.%;\n", ns); + w.write("export import winrt.%;\n", owner); + w.flush_to_file(settings.output_folder + "winrt/winrt." + std::string(ns) + ".ixx"); + } } diff --git a/cppwinrt/helpers.h b/cppwinrt/helpers.h index 22854c48e..2dc152a74 100644 --- a/cppwinrt/helpers.h +++ b/cppwinrt/helpers.h @@ -31,7 +31,7 @@ namespace cppwinrt ++params.first; } - for (uint32_t i{}; i != size(m_signature.Params()); ++i) + for (std::uint32_t i{}; i != size(m_signature.Params()); ++i) { m_params.emplace_back(params.first + i, &m_signature.Params().first[i]); } @@ -80,7 +80,7 @@ namespace cppwinrt // by the caller and callee. The exception to this rule is property setters where the callee may simply store a // reference to the collection. The collection thus becomes async in the sense that it is expected to remain // valid beyond the duration of the call. - + if (is_put_overload(m_method)) { return true; @@ -127,7 +127,7 @@ namespace cppwinrt struct separator { writer& w; - bool first{ true }; + bool first = true; void operator()() { @@ -148,10 +148,54 @@ namespace cppwinrt return static_cast(get_attribute(row, type_namespace, type_name)); } + namespace impl + { + template + struct variant_index; + + template + struct variant_index + { + static constexpr bool found = std::is_same_v; + static constexpr std::size_t value = std::conditional_t, + variant_index>::value + (found ? 0 : 1); + }; + } + + template + struct variant_index; + + template + struct variant_index, T> : impl::variant_index + { + }; + + template + constexpr std::size_t variant_index_v = variant_index::value; + template - auto get_attribute_value(CustomAttribute const& attribute, uint32_t const arg) + auto get_integer_attribute(FixedArgSig const& signature) { - return std::get(std::get(attribute.Value().FixedArgs()[arg].value).value); + auto variant = std::get(signature.value).value; + switch (variant.index()) + { + case variant_index_v>: return static_cast(std::get>(variant)); + case variant_index_v>: return static_cast(std::get>(variant)); + default: return std::get(variant); // Likely throws, but that's intentional + } + } + + template + auto get_attribute_value(FixedArgSig const& signature) + { + return std::get(std::get(signature.value).value); + } + + template + auto get_attribute_value(CustomAttribute const& attribute, std::uint32_t const arg) + { + return get_attribute_value(attribute.Value().FixedArgs()[arg]); } static auto get_abi_name(MethodDef const& method) @@ -283,45 +327,217 @@ namespace cppwinrt return bases; } - static std::pair get_version(TypeDef const& type) + struct contract_version + { + std::string_view name; + std::uint32_t version; + }; + + struct previous_contract + { + std::string_view contract_from; + std::string_view contract_to; + std::uint32_t version_low; + std::uint32_t version_high; + }; + + struct contract_history + { + contract_version current_contract; + + // Sorted such that the first entry is the first contract the type was introduced in + std::vector previous_contracts; + }; + + static contract_version decode_contract_version_attribute(CustomAttribute const& attribute) + { + // ContractVersionAttribute has three constructors, but only two we care about here: + // .ctor(string contract, uint32 version) + // .ctor(System.Type contract, uint32 version) + auto signature = attribute.Value(); + auto& args = signature.FixedArgs(); + assert(args.size() == 2); + + contract_version result{}; + result.version = get_integer_attribute(args[1]); + call(std::get(args[0].value).value, + [&](ElemSig::SystemType t) + { + result.name = t.name; + }, + [&](std::string_view name) + { + result.name = name; + }, + [](auto&&) + { + assert(false); + }); + + return result; + } + + static previous_contract decode_previous_contract_attribute(CustomAttribute const& attribute) { - uint32_t version{}; + // PreviousContractVersionAttribute has two constructors: + // .ctor(string fromContract, uint32 versionLow, uint32 versionHigh) + // .ctor(string fromContract, uint32 versionLow, uint32 versionHigh, string contractTo) + auto signature = attribute.Value(); + auto& args = signature.FixedArgs(); + assert(args.size() >= 3); + + previous_contract result{}; + result.contract_from = get_attribute_value(args[0]); + result.version_low = get_integer_attribute(args[1]); + result.version_high = get_integer_attribute(args[2]); + if (args.size() == 4) + { + result.contract_to = get_attribute_value(args[3]); + } + + return result; + } + static contract_version get_initial_contract_version(TypeDef const& type) + { + // Most types don't have previous contracts, so optimize for that scenario to avoid unnecessary allocations + contract_version current_contract{}; + + // The initial contract, assuming the type has moved contracts, is the only contract name that doesn't appear as + // a "to contract" argument to a PreviousContractVersionAttribute. Note that this assumes that a type does not + // "return" to a prior contract, however this is a restriction enforced by midlrt + std::vector previous_contracts; + std::vector to_contracts; for (auto&& attribute : type.CustomAttribute()) { - auto name = attribute.TypeNamespaceAndName(); + auto [ns, name] = attribute.TypeNamespaceAndName(); + if (ns != "Windows.Foundation.Metadata") + { + continue; + } - if (name.first != "Windows.Foundation.Metadata") + if (name == "ContractVersionAttribute") + { + assert(current_contract.name.empty()); + current_contract = decode_contract_version_attribute(attribute); + } + else if (name == "PreviousContractVersionAttribute") + { + auto prev = decode_previous_contract_attribute(attribute); + + // If this contract was the target of an earlier contract change, we know this isn't the initial one + if (std::find(to_contracts.begin(), to_contracts.end(), prev.contract_from) == to_contracts.end()) + { + previous_contracts.push_back(contract_version{ prev.contract_from, prev.version_low }); + } + + if (!prev.contract_to.empty()) + { + auto itr = std::find_if(previous_contracts.begin(), previous_contracts.end(), [&](auto const& ver) + { + return ver.name == prev.contract_to; + }); + if (itr != previous_contracts.end()) + { + *itr = previous_contracts.back(); + previous_contracts.pop_back(); + } + + to_contracts.push_back(prev.contract_to); + } + } + else if (name == "VersionAttribute") + { + // Prefer contract versioning, if present. Otherwise, use an empty contract name to indicate that this + // is not a contract version + if (current_contract.name.empty()) + { + current_contract.version = get_attribute_value(attribute, 0); + } + } + } + + if (!previous_contracts.empty()) + { + assert(previous_contracts.size() == 1); + return previous_contracts[0]; + } + + return current_contract; + } + + static contract_history get_contract_history(TypeDef const& type) + { + contract_history result{}; + for (auto&& attribute : type.CustomAttribute()) + { + auto [ns, name] = attribute.TypeNamespaceAndName(); + if (ns != "Windows.Foundation.Metadata") { continue; } - if (name.second == "ContractVersionAttribute") + if (name == "ContractVersionAttribute") { - version = get_attribute_value(attribute, 1); - break; + assert(result.current_contract.name.empty()); + result.current_contract = decode_contract_version_attribute(attribute); } + else if (name == "PreviousContractVersionAttribute") + { + result.previous_contracts.push_back(decode_previous_contract_attribute(attribute)); + } + // We could report the version that the type was introduced if the type is not contract versioned, however + // that information is not useful to us anywhere, so just skip it + } + + if (result.previous_contracts.empty()) + { + return result; + } + assert(!result.current_contract.name.empty()); - if (name.second == "VersionAttribute") + // There's no guarantee that the contract history will be sorted in metadata (in fact it's unlikely to be) + for (auto& prev : result.previous_contracts) + { + if (prev.contract_to.empty() || (prev.contract_to == result.current_contract.name)) { - version = get_attribute_value(attribute, 0); + // No 'to' contract indicates that this was the last contract before the current one + prev.contract_to = result.current_contract.name; + std::swap(prev, result.previous_contracts.back()); break; } } + assert(result.previous_contracts.back().contract_to == result.current_contract.name); + + for (std::size_t size = result.previous_contracts.size() - 1; size; --size) + { + auto& last = result.previous_contracts[size]; + auto itr = std::find_if(result.previous_contracts.begin(), result.previous_contracts.begin() + size, [&](auto const& prev) + { + return prev.contract_to == last.contract_from; + }); + assert(itr != result.previous_contracts.end()); + std::swap(*itr, result.previous_contracts[size - 1]); + } - return { HIWORD(version), LOWORD(version) }; + return result; } struct interface_info { TypeDef type; bool is_default{}; + bool is_protected{}; bool defaulted{}; bool overridable{}; bool base{}; bool exclusive{}; bool fastabi{}; - std::pair version{}; + // A pair of (relativeContract, version) where 'relativeContract' is the contract the interface was introduced + // in relative to the contract history of the class. E.g. if a class goes from contract 'A' to 'B' to 'C', + // 'relativeContract' would be '0' for an interface introduced in contract 'A', '1' for an interface introduced + // in contract 'B', etc. This is only set/valid for 'fastabi' interfaces + std::pair relative_version{}; std::vector> generic_param_stack{}; }; @@ -362,6 +578,7 @@ namespace cppwinrt auto type = impl.Interface(); auto name = w.write_temp("%", type); info.is_default = has_attribute(impl, "Windows.Foundation.Metadata", "DefaultAttribute"); + info.is_protected = has_attribute(impl, "Windows.Foundation.Metadata", "ProtectedAttribute"); info.defaulted = !base && (defaulted || info.is_default); { @@ -421,7 +638,6 @@ namespace cppwinrt } info.exclusive = has_attribute(info.type, "Windows.Foundation.Metadata", "ExclusiveToAttribute"); - info.version = get_version(info.type); get_interfaces_impl(w, result, info.defaulted, info.overridable, base, info.generic_param_stack, info.type.InterfaceImpl()); insert_or_assign(result, name, std::move(info)); } @@ -443,10 +659,32 @@ namespace cppwinrt return result; } - auto count = std::count_if(result.begin(), result.end(), [](auto&& pair) + auto history = get_contract_history(type); + std::size_t count = 0; + for (auto& pair : result) { - return pair.second.exclusive && !pair.second.base && !pair.second.overridable; - }); + if (pair.second.exclusive && !pair.second.base && !pair.second.overridable) + { + ++count; + + auto introduced = get_initial_contract_version(pair.second.type); + pair.second.relative_version.second = introduced.version; + + auto itr = std::find_if(history.previous_contracts.begin(), history.previous_contracts.end(), [&](previous_contract const& prev) + { + return prev.contract_from == introduced.name; + }); + if (itr != history.previous_contracts.end()) + { + pair.second.relative_version.first = static_cast(itr - history.previous_contracts.begin()); + } + else + { + assert(history.current_contract.name == introduced.name); + pair.second.relative_version.first = static_cast(history.previous_contracts.size()); + } + } + } std::partial_sort(result.begin(), result.begin() + count, result.end(), [](auto&& left_pair, auto&& right_pair) { @@ -482,9 +720,9 @@ namespace cppwinrt return left_enabled; } - if (left.version != right.version) + if (left.relative_version != right.relative_version) { - return left.version < right.version; + return left.relative_version < right.relative_version; } return left_pair.first < right_pair.first; @@ -625,7 +863,7 @@ namespace cppwinrt { if (auto visibility = std::get_if(&std::get(arg.value).value)) { - info.visible = std::get(visibility->value) == 2; + info.visible = std::get(visibility->value) == 2; break; } } diff --git a/cppwinrt/main.cpp b/cppwinrt/main.cpp index 6f10f8e79..33bb9248e 100644 --- a/cppwinrt/main.cpp +++ b/cppwinrt/main.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include +#include #include "strings.h" #include "settings.h" #include "type_writers.h" @@ -34,11 +35,14 @@ namespace cppwinrt { "?", 0, option::no_max, {}, {} }, { "library", 0, 1, "", "Specify library prefix (defaults to winrt)" }, { "filter" }, // One or more prefixes to include in input (same as -include) - { "license", 0, 0 }, // Generate license comment + { "license", 0, 1, "[]", "Generate license comment from template file" }, { "brackets", 0, 0 }, // Use angle brackets for #includes (defaults to quotes) { "fastabi", 0, 0 }, // Enable support for the Fast ABI { "ignore_velocity", 0, 0 }, // Ignore feature staging metadata and always include implementations { "synchronous", 0, 0 }, // Instructs cppwinrt to run on a single thread to avoid file system issues in batch builds + { "modules", 0, 0, {}, "Generate per-namespace C++20 module interface units (.ixx)" }, + { "module_include", 0, option::no_max, "", "Filter which namespaces are included in module .ixx generation" }, + { "module_exclude", 0, option::no_max, "", "Filter which namespaces are excluded from module .ixx generation" }, }; static void print_usage(writer& w) @@ -70,10 +74,14 @@ Copyright (c) Microsoft Corporation. All rights reserved. Where is one or more of: path Path to winmd file or recursively scanned folder - local Local ^%WinDir^%\System32\WinMetadata folder +)" +#if defined(_WIN32) || defined(_WIN64) +R"( local Local ^%WinDir^%\System32\WinMetadata folder sdk[+] Current version of Windows SDK [with extensions] 10.0.12345.0[+] Specific version of Windows SDK [with extensions] -)"; +)" +#endif + ; w.write(format, CPPWINRT_VERSION_STRING, bind_each(printOption, options)); } @@ -81,6 +89,7 @@ Where is one or more of: { settings.verbose = args.exists("verbose"); settings.fastabi = args.exists("fastabi"); + settings.modules = args.exists("modules"); settings.input = args.files("input", database::is_database); settings.reference = args.files("reference", database::is_database); @@ -88,13 +97,22 @@ Where is one or more of: settings.component = args.exists("component"); settings.base = args.exists("base"); + for (auto&& ns : args.values("module_include")) + { + settings.module_include.insert(ns); + } + for (auto&& ns : args.values("module_exclude")) + { + settings.module_exclude.insert(ns); + } + settings.license = args.exists("license"); settings.brackets = args.exists("brackets"); path output_folder = args.value("output", "."); create_directories(output_folder / "winrt/impl"); settings.output_folder = canonical(output_folder).string(); - settings.output_folder += '\\'; + settings.output_folder += std::filesystem::path::preferred_separator; for (auto && include : args.values("include")) { @@ -111,6 +129,40 @@ Where is one or more of: settings.exclude.insert(exclude); } + if (settings.license) + { + std::string license_arg = args.value("license"); + if (license_arg.empty()) + { + settings.license_template = R"(// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +)"; + } + else + { + std::filesystem::path template_path{ license_arg }; + std::ifstream template_file(absolute(template_path)); + if (template_file.fail()) + { + throw_invalid("Cannot read license template file '", absolute(template_path).string() + "'"); + } + std::string line_buf; + while (getline(template_file, line_buf)) + { + if (line_buf.empty()) + { + settings.license_template += "//\n"; + } + else + { + settings.license_template += "// "; + settings.license_template += line_buf; + settings.license_template += "\n"; + } + } + } + } + if (settings.component) { settings.component_overwrite = args.exists("overwrite"); @@ -146,7 +198,7 @@ Where is one or more of: { create_directories(component); settings.component_folder = canonical(component).string(); - settings.component_folder += '\\'; + settings.component_folder += std::filesystem::path::preferred_separator; } } } @@ -161,6 +213,13 @@ Where is one or more of: static void build_filters(cache const& c) { + // Build module_filter from -module_include / -module_exclude args. + // This controls which namespaces get .ixx files without affecting header generation. + if (!settings.module_include.empty() || !settings.module_exclude.empty()) + { + settings.module_filter = { settings.module_include, settings.module_exclude }; + } + if (settings.reference.empty()) { return; @@ -243,6 +302,79 @@ Where is one or more of: c.remove_type("Windows.Foundation.Numerics", "Vector4"); } + // Tarjan's algorithm for finding strongly connected components in the + // namespace dependency graph. Namespaces in an SCC have cyclic deps and + // must be combined into a single module. + static std::vector> find_sccs( + std::map, std::less<>> const& graph) + { + struct context + { + std::map index_of; + std::map lowlink; + std::map on_stack; + std::vector stack; + int next_index = 0; + std::vector> result; + + void strongconnect(std::string const& v, + std::map, std::less<>> const& g) + { + index_of[v] = next_index; + lowlink[v] = next_index; + next_index++; + stack.push_back(v); + on_stack[v] = true; + + auto it = g.find(v); + if (it != g.end()) + { + for (auto& w : it->second) + { + if (g.find(w) == g.end()) + { + continue; // dep not in graph (not a projected namespace) + } + + if (index_of.find(w) == index_of.end()) + { + strongconnect(w, g); + lowlink[v] = (std::min)(lowlink[v], lowlink[w]); + } + else if (on_stack[w]) + { + lowlink[v] = (std::min)(lowlink[v], index_of[w]); + } + } + } + + if (lowlink[v] == index_of[v]) + { + std::vector scc; + std::string w; + do + { + w = stack.back(); + stack.pop_back(); + on_stack[w] = false; + scc.push_back(std::move(w)); + } while (scc.back() != v); + result.push_back(std::move(scc)); + } + } + }; + + context ctx; + for (auto& [node, _] : graph) + { + if (ctx.index_of.find(node) == ctx.index_of.end()) + { + ctx.strongconnect(node, graph); + } + } + return std::move(ctx.result); + } + static int run(int const argc, char** argv) { int result{}; @@ -268,9 +400,19 @@ Where is one or more of: if (settings.verbose) { - char* path = nullptr; - _get_pgmptr(&path); - w.write(" tool: %\n", path); + { + char* path = argv[0]; +#if defined(_WIN32) || defined(_WIN64) + char path_buf[32768]; + DWORD path_size = GetModuleFileNameA(nullptr, path_buf, sizeof(path_buf)); + if (path_size) + { + path_buf[sizeof(path_buf) - 1] = 0; + path = path_buf; + } +#endif + w.write(" tool: %\n", path); + } w.write(" ver: %\n", CPPWINRT_VERSION_STRING); for (auto&& file : settings.input) @@ -294,11 +436,30 @@ Where is one or more of: w.flush_to_console(); task_group group; group.synchronous(args.exists("synchronous")); - writer ixx; - write_preamble(ixx); - ixx.write("module;\n"); - ixx.write(strings::base_includes); - ixx.write("\nexport module winrt;\n#define WINRT_EXPORT export\n\n"); + + // Dependency collection for per-namespace modules (v2) + std::map, std::less<>> ns_deps_map; + std::set projected_namespaces; + std::mutex ns_deps_mutex; + + // First pass: determine which namespaces will be in the module. + // This includes namespaces from this invocation AND those from other invocations + // (e.g., platform namespaces when building a component). The module_filter + // tells us which namespaces have modules across all invocations. + if (settings.modules) + { + for (auto&& [ns, members] : c.namespaces()) + { + if (!has_projected_types(members)) + { + continue; + } + if (settings.module_filter.empty() || settings.module_filter.includes(members)) + { + projected_namespaces.insert(std::string(ns)); + } + } + } for (auto&&[ns, members] : c.namespaces()) { @@ -307,21 +468,29 @@ Where is one or more of: continue; } - ixx.write("#include \"winrt/%.h\"\n", ns); - group.add([&, &ns = ns, &members = members] { - write_namespace_0_h(ns, members); - write_namespace_1_h(ns, members); - write_namespace_2_h(ns, members); - write_namespace_h(c, ns, members); + bool in_module = projected_namespaces.count(std::string(ns)) > 0; + std::set ns_deps; + auto* deps_ptr = (settings.modules && in_module) ? &ns_deps : nullptr; + + write_namespace_0_h(ns, members, deps_ptr); + write_namespace_1_h(ns, members, deps_ptr); + write_namespace_2_h(ns, members, deps_ptr); + write_namespace_h(c, ns, members, deps_ptr); + + if (settings.modules && in_module) + { + std::lock_guard lock(ns_deps_mutex); + ns_deps_map[std::string(ns)] = std::move(ns_deps); + } }); } if (settings.base) { write_base_h(); - ixx.flush_to_file(settings.output_folder + "winrt/winrt.ixx"); + write_macros_h(); } if (settings.component) @@ -356,6 +525,64 @@ Where is one or more of: group.get(); + // Generate per-namespace module interface files (.ixx) + // + // Each projected namespace gets its own C++20 named module (winrt.). + // Namespaces that form dependency cycles are detected using Tarjan's SCC algorithm + // and consolidated: one namespace "owns" the SCC module (containing all declarations), + // while others get thin re-export stubs so 'import winrt.;' always works. + // + // Base infrastructure modules (winrt_base, winrt_numerics) are only generated + // for platform projection builds (-base flag). + if (settings.modules) + { + if (settings.base) + { + write_numerics_ixx(); + write_base_ixx(); + } + + // Tarjan's SCC algorithm for cyclic namespace dependencies + auto sccs = find_sccs(ns_deps_map); + + for (auto& scc : sccs) + { + if (scc.size() == 1) + { + // Standalone namespace module + auto& ns = scc[0]; + write_namespace_ixx(ns, ns_deps_map[ns]); + } + else + { + // SCC: choose owner (alphabetically first), others re-export + std::sort(scc.begin(), scc.end()); + auto& owner = scc[0]; + + // External deps = union of all SCC members' deps, minus SCC members themselves + std::set external_deps; + std::set scc_set(scc.begin(), scc.end()); + for (auto& ns : scc) + { + for (auto& dep : ns_deps_map[ns]) + { + if (!scc_set.count(dep)) + { + external_deps.insert(dep); + } + } + } + + write_namespace_scc_owner_ixx(c, owner, scc, external_deps); + + for (size_t i = 1; i < scc.size(); ++i) + { + write_namespace_reexport_ixx(scc[i], owner); + } + } + } + } + if (settings.verbose) { w.write(" time: %ms\n", get_elapsed_time(start)); diff --git a/cppwinrt/pch.h b/cppwinrt/pch.h index 335324767..e6a31443e 100644 --- a/cppwinrt/pch.h +++ b/cppwinrt/pch.h @@ -1,5 +1,6 @@ #pragma once +#include #include "cmd_reader.h" #include #include "task_group.h" diff --git a/cppwinrt/settings.h b/cppwinrt/settings.h index 7655f8cc2..110e64917 100644 --- a/cppwinrt/settings.h +++ b/cppwinrt/settings.h @@ -10,6 +10,7 @@ namespace cppwinrt std::string output_folder; bool base{}; bool license{}; + std::string license_template; bool brackets{}; bool verbose{}; bool component{}; @@ -30,6 +31,12 @@ namespace cppwinrt bool fastabi{}; std::map fastabi_cache; + + bool modules{}; // Generate per-namespace C++20 module interface units (.ixx) + + std::set module_include; + std::set module_exclude; + winmd::reader::filter module_filter; }; extern settings_type settings; diff --git a/cppwinrt/text_writer.h b/cppwinrt/text_writer.h index bde87806e..c6fc380b3 100644 --- a/cppwinrt/text_writer.h +++ b/cppwinrt/text_writer.h @@ -1,18 +1,38 @@ #pragma once #include +#include #include #include #include #include #include +#include namespace cppwinrt { inline std::string file_to_string(std::string const& filename) { - std::ifstream file(filename, std::ios::binary); - return static_cast(std::stringstream() << file.rdbuf()).str(); + std::ifstream file(filename, std::ios::binary | std::ios::ate); + if (!file) { return{}; } + + const auto stream_size = file.tellg(); + if (stream_size == std::ifstream::pos_type(-1)) + { + return {}; + } + + file.seekg(0); + + auto size = static_cast(stream_size); + std::string result(size, '\0'); + file.read(result.data(), size); + if (!file) + { + result.resize(static_cast(file.gcount())); + } + + return result; } template @@ -65,7 +85,7 @@ namespace cppwinrt #if defined(_DEBUG) if (debug_trace) { - ::printf("%.*s", static_cast(value.size()), value.data()); + std::printf("%.*s", static_cast(value.size()), value.data()); } #endif } @@ -77,7 +97,7 @@ namespace cppwinrt #if defined(_DEBUG) if (debug_trace) { - ::printf("%c", value); + std::printf("%c", value); } #endif } @@ -103,22 +123,32 @@ namespace cppwinrt f(*static_cast(this)); } - void write(int32_t const value) + void write(int const value) + { + write(std::to_string(value)); + } + + void write(unsigned int const value) { write(std::to_string(value)); } - void write(uint32_t const value) + void write(signed long const value) { write(std::to_string(value)); } - void write(int64_t const value) + void write(unsigned long const value) { write(std::to_string(value)); } - void write(uint64_t const value) + void write(signed long long const value) + { + write(std::to_string(value)); + } + + void write(unsigned long long const value) { write(std::to_string(value)); } @@ -127,7 +157,16 @@ namespace cppwinrt void write_printf(char const* format, Args const&... args) { char buffer[128]; - size_t const size = sprintf_s(buffer, format, args...); +#if defined(_WIN32) || defined(_WIN64) + std::size_t const size = sprintf_s(buffer, format, args...); +#else + std::size_t size = std::snprintf(buffer, sizeof(buffer), format, args...); + if (size > sizeof(buffer) - 1) + { + std::fprintf(stderr, "\n*** WARNING: writer_base::write_printf -- buffer too small\n"); + size = sizeof(buffer) - 1; + } +#endif write(std::string_view{ buffer, size }); } @@ -147,8 +186,8 @@ namespace cppwinrt void flush_to_console(bool to_stdout = true) noexcept { - fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_first.size()), m_first.data()); - fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_second.size()), m_second.data()); + std::fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_first.size()), m_first.data()); + std::fprintf(to_stdout ? stdout : stderr, "%.*s", static_cast(m_second.size()), m_second.data()); m_first.clear(); m_second.clear(); } @@ -197,18 +236,15 @@ namespace cppwinrt bool file_equal(std::string const& filename) const { - if (!std::filesystem::exists(filename)) + // Non-throwing file_size returns uintmax_t(-1) on errors, which shouldn't ever be the size of m_first or m_second + std::error_code ec; + if (std::filesystem::file_size(filename, ec) != m_first.size() + m_second.size()) { return false; } auto file = file_to_string(filename); - if (file.size() != m_first.size() + m_second.size()) - { - return false; - } - if (!std::equal(m_first.begin(), m_first.end(), file.begin(), file.begin() + m_first.size())) { return false; @@ -223,9 +259,9 @@ namespace cppwinrt private: - static constexpr uint32_t count_placeholders(std::string_view const& format) noexcept + static constexpr std::uint32_t count_placeholders(std::string_view const& format) noexcept { - uint32_t count{}; + std::uint32_t count{}; bool escape{}; for (auto c : format) @@ -312,7 +348,7 @@ namespace cppwinrt { struct indent_guard { - indent_guard(indented_writer_base& w, int32_t offset = 1) noexcept : m_writer(w), m_offset(offset) + indent_guard(indented_writer_base& w, std::int32_t offset = 1) noexcept : m_writer(w), m_offset(offset) { m_writer.m_indent += m_offset; } @@ -324,13 +360,13 @@ namespace cppwinrt private: indented_writer_base& m_writer; - int32_t m_offset{}; + std::int32_t m_offset{}; }; void write_indent() { - for (int32_t i = 0; i < m_indent; i++) + for (std::int32_t i = 0; i < m_indent; i++) { writer_base::write_impl(" "); } @@ -398,7 +434,7 @@ namespace cppwinrt return result; } - int32_t m_indent{}; + std::int32_t m_indent{}; }; @@ -461,7 +497,7 @@ namespace cppwinrt { return [&](auto& writer) { - bool first{ true }; + bool first = true; for (auto&& item : list) { @@ -484,7 +520,7 @@ namespace cppwinrt { return [&](auto& writer) { - bool first{ true }; + bool first = true; for (auto&& item : list) { diff --git a/cppwinrt/type_writers.h b/cppwinrt/type_writers.h index a41b3086c..df17450f1 100644 --- a/cppwinrt/type_writers.h +++ b/cppwinrt/type_writers.h @@ -92,6 +92,18 @@ namespace cppwinrt return result; } + static bool transform_special_numeric_type(std::string_view& name) + { + if (name == "Matrix3x2") { name = "float3x2"; return true; } + else if (name == "Matrix4x4") { name = "float4x4"; return true; } + else if (name == "Plane") { name = "plane"; return true; } + else if (name == "Quaternion") { name = "quaternion"; return true; } + else if (name == "Vector2") { name = "float2"; return true; } + else if (name == "Vector3") { name = "float3"; return true; } + else if (name == "Vector4") { name = "float4"; return true; } + return false; + } + struct writer : writer_base { using writer_base::write; @@ -220,12 +232,12 @@ namespace cppwinrt return member_value_guard(this, &writer::delegate_types, value); } - void write_value(int32_t value) + void write_value(std::int32_t value) { write_printf("%d", value); } - void write_value(uint32_t value) + void write_value(std::uint32_t value) { write_printf("%#0x", value); } @@ -277,8 +289,6 @@ namespace cppwinrt return; } - // TODO: get rid of all these renames once parity with cppwinrt.exe has been reached... - if (name == "EventRegistrationToken" && ns == "Windows.Foundation") { write("winrt::event_token"); @@ -291,23 +301,15 @@ namespace cppwinrt { auto category = get_category(type); - if (ns == "Windows.Foundation.Numerics") + if (ns == "Windows.Foundation.Numerics" && transform_special_numeric_type(name)) { - if (name == "Matrix3x2") { name = "float3x2"; } - else if (name == "Matrix4x4") { name = "float4x4"; } - else if (name == "Plane") { name = "plane"; } - else if (name == "Quaternion") { name = "quaternion"; } - else if (name == "Vector2") { name = "float2"; } - else if (name == "Vector3") { name = "float3"; } - else if (name == "Vector4") { name = "float4"; } - write("winrt::@::%", ns, name); } else if (category == category::struct_type) { if ((name == "DateTime" || name == "TimeSpan") && ns == "Windows.Foundation") { - write("int64_t"); + write("std::int64_t"); } else if ((name == "Point" || name == "Size" || name == "Rect") && ns == "Windows.Foundation") { @@ -471,14 +473,14 @@ namespace cppwinrt { if (type == ElementType::Boolean) { write("bool"); } else if (type == ElementType::Char) { write("char16_t"); } - else if (type == ElementType::I1) { write("int8_t"); } - else if (type == ElementType::U1) { write("uint8_t"); } - else if (type == ElementType::I2) { write("int16_t"); } - else if (type == ElementType::U2) { write("uint16_t"); } - else if (type == ElementType::I4) { write("int32_t"); } - else if (type == ElementType::U4) { write("uint32_t"); } - else if (type == ElementType::I8) { write("int64_t"); } - else if (type == ElementType::U8) { write("uint64_t"); } + else if (type == ElementType::I1) { write("std::int8_t"); } + else if (type == ElementType::U1) { write("std::uint8_t"); } + else if (type == ElementType::I2) { write("std::int16_t"); } + else if (type == ElementType::U2) { write("std::uint16_t"); } + else if (type == ElementType::I4) { write("std::int32_t"); } + else if (type == ElementType::U4) { write("std::uint32_t"); } + else if (type == ElementType::I8) { write("std::int64_t"); } + else if (type == ElementType::U8) { write("std::uint64_t"); } else if (type == ElementType::R4) { write("float"); } else if (type == ElementType::R8) { write("double"); } else if (type == ElementType::String) diff --git a/cross-mingw-toolchain.cmake b/cross-mingw-toolchain.cmake new file mode 100644 index 000000000..23156e11b --- /dev/null +++ b/cross-mingw-toolchain.cmake @@ -0,0 +1,42 @@ +# This is a cmake-toolchain(5) file that can be used to cross-build +# cppwinrt.exe from Linux or other operating systems using a mingw-w64 cross +# toolchain. This should work with both GCC-based and llvm-mingw toolchains. +# +# Example usage with external toolchain: +# +# $ cmake -S . -B build/cross_x64/ \ +# --toolchain cross-mingw-toolchain.cmake \ +# -DMINGW_BIN_PATH=/opt/llvm-mingw/bin \ +# -DCMAKE_BUILD_TYPE=RelWithDebInfo \ +# -DCMAKE_INSTALL_PREFIX=$PWD/install/ +# +# Example usage with toolchain installed system-wide: +# +# $ cmake -S . -B build/cross_i686/ \ +# --toolchain cross-mingw-toolchain.cmake \ +# -DCMAKE_SYSTEM_PROCESSOR=i686 \ +# -DCMAKE_BUILD_TYPE=RelWithDebInfo \ +# -DCMAKE_INSTALL_PREFIX=$PWD/install/ + + +set(CMAKE_SYSTEM_NAME Windows) +if(NOT DEFINED CMAKE_SYSTEM_PROCESSOR) + set(CMAKE_SYSTEM_PROCESSOR x86_64) +endif() + +set(TOOLCHAIN_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32) + +if(DEFINED MINGW_BIN_PATH) + set(TOOLCHAIN_PREFIX "${MINGW_BIN_PATH}/${TOOLCHAIN_PREFIX}") +endif() + +set(CMAKE_C_COMPILER "${TOOLCHAIN_PREFIX}-gcc") +set(CMAKE_CXX_COMPILER "${TOOLCHAIN_PREFIX}-g++") +set(CMAKE_RC_COMPILER "${TOOLCHAIN_PREFIX}-windres") + +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +unset(TOOLCHAIN_PREFIX) diff --git a/CODE_OF_CONDUCT.md b/docs/code_of_conduct.md similarity index 93% rename from CODE_OF_CONDUCT.md rename to docs/code_of_conduct.md index f9ba8cf65..6257f2e76 100644 --- a/CODE_OF_CONDUCT.md +++ b/docs/code_of_conduct.md @@ -6,4 +6,4 @@ Resources: - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) -- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns \ No newline at end of file diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 000000000..9671ac0f7 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,26 @@ +## Contributing + +Thanks for your interest in C++/WinRT! You are welcome to contribute by filing issues for problems you encounter. +Project maintainers will consider changes that improve compatibility or fix bugs. + +The following process is required in order to have a pull request considered: + +* File an issue for any change you would like to propose. This can start a discussion so we can agree on an approach +before you invest a large amount of time. Due to the large number of dependent projects, contributions that include +compatibility risk or added complexity will generally be rejected. + +* Contributors will need the help of a project maintainer to verify the change with the Windows operating system +build system. If a project maintainer is available to provide guidance and mentorship for the change, a pull request +may be opened to begin the formal review process. + +Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that +you have the right to, and actually do, grant us the rights to use your contribution. For details, +visit https://cla.opensource.microsoft.com. + +When you submit a pull request, a CLA bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/docs/modules-design.md b/docs/modules-design.md new file mode 100644 index 000000000..8327231a7 --- /dev/null +++ b/docs/modules-design.md @@ -0,0 +1,190 @@ +# C++/WinRT Per-Namespace Modules: Design & Internals + +This document describes the design and implementation of per-namespace C++20 module support in C++/WinRT. It is intended for cppwinrt maintainers and contributors. + +## Architecture Overview + +The module system generates one C++20 named module per WinRT namespace. Each module encapsulates the same content as the traditional header files but exports declarations via `WINRT_EXPORT` in module purview. + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ winrt_numerics.ixx ── export module winrt_numerics; │ +│ winrt_base.ixx ── export module winrt_base; │ +│ export import winrt_numerics; │ +│ winrt.Windows.Foundation.ixx │ +│ ── export module winrt.Windows.Foundation; │ +│ import std; export import winrt_base; │ +│ import winrt.Windows.Foundation.Collections; │ +│ #include "winrt/impl/Windows.Foundation.0.h" │ +│ ... │ +│ #include "winrt/Windows.Foundation.h" │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Key Design Decisions + +### Unconditional Guards + +Module guards (`WINRT_IMPL_BUILD_MODULE`, `WINRT_IMPORT_MODULE`) are emitted unconditionally in generated projection headers — they are always present regardless of whether `-modules` was passed to cppwinrt.exe. The `-modules` flag controls `.ixx` generation and whether generated component files (`module.g.cpp`, stub `.cpp`) use module imports. This means: + +- Projection headers generated without `-modules` still work correctly when later compiled inside a module interface unit +- No regeneration of projection headers needed when switching between header and module consumption + +### WINRT_EXPORT Macro + +`WINRT_EXPORT` is defined in `base_macros.h` (generated as `winrt/base_macros.h`): +- When `WINRT_IMPL_BUILD_MODULE` is defined (inside `.ixx` compilation): `export extern "C++"` +- Otherwise (header mode): empty + +All `namespace winrt::impl` and `namespace std` blocks use `WINRT_EXPORT` so they export correctly from modules. The `extern "C++"` wrapping enables include-before-import compatibility (same technique as MSVC STL). + +### Per-Namespace vs Monolithic + +Unlike the v1 approach (single `import winrt;`), v2 generates one module per namespace. This provides: + +- **Finer granularity**: Import only what you need +- **Better parallelism**: Independent modules compile in parallel +- **Component module support**: Component namespaces get their own modules + +The trade-off is handling dependency cycles between namespaces (see SCC below). + +This is enforced via the MSBuild `CppWinRTConsumeModule` metadata on ProjectReference — it only points at the platform module builder, not at component projects. + +## Code Generator Pipeline + +### Entry Point: `main.cpp` + +1. **Namespace enumeration**: First pass determines which namespaces are module-eligible using `module_filter` (from `-module_include`/`-module_exclude`) + +2. **Header generation**: Standard header generation with optional dependency collection. When `-modules` is active and a namespace is in the module, `write_namespace_*_h()` functions populate `ns_deps` sets via the `deps_ptr` parameter + +3. **Dependency graph construction**: After all headers are generated, `ns_deps_map` contains the full namespace dependency graph + +4. **SCC detection**: Tarjan's algorithm (`find_sccs()`) identifies strongly-connected components + +5. **Module generation**: For each SCC: + - Size 1: `write_namespace_ixx()` — standalone module + - Size > 1: `write_namespace_scc_owner_ixx()` for the owner (alphabetically first) + `write_namespace_reexport_ixx()` for others + +### CLI Options + +| Flag | Description | +|-|-| +| `-modules` | Enable `.ixx` generation | +| `-module_include ...` | Only generate modules for these namespace prefixes | +| `-module_exclude ...` | Skip these namespace prefixes | + +The `module_filter` is populated from these flags and checked against ALL cache namespaces (not just the projection filter). This is important for component builds where the platform namespaces are not being projected but their modules exist from a prior builder invocation. + +### Generated Files + +| File | When Generated | Purpose | +|-|-|-| +| `winrt/base_macros.h` | Always with `-base` | Macros for module builds (WINRT_EXPORT, etc.) | +| `winrt/winrt_base.ixx` | `-modules -base` | Core types module | +| `winrt/winrt_numerics.ixx` | `-modules -base` | Numerics module | +| `winrt/winrt..ixx` | `-modules` | Per-namespace module | + +## SCC (Strongly Connected Components) + +### The Problem + +WinRT namespaces have cyclic dependencies. For example: +- `Windows.Foundation` depends on `Windows.Foundation.Collections` (via `IVector`, `IMap`, etc.) +- `Windows.Foundation.Collections` depends on `Windows.Foundation` (via `IAsyncOperation`, `Uri`, etc.) + +C++20 modules cannot have circular imports. If module A imports module B, then module B cannot import module A. + +### The Solution: SCC Consolidation + +Tarjan's algorithm identifies groups of namespaces that form dependency cycles. These groups (SCCs) are consolidated: + +1. **Owner selection**: The alphabetically first namespace in the SCC becomes the "owner" +2. **Owner module**: Contains ALL declarations from ALL SCC namespaces. Forward-declares all types first, then includes headers in phase order (all `*.0.h`, then `*.1.h`, then `*.2.h`, then public headers) +3. **Re-export stubs**: Other SCC members get thin `.ixx` files that just re-export the owner module + +This means `import winrt.Windows.Foundation;` and `import winrt.Windows.Foundation.Collections;` both work — they resolve to the same underlying module. + +### Example Generated Files + +**Owner** (`winrt.Windows.Foundation.ixx`): +```cpp +module; +#define WINRT_IMPL_BUILD_MODULE +#include "winrt/base_macros.h" +// ... + +// This module is an SCC owner (cycle breaker). The following namespaces +// form a dependency cycle and are consolidated into this single module: +// - Windows.Foundation +// - Windows.Foundation.Collections +// Other SCC namespaces are emitted as re-export stubs. + +export module winrt.Windows.Foundation; + +import std; +export import winrt_base; + +// Forward declarations for all SCC namespaces... +// #include all impl headers in phase order... +``` + +**Re-export stub** (`winrt.Windows.Foundation.Collections.ixx`): +```cpp +// NOTE: This module does not define declarations of its own. +// It re-exports all declarations from the 'winrt.Windows.Foundation' module. +export module winrt.Windows.Foundation.Collections; +export import winrt.Windows.Foundation; +``` + +## MSBuild Integration + +### Targets Flow + +``` +CppWinRTResolveModuleReferences (resolves IFC paths from ProjectReference metadata) + ↓ +CppWinRTMakePlatformProjection (generates headers + .ixx for platform types) +CppWinRTMakeReferenceProjection (generates headers + .ixx for referenced WinMDs) +CppWinRTMakeComponentProjection (generates headers + .ixx for component types) + ↓ +CppWinRTAddModuleInterfaces (discovers .ixx files, adds to ClCompile items) + ↓ +FixupCLCompileOptions (MSVC module dependency scanner processes .ixx) + ↓ +ClCompile (compiles .ixx → .ifc + .obj) +``` + +### Key Properties + +- `CppWinRTBuildModule`: Enables `-modules` for all three projections (platform, reference, component), causing `.ixx` generation and compilation. +- `CppWinRTConsumeModule` (ProjectReference metadata): Per-reference opt-in for IFC consumption. When set, suppresses `-modules` on the platform projection so the consumer uses pre-built IFCs from the referenced project instead of generating its own. +- `_CppWinRTConsumesPlatformModules`: Internal property set by `CppWinRTResolveModuleReferences` when any ProjectReference has `CppWinRTConsumeModule=true`. Controls whether the platform projection receives `-modules`. + +### Cross-Project IFC Resolution + +MSVC's module dependency scanner uses `/ifcSearchDir` for within-project module resolution. For cross-project modules, the scanner generates explicit `/reference "module.name=path.ifc"` entries based on the dependency scan results. The `/ifcSearchDir` pointing to the builder's `$(IntDir)` allows the scanner to find the pre-built IFCs. + +## Dependency Collection + +During header generation, when `-modules` is active, each `write_namespace_*_h()` function receives a `deps_ptr` parameter. The writer's `w.depends` map is inspected to find referenced namespaces. Only namespaces that: +1. Exist in the cache +2. Have projected types +3. Are in the module namespace set (or set is empty) + +are added to the dependency set. Self-references are excluded. The union of dependencies from all four header files (`*.0.h`, `*.1.h`, `*.2.h`, `.h`) gives the complete dependency set for a namespace module. + +## Testing + +### test/test_cpp20_module/ (in-repo) + +Standalone test built by the main solution. Uses a PreBuildEvent to run cppwinrt.exe with `-modules -base -module_include "Windows.Foundation"`. Tests URI, events, collections, and coroutines. + +### test/nuget/ (NuGet integration) + +Multi-project solution: +- **TestModuleBuilder**: Static library that pre-builds platform modules +- **TestModuleComponent1**: Component DLL (Greeter class), consumes builder's modules +- **TestModuleComponent2**: Component DLL (GreeterGroup), depends on Component1 +- **TestModuleConsumerApp**: Console app, consumes builder + both components +- **TestModuleApp**: Single-project that builds and consumes its own modules diff --git a/SECURITY.md b/docs/security.md similarity index 72% rename from SECURITY.md rename to docs/security.md index e0dfff56a..b8a28b1c5 100644 --- a/SECURITY.md +++ b/docs/security.md @@ -1,20 +1,20 @@ - + ## Security -Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). -If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. ## Reporting Security Issues **Please do not report security vulnerabilities through public GitHub issues.** -Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). -If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). -You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: @@ -28,7 +28,7 @@ Please include the requested information listed below (as much as you can provid This information will help us triage your report more quickly. -If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. ## Preferred Languages @@ -36,6 +36,6 @@ We prefer all communications to be in English. ## Policy -Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). - + \ No newline at end of file diff --git a/fast_fwd/arm/thunks.asm b/fast_fwd/arm/thunks.asm deleted file mode 100644 index 9010908b6..000000000 --- a/fast_fwd/arm/thunks.asm +++ /dev/null @@ -1,58 +0,0 @@ -; ARM fast forwarder thunk implementations -; Calling convention: https://docs.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions - -#include "ksarm.h" - - IMPORT __guard_check_icall_fptr - - TEXTAREA - - CFG_ALIGN - NESTED_ENTRY InvokeForwarder - - ; Save enregistered args and return address - PROLOG_PUSH {r0-r4, lr} - - ; Replace forwarder abi with owner abi - ldr r1, [r0, #4] - str r1, [sp] - - ; Add offset and index (on stack) - ldr r2, [sp, #24] - ldr r3, [r0, #8] - add r2, r2, r3 - - ; Get method address from owner abi vtable - ldr r0, [r1] - ldr r4, [r0, r2, lsl #2] - mov r0, r4 - - ; Verify indirect call target - mov32 r12, __guard_check_icall_fptr - ldr r12, [r12] - blx r12 - - ; Restore method address, return address, and args - mov r12, r4 - EPILOG_POP {r0-r4, lr} - EPILOG_NOP add sp, #4 - - ; Jump to method - EPILOG_NOP bx r12 - - NESTED_END InvokeForwarder - - ; Define thunks - MACRO - WINRT_FF_THUNK $i - LEAF_ENTRY winrt_ff_thunk$i - ; Note: no scratch registers available (r12/IP is used by CFG), must use stack - mov r12, $i - push r12 - ldr pc, =InvokeForwarder - LEAF_END winrt_ff_thunk$i - MEND - -#include "thunks.inc" - - END \ No newline at end of file diff --git a/fast_fwd/fast_fwd.vcxproj b/fast_fwd/fast_fwd.vcxproj index dbd337e66..b9452d149 100644 --- a/fast_fwd/fast_fwd.vcxproj +++ b/fast_fwd/fast_fwd.vcxproj @@ -17,14 +17,6 @@ Release x64 - - Debug - ARM - - - Release - ARM - Debug ARM64 @@ -39,9 +31,8 @@ {A63B3AD1-AB7B-461E-9FFF-2447F5BCD459} Win32Proj fastfwd - 10.0 - + StaticLibrary true @@ -80,16 +71,10 @@ - true + true false !$(Platform_Arm) - - cppwinrt_fast_forwarder - - - cppwinrt_fast_forwarder - cppwinrt_fast_forwarder @@ -120,12 +105,11 @@ Document src true - true - true + false Document src diff --git a/mingw-support/xmllite.def b/mingw-support/xmllite.def new file mode 100644 index 000000000..c96291d16 --- /dev/null +++ b/mingw-support/xmllite.def @@ -0,0 +1,8 @@ +LIBRARY "XmlLite.dll" +EXPORTS +CreateXmlReader +CreateXmlReaderInputWithEncodingCodePage +CreateXmlReaderInputWithEncodingName +CreateXmlWriter +CreateXmlWriterOutputWithEncodingCodePage +CreateXmlWriterOutputWithEncodingName diff --git a/mingw-support/xmllite_i386.def b/mingw-support/xmllite_i386.def new file mode 100644 index 000000000..79921fce7 --- /dev/null +++ b/mingw-support/xmllite_i386.def @@ -0,0 +1,8 @@ +LIBRARY "XmlLite.dll" +EXPORTS +CreateXmlReader@12 +CreateXmlReaderInputWithEncodingCodePage@24 +CreateXmlReaderInputWithEncodingName@24 +CreateXmlWriter@12 +CreateXmlWriterOutputWithEncodingCodePage@16 +CreateXmlWriterOutputWithEncodingName@16 diff --git a/natvis/cppwinrt.natvis b/natvis/cppwinrt.natvis index de9cff59c..7fad2e26c 100644 --- a/natvis/cppwinrt.natvis +++ b/natvis/cppwinrt.natvis @@ -14,18 +14,26 @@ null + + + + null + null + + #{A,nvoXb}{R,nvoXb}{G,nvoXb}{B,nvoXb} + {{size = {m_size}, {m_data,[m_size]}}} - m_size - m_data + m_size + m_data diff --git a/natvis/cppwinrt_visualizer.cpp b/natvis/cppwinrt_visualizer.cpp index 1e2539910..4b0a0c370 100644 --- a/natvis/cppwinrt_visualizer.cpp +++ b/natvis/cppwinrt_visualizer.cpp @@ -11,8 +11,39 @@ using namespace std::filesystem; using namespace winrt; using namespace winmd::reader; -std::vector db_files; -std::unique_ptr db; +namespace +{ + std::vector db_files; + std::unique_ptr db_cache; + coded_index guid_TypeRef{}; +} + +coded_index FindGuidType() +{ + if (!guid_TypeRef) + { + // There is no definitive TypeDef for System.Guid. But there are a variety of TypeRefs scattered about + // This one should be relatively quick to find + auto pv = db_cache->find("Windows.Foundation", "IPropertyValue"); + for (auto&& method : pv.MethodList()) + { + if (method.Name() == "GetGuid") + { + auto const& sig = method.Signature(); + auto const& type = sig.ReturnType().Type().Type(); + XLANG_ASSERT(std::holds_alternative>(type)); + if (std::holds_alternative>(type)) + { + guid_TypeRef = std::get>(type); + XLANG_ASSERT(guid_TypeRef.type() == TypeDefOrRef::TypeRef); + XLANG_ASSERT(guid_TypeRef.TypeRef().TypeNamespace() == "System"); + XLANG_ASSERT(guid_TypeRef.TypeRef().TypeName() == "Guid"); + } + } + } + } + return guid_TypeRef; +} void MetadataDiagnostic(DkmProcess* process, std::wstring const& status, std::filesystem::path const& path) { @@ -93,7 +124,7 @@ void LoadMetadata(DkmProcess* process, WCHAR const* processPath, std::string_vie { auto winmd_path = path{ processPath }; auto probe_file = std::string{ typeName }; - do + while (true) { winmd_path.replace_filename(probe_file + ".winmd"); MetadataDiagnostic(process, L"Looking for ", winmd_path); @@ -105,7 +136,7 @@ void LoadMetadata(DkmProcess* process, WCHAR const* processPath, std::string_vie if (std::find(db_files.begin(), db_files.end(), path_string) == db_files.end()) { - db->add_database(path_string, [](TypeDef const& type) { return type.Flags().WindowsRuntime(); }); + db_cache->add_database(path_string, [](TypeDef const& type) { return type.Flags().WindowsRuntime(); }); db_files.push_back(path_string); } } @@ -115,17 +146,18 @@ void LoadMetadata(DkmProcess* process, WCHAR const* processPath, std::string_vie break; } probe_file = probe_file.substr(0, pos); - } while (true); + } } -TypeDef FindType(DkmProcess* process, std::string_view const& typeName) +TypeDef FindSimpleType(DkmProcess* process, std::string_view const& typeName) { - auto type = db->find(typeName); + XLANG_ASSERT(typeName.find('<') == std::string_view::npos); + auto type = db_cache->find(typeName); if (!type) { auto processPath = process->Path()->Value(); LoadMetadata(process, processPath, typeName); - type = db->find(typeName); + type = db_cache->find(typeName); if (!type) { NatvisDiagnostic(process, @@ -135,19 +167,104 @@ TypeDef FindType(DkmProcess* process, std::string_view const& typeName) return type; } -TypeDef FindType(DkmProcess* process, std::string_view const& typeNamespace, std::string_view const& typeName) +TypeDef FindSimpleType(DkmProcess* process, std::string_view const& typeNamespace, std::string_view const& typeName) { - auto type = db->find(typeNamespace, typeName); + XLANG_ASSERT(typeName.find('<') == std::string_view::npos); + auto type = db_cache->find(typeNamespace, typeName); if (!type) { std::string fullName(typeNamespace); fullName.append("."); fullName.append(typeName); - FindType(process, fullName); + FindSimpleType(process, fullName); } return type; } +std::vector ParseTypeName(std::string_view name) +{ + DWORD count; + HSTRING* parts; + auto wide_name = winrt::to_hstring(name); + winrt::check_hresult(::RoParseTypeName(static_cast(get_abi(wide_name)), &count, &parts)); + + winrt::com_array wide_parts{ parts, count, winrt::take_ownership_from_abi }; + std::vector result; + for (auto&& part : wide_parts) + { + result.push_back(winrt::to_string(part)); + } + return result; +} + +template sent> +TypeSig ResolveGenericTypePart(DkmProcess* process, iter& it, sent const& end) +{ + constexpr std::pair elementNames[] = { + {"Boolean", ElementType::Boolean}, + {"Int8", ElementType::I1}, + {"Int16", ElementType::I2}, + {"Int32", ElementType::I4}, + {"Int64", ElementType::I8}, + {"UInt8", ElementType::U1}, + {"UInt16", ElementType::U2}, + {"UInt32", ElementType::U4}, + {"UInt64", ElementType::U8}, + {"Single", ElementType::R4}, + {"Double", ElementType::R8}, + {"String", ElementType::String}, + {"Char16", ElementType::Char}, + {"Object", ElementType::Object} + }; + std::string_view partName = *it; + auto basic_type_pos = std::find_if(std::begin(elementNames), std::end(elementNames), [&partName](auto&& elem) { return elem.first == partName; }); + if (basic_type_pos != std::end(elementNames)) + { + return TypeSig{ basic_type_pos->second }; + } + + if (partName == "Guid") + { + return TypeSig{ FindGuidType() }; + } + + TypeDef type = FindSimpleType(process, partName); + auto tickPos = partName.rfind('`'); + if (tickPos == partName.npos) + { + return TypeSig{ type.coded_index() }; + } + + int paramCount = 0; + std::from_chars(partName.data() + tickPos + 1, partName.data() + partName.size(), paramCount); + std::vector genericArgs; + for (int i = 0; i < paramCount; ++i) + { + genericArgs.push_back(ResolveGenericTypePart(process, ++it, end)); + } + return TypeSig{ GenericTypeInstSig{ type.coded_index(), std::move(genericArgs) } }; +} + +TypeSig ResolveGenericType(DkmProcess* process, std::string_view genericName) +{ + auto parts = ParseTypeName(genericName); + auto begin = parts.begin(); + return ResolveGenericTypePart(process, begin, parts.end()); +} + +TypeSig FindType(DkmProcess* process, std::string_view const& typeName) +{ + auto paramIndex = typeName.find('<'); + if (paramIndex == std::string_view::npos) + { + return TypeSig{ FindSimpleType(process, typeName).coded_index() }; + } + else + { + return ResolveGenericType(process, typeName); + } +} + cppwinrt_visualizer::cppwinrt_visualizer() { try @@ -165,7 +282,7 @@ cppwinrt_visualizer::cppwinrt_visualizer() db_files.push_back(file.path().string()); } } - db.reset(new cache(db_files, [](TypeDef const& type) { return type.Flags().WindowsRuntime(); })); + db_cache.reset(new cache(db_files, [](TypeDef const& type) { return type.Flags().WindowsRuntime(); })); } catch (...) { @@ -187,13 +304,14 @@ cppwinrt_visualizer::cppwinrt_visualizer() cppwinrt_visualizer::~cppwinrt_visualizer() { ClearTypeResolver(); + guid_TypeRef = {}; db_files.clear(); - db.reset(); + db_cache.reset(); } HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression( _In_ DkmVisualizedExpression* pVisualizedExpression, - _Deref_out_ DkmEvaluationResult** ppResultObject + _COM_Outptr_result_maybenull_ DkmEvaluationResult** ppResultObject ) { try @@ -207,31 +325,37 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression( IF_FAIL_RET(pTypeSymbol->get_name(&bstrTypeName)); // Visualize top-level C++/WinRT objects containing ABI pointers - bool isAbiObject; + ObjectType objectType; if (wcscmp(bstrTypeName, L"winrt::Windows::Foundation::IInspectable") == 0) { - isAbiObject = false; + objectType = ObjectType::Projection; } // Visualize nested object properties via raw ABI pointers else if ((wcscmp(bstrTypeName, L"winrt::impl::IInspectable") == 0) || (wcscmp(bstrTypeName, L"winrt::impl::inspectable_abi") == 0)) { - isAbiObject = true; + objectType = ObjectType::Abi; + } + // Visualize C++/WinRT object implementations + else if (wcsncmp(bstrTypeName, L"winrt::impl::producer<", wcslen(L"winrt::impl::producer<")) == 0) + { + objectType = ObjectType::Abi; } // Visualize all raw IInspectable pointers else if (wcscmp(bstrTypeName, L"IInspectable") == 0) { - isAbiObject = true; + objectType = ObjectType::Abi; } else { // unrecognized type NatvisDiagnostic(pVisualizedExpression, std::wstring(L"Unrecognized type: ") + (LPWSTR)bstrTypeName, NatvisDiagnosticLevel::Error); + *ppResultObject = nullptr; return S_OK; } - IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, isAbiObject, ppResultObject)); + IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, objectType, ppResultObject)); return S_OK; } diff --git a/natvis/cppwinrt_visualizer.h b/natvis/cppwinrt_visualizer.h index 5f12ec39a..924dc3cbc 100644 --- a/natvis/cppwinrt_visualizer.h +++ b/natvis/cppwinrt_visualizer.h @@ -8,7 +8,7 @@ struct cppwinrt_visualizer : winrt::implements - + + + Debug + ARM64 + Debug Win32 + + Release + ARM64 + Release Win32 @@ -27,14 +35,6 @@ cppwinrtvisualizer $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)packages\)) - - v142 - 10.0 - - - v141 - 10.0.17763.0 - DynamicLibrary @@ -49,11 +49,20 @@ DynamicLibrary true + + DynamicLibrary + true + DynamicLibrary false true + + DynamicLibrary + false + true + $(VSInstallDir)DIA SDK\include @@ -71,40 +80,34 @@ + + + + + + - + true - x86\$(Configuration)\$(Deployment)\ - x86\$(Configuration)\$(Deployment)\ - - true - x64\$(Configuration)\$(Deployment)\ - x64\$(Configuration)\$(Deployment)\ - - + false - x86\$(Configuration)\$(Deployment)\ - x86\$(Configuration)\$(Deployment)\ - - false - x64\$(Configuration)\$(Deployment)\ - x64\$(Configuration)\$(Deployment)\ + + $(CppWinRTPlatform)\$(Configuration)\$(Deployment)\ Use Level4 + true Disabled - false - WIN32;_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;WIN32;_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) - stdcpp17 - /await + stdcpp20 pch.h @@ -125,13 +128,36 @@ Use Level4 + true + Disabled + VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) + stdcpp20 + pch.h + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + + + Windows + DebugFull + advapi32.lib;shell32.lib;windowsapp.lib;$(VsDebugEng_Lib);%(AdditionalDependencies) + .\cppwinrtvisualizer.def + vsdebugeng.dll + + + + + Use + Level4 + true Disabled - false - _DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;_DEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) - stdcpp17 + stdcpp20 pch.h - /await _DEBUG;%(PreprocessorDefinitions) @@ -150,15 +176,15 @@ Use Level4 + true MaxSpeed true true - false - WIN32;NDEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;WIN32;NDEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) - stdcpp17 + stdcpp20 pch.h - /await + Guard _DEBUG;%(PreprocessorDefinitions) @@ -180,15 +206,45 @@ Use Level4 + true + MaxSpeed + true + true + VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;NDEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) + stdcpp20 + pch.h + Guard + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + $(IntDir);%(AdditionalIncludeDirectories) + + + Windows + true + true + DebugFull + advapi32.lib;shell32.lib;windowsapp.lib;$(VsDebugEng_Lib);%(AdditionalDependencies) + .\cppwinrtvisualizer.def + vsdebugeng.dll + /DEBUGTYPE:CV,FIXUP %(AdditionalOptions) + + + + + Use + Level4 + true MaxSpeed true true - false - NDEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + VSDEBUGENG_USE_CPP11_SCOPED_ENUMS;NDEBUG;VISUALIZER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) $(IntDir);..\cppwinrt;..\strings;$(DIASDKInc);%(AdditionalIncludeDirectories) - stdcpp17 + stdcpp20 pch.h - /await + Guard _DEBUG;%(PreprocessorDefinitions) @@ -227,8 +283,10 @@ Create Create + Create Create Create + Create @@ -263,6 +321,6 @@ - + \ No newline at end of file diff --git a/natvis/object_visualizer.cpp b/natvis/object_visualizer.cpp index 6bb6b6deb..d953a1c03 100644 --- a/natvis/object_visualizer.cpp +++ b/natvis/object_visualizer.cpp @@ -99,18 +99,18 @@ static HRESULT EvaluatePropertyExpression( _In_ PropertyData const& prop, _In_ DkmVisualizedExpression* pExpression, _In_ DkmPointerValueHome* pObject, - bool isAbiObject, + ObjectType objectType, _Out_ com_ptr& pEvaluationResult ) { wchar_t abiAddress[40]; auto process = pExpression->RuntimeInstance()->Process(); bool is64Bit = ((process->SystemInformation()->Flags() & DefaultPort::DkmSystemInformationFlags::Is64Bit) != 0); - swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", isAbiObject ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address()); + swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", objectType == ObjectType::Abi ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address()); wchar_t wszEvalText[500]; std::wstring propCast; PCWSTR propField; - if (prop.category < PropertyCategory::Value) + if (IsBuiltIn(prop.category)) { propField = g_categoryData[(int)prop.category].propField; } @@ -174,12 +174,12 @@ static HRESULT EvaluatePropertyString( _In_ PropertyData const& prop, _In_ DkmVisualizedExpression* pExpression, _In_ DkmPointerValueHome* pObject, - bool isAbiObject, + ObjectType objectType, _Out_ com_ptr& pValue ) { com_ptr pEvaluationResult; - IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, isAbiObject, pEvaluationResult)); + IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, objectType, pEvaluationResult)); if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult) { return E_FAIL; @@ -195,11 +195,11 @@ static HRESULT EvaluatePropertyString( static std::string GetRuntimeClass( _In_ DkmVisualizedExpression* pExpression, _In_ DkmPointerValueHome* pObject, - bool isAbiObject + ObjectType objectType ) { com_ptr pValue; - EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue); + EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, objectType, pValue); if (!pValue || pValue->Length() == 0) { return ""; @@ -210,16 +210,11 @@ static std::string GetRuntimeClass( static HRESULT ObjectToString( _In_ DkmVisualizedExpression* pExpression, _In_ DkmPointerValueHome* pObject, - bool isAbiObject, - _Out_ com_ptr& pValue, - bool* unavailable = nullptr + ObjectType objectType, + _Out_ com_ptr& pValue ) { - if (unavailable) - { - *unavailable = false; - } - if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue))) + if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, objectType, pValue))) { if (pValue && pValue->Length() > 0) { @@ -229,7 +224,7 @@ static HRESULT ObjectToString( // WINRT_abi_val returned 0, which may be success or failure (due to VirtualQuery validation) // Call back for the runtime class name to determine which it was - if (!GetRuntimeClass(pExpression, pObject, isAbiObject).empty()) + if (!GetRuntimeClass(pExpression, pObject, objectType).empty()) { return DkmString::Create(L"", pValue.put()); } @@ -237,17 +232,13 @@ static HRESULT ObjectToString( // VirtualQuery validation failed (as determined by no runtime class name) or an // exception escaped WINRT_abi_val (e.g, bad pointer, which we try to avoid via VirtualQuery) - if (unavailable) - { - *unavailable = true; - } return DkmString::Create(L"", pValue.put()); } static HRESULT CreateChildVisualizedExpression( _In_ PropertyData const& prop, _In_ DkmVisualizedExpression* pParent, - bool isAbiObject, + ObjectType objectType, _Deref_out_ DkmChildVisualizedExpression** ppResult ) { @@ -256,7 +247,7 @@ static HRESULT CreateChildVisualizedExpression( com_ptr pEvaluationResult; auto valueHome = make_com_ptr(pParent->ValueHome()); com_ptr pParentPointer = valueHome.as(); - IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), isAbiObject, pEvaluationResult)); + IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), objectType, pEvaluationResult)); if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult) { return E_FAIL; @@ -273,7 +264,7 @@ static HRESULT CreateChildVisualizedExpression( { isNonNullObject = true; IF_FAIL_RET(DkmPointerValueHome::Create(childObjectAddress, pChildPointer.put())); - IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), true, pValue)); + IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), ObjectType::Abi, pValue)); } } if(!isNonNullObject) @@ -287,7 +278,7 @@ static HRESULT CreateChildVisualizedExpression( IF_FAIL_RET(DkmString::Create(prop.displayName.c_str(), pDisplayName.put())); PCWSTR displayType; - if (prop.category < PropertyCategory::Value) + if (IsBuiltIn(prop.category)) { displayType = g_categoryData[(int)prop.category].displayType; } @@ -335,7 +326,7 @@ static HRESULT CreateChildVisualizedExpression( if (isNonNullObject) { - com_ptr pObjectVisualizer = make_self(pChildVisualizedExpression.get(), true); + com_ptr pObjectVisualizer = make_self(pChildVisualizedExpression.get(), ObjectType::Abi); IF_FAIL_RET(pChildVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get())); } else @@ -349,19 +340,291 @@ static HRESULT CreateChildVisualizedExpression( return S_OK; } -struct property_type +std::optional GetPropertyCategory( + Microsoft::VisualStudio::Debugger::DkmProcess* process, + TypeSig const& owningType, + TypeSig const& propertyType +) { - MethodDef get; - MethodDef set; + std::optional propCategory; + if (auto pElementType = std::get_if(&propertyType.Type())) + { + if ((ElementType::Boolean <= *pElementType) && (*pElementType <= ElementType::String)) + { + propCategory = (PropertyCategory)(static_cast::type>(*pElementType) - + static_cast::type>(ElementType::Boolean)); + } + else if (*pElementType == ElementType::Object) + { + // result = PropertyCategory::Class; + } + } + else if (auto pIndex = std::get_if>(&propertyType.Type())) + { + auto type = ResolveType(process, *pIndex); + if (type) + { + if (get_category(type) == category::class_type || get_category(type) == category::interface_type) + { + propCategory = PropertyCategory::Class; + } + else + { + propCategory = PropertyCategory::Value; + } + } + else if (pIndex->type() == TypeDefOrRef::TypeRef) + { + auto typeRef = pIndex->TypeRef(); + if (typeRef.TypeNamespace() == "System" && typeRef.TypeName() == "Guid") + { + propCategory = PropertyCategory::Guid; + } + } + } + else if (auto pGenericInst = std::get_if(&propertyType.Type())) + { + XLANG_ASSERT(get_category(ResolveType(process, pGenericInst->GenericType())) == category::interface_type); + propCategory = PropertyCategory::Class; + } + else if (auto pGenericIndex = std::get_if(&propertyType.Type())) + { + if (auto pOwner = std::get_if(&owningType.Type())) + { + auto const& index = pGenericIndex->index; + auto const& genericArgs = pOwner->GenericArgs(); + propCategory = GetPropertyCategory(process, owningType, genericArgs.first[index]); + } + else + { + NatvisDiagnostic(process, L"Can't resolve GenericTypeIndex property on non-generic Type", NatvisDiagnosticLevel::Warning); + } + } + else + { + NatvisDiagnostic(process, L"Unsupported TypeSig encountered", NatvisDiagnosticLevel::Warning); + } + return propCategory; +} + +struct writer +{ + std::vector generic_params; + + std::string result; + + void write(char c) + { + result.push_back(c); + } + + void write(std::string_view const& str) + { + for (auto c : str) + { + if (c == '.') + { + write(':'); + write(':'); + } + else if (c != '`') + { + write(c); + } + else + { + return; + } + } + } + + void write(ElementType type) + { + switch (type) + { + case ElementType::Boolean: + write("bool"); + break; + case ElementType::Char: + write("wchar_t"); + break; + case ElementType::I1: + write("int8_t"); + break; + case ElementType::U1: + write("uint8_t"); + break; + case ElementType::I2: + write("int16_t"); + break; + case ElementType::U2: + write("uint16_t"); + break; + case ElementType::I4: + write("int32_t"); + break; + case ElementType::U4: + write("uint32_t"); + break; + case ElementType::I8: + write("int64_t"); + break; + case ElementType::U8: + write("uint64_t"); + break; + case ElementType::R4: + write("float"); + break; + case ElementType::R8: + write("double"); + break; + case ElementType::String: + write("winrt::hstring"); + break; + case ElementType::Object: + write("winrt::Windows::Foundation::IInspectable"); + break; + default: + XLANG_ASSERT(false); + break; + }; + } + + void write_namespace_and_type(std::string_view ns, std::string_view name) + { + if (ns == "System") + { + if (name == "Guid") + { + ns = ""; + name = "guid"; + } + } + else if (ns == "Windows.Foundation") + { + if (name == "EventRegistrationToken") + { + ns = ""; + name = "event_token"; + } + else if (name == "HResult") + { + ns = ""; + name = "hresult"; + } + } + else if (ns == "Windows.Foundation.Numerics") + { + if (name == "Matrix3x2") { name = "float3x2"; } + else if (name == "Matrix4x4") { name = "float4x4"; } + else if (name == "Plane") { name = "plane"; } + else if (name == "Quaternion") { name = "quarternion"; } + else if (name == "Vector2") { name = "float2"; } + else if (name == "Vector3") { name = "float3"; } + else if (name == "Vector4") { name = "float4"; } + } + + write("winrt::"); + if (!ns.empty()) + { + write(ns); + write("::"); + } + write(name); + } + + void write(TypeRef const& type) + { + write_namespace_and_type(type.TypeNamespace(), type.TypeName()); + } + + void write(TypeDef const& type) + { + write_namespace_and_type(type.TypeNamespace(), type.TypeName()); + } + + void write(TypeSpec const& type) + { + write(type.Signature().GenericTypeInst()); + } + + void write(coded_index type) + { + switch (type.type()) + { + case TypeDefOrRef::TypeDef: + write(type.TypeDef()); + break; + case TypeDefOrRef::TypeRef: + write(type.TypeRef()); + break; + case TypeDefOrRef::TypeSpec: + write(type.TypeSpec()); + break; + } + } + + void write(GenericTypeInstSig const& type) + { + write(type.GenericType()); + bool first = true; + write("<"); + for (auto&& elem : type.GenericArgs()) + { + if (first) + { + first = false; + } + else + { + write(", "); + } + write(elem); + } + write(">"); + } + + void write(GenericTypeIndex const& var) + { + write(generic_params[var.index]); + } + + void write(GenericMethodTypeIndex const&) + { + // Nothing + } + + void write(TypeSig const& type) + { + std::visit([this](auto&& arg) + { + write(arg); + }, type.Type()); + } }; +std::wstring string_to_wstring(std::string_view const& str) +{ + int const size = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), nullptr, 0); + if (size == 0) + { + return {}; + } + + std::wstring result(size, L'?'); + [[maybe_unused]] auto size_result = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast(str.size()), result.data(), size); + XLANG_ASSERT(size == size_result); + return result; +} + void GetInterfaceData( Microsoft::VisualStudio::Debugger::DkmProcess* process, - coded_index index, + TypeSig const& typeSig, _Inout_ std::vector& propertyData, _Out_ bool& isStringable ){ - auto [type, propIid] = ResolveTypeInterface(process, index); + auto [type, propIid] = ResolveTypeInterface(process, typeSig); + if (!type) { return; @@ -384,106 +647,34 @@ void GetInterfaceData( continue; } - std::optional propCategory; - std::wstring propAbiType; - std::wstring propDisplayType; - - auto retType = method.Signature().ReturnType(); - std::visit(overloaded{ - [&](ElementType type) - { - if ((ElementType::Boolean <= type) && (type <= ElementType::String)) - { - propCategory = (PropertyCategory)(static_cast::type>(type) - - static_cast::type>(ElementType::Boolean)); - } - else if (type == ElementType::Object) - { - //propDisplayType = L"winrt::Windows::Foundation::IInspectable"; - //propCategory = PropertyCategory::Class; - //propAbiType = L"winrt::impl::inspectable_abi*"; - } - }, - [&](coded_index const& index) + std::optional propCategory = GetPropertyCategory(process, typeSig, method.Signature().ReturnType().Type()); + if (propCategory) + { + std::wstring propAbiType; + std::wstring propDisplayType; + if (!IsBuiltIn(*propCategory)) { - auto type = ResolveType(process, index); - if (!type) + writer writer; + if (auto pGenericTypeInst = std::get_if(&typeSig.Type())) { - return; + auto const& genericArgs = pGenericTypeInst->GenericArgs(); + writer.generic_params.assign(genericArgs.first, genericArgs.second); } - - auto typeName = type.TypeName(); - if (typeName == "GUID"sv) + writer.write(method.Signature().ReturnType().Type()); + propDisplayType = string_to_wstring(writer.result); + + if (*propCategory == PropertyCategory::Class) { - propCategory = PropertyCategory::Guid; + propAbiType = L"winrt::impl::inspectable_abi*"; } else { - auto ns = std::string(type.TypeNamespace()); - auto name = std::string(type.TypeName()); - - // Map numeric type names - if (ns == "Windows.Foundation.Numerics") - { - if (name == "Matrix3x2") { name = "float3x2"; } - else if (name == "Matrix4x4") { name = "float4x4"; } - else if (name == "Plane") { name = "plane"; } - else if (name == "Quaternion") { name = "quaternion"; } - else if (name == "Vector2") { name = "float2"; } - else if (name == "Vector3") { name = "float3"; } - else if (name == "Vector4") { name = "float4"; } - } - - // Types come back from winmd files with '.', need to be '::' - // Ex. Windows.Foundation.Uri needs to be Windows::Foundation::Uri - auto fullTypeName = ns + "::" + name; - wchar_t cppTypename[500]; - size_t i, j; - for (i = 0, j = 0; i < (fullTypeName.length() + 1); i++, j++) - { - if (fullTypeName[i] == L'.') - { - cppTypename[j++] = L':'; - cppTypename[j] = L':'; - } - else - { - cppTypename[j] = fullTypeName[i]; - } - } - - propDisplayType = std::wstring(L"winrt::") + cppTypename; - if(get_category(type) == category::class_type) - { - propCategory = PropertyCategory::Class; - propAbiType = L"winrt::impl::inspectable_abi*"; - } - else - { - propCategory = PropertyCategory::Value; - propAbiType = propDisplayType; - } + propAbiType = propDisplayType; } - }, - [&](GenericTypeIndex /*var*/) - { - NatvisDiagnostic(process, L"Generics not yet supported", NatvisDiagnosticLevel::Warning); - }, - [&](GenericMethodTypeIndex /*var*/) - { - NatvisDiagnostic(process, L"Generics not yet supported", NatvisDiagnosticLevel::Warning); - }, - [&](GenericTypeInstSig const& /*type*/) - { - NatvisDiagnostic(process, L"Generics not yet supported", NatvisDiagnosticLevel::Warning); } - }, retType.Type().Type()); - if (propCategory) - { auto propName = method.Name().substr(4); - std::wstring propDisplayName(propName.cbegin(), propName.cend()); - propertyData.push_back({ propIid, propIndex, *propCategory, propAbiType, propDisplayType, propDisplayName }); + propertyData.emplace_back(propIid, propIndex, *propCategory, std::move(propAbiType), std::move(propDisplayType), string_to_wstring(propName)); } } } @@ -492,7 +683,7 @@ void object_visualizer::GetPropertyData() { auto valueHome = make_com_ptr(m_pVisualizedExpression->ValueHome()); com_ptr pObject = valueHome.as(); - auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_isAbiObject); + auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_objectType); if (rc.empty()) { return; @@ -502,10 +693,55 @@ void object_visualizer::GetPropertyData() GetTypeProperties(process, std::string_view{ rc.data() + 2, rc.length() - 3 }); } +GenericTypeInstSig ReplaceGenericIndices(GenericTypeInstSig const& sig, std::vector const& genericArgs) +{ + std::vector replacementArgs; + for (auto&& arg : sig.GenericArgs()) + { + if (auto pGenericSig = std::get_if(&arg.Type())) + { + replacementArgs.emplace_back(ReplaceGenericIndices(*pGenericSig, genericArgs)); + } + else if (auto pGenericIndex = std::get_if(&arg.Type())) + { + replacementArgs.push_back(genericArgs[pGenericIndex->index]); + } + else + { + replacementArgs.push_back(arg); + } + } + return GenericTypeInstSig{ sig.GenericType(), std::move(replacementArgs) }; +} + +TypeSig ExpandInterfaceImplForType(coded_index impl, TypeSig const& type) +{ + if (auto pGenericInst = std::get_if(&type.Type())) + { + if (impl.type() == TypeDefOrRef::TypeSpec) + { + auto const& genericArgs = pGenericInst->GenericArgs(); + auto newSig = ReplaceGenericIndices(impl.TypeSpec().Signature().GenericTypeInst(), std::vector{ genericArgs.first, genericArgs.second }); + return TypeSig{ newSig }; + } + } + return TypeSig{ impl }; +} + void object_visualizer::GetTypeProperties(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& type_name) { // TODO: add support for direct generic interface implementations (e.g., key_value_pair) - auto type = FindType(process, type_name); + auto typeSig = FindType(process, type_name); + TypeDef type{}; + if (auto const* index = std::get_if>(&typeSig.Type())) + { + type = ResolveType(process, *index); + } + else if (auto const* genericInst = std::get_if(&typeSig.Type())) + { + type = ResolveType(process, genericInst->GenericType()); + } + if (!type) { return; @@ -525,7 +761,7 @@ void object_visualizer::GetTypeProperties(Microsoft::VisualStudio::Debugger::Dkm auto impls = type.InterfaceImpl(); for (auto&& impl : impls) { - GetInterfaceData(process, impl.Interface(), m_propertyData, m_isStringable); + GetInterfaceData(process, ExpandInterfaceImplForType(impl.Interface(), typeSig), m_propertyData, m_isStringable); } } else if (get_category(type) == category::interface_type) @@ -533,15 +769,15 @@ void object_visualizer::GetTypeProperties(Microsoft::VisualStudio::Debugger::Dkm auto impls = type.InterfaceImpl(); for (auto&& impl : impls) { - GetInterfaceData(process, impl.Interface(), m_propertyData, m_isStringable); + GetInterfaceData(process, ExpandInterfaceImplForType(impl.Interface(), typeSig), m_propertyData, m_isStringable); } - GetInterfaceData(process, type.coded_index(), m_propertyData, m_isStringable); + GetInterfaceData(process, typeSig, m_propertyData, m_isStringable); } } -HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ DkmEvaluationResult** ppResultObject) +HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ ObjectType objectType, _Deref_out_ DkmEvaluationResult** ppResultObject) { - com_ptr pObjectVisualizer = make_self(pVisualizedExpression, isAbiObject); + com_ptr pObjectVisualizer = make_self(pVisualizedExpression, objectType); IF_FAIL_RET(pVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get())); @@ -582,7 +818,7 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul auto address = pPointerValueHome->Address(); com_ptr pValue; - DkmEvaluationResultFlags_t evalResultFlags = DkmEvaluationResultFlags::ReadOnly; + DkmEvaluationResultFlags_t evalResultFlags = DkmEvaluationResultFlags::ReadOnly | DkmEvaluationResultFlags::Expandable; if (requires_refresh(address, m_pVisualizedExpression->InspectionContext()->EvaluationFlags())) { IF_FAIL_RET(DkmString::Create(L"", pValue.put())); @@ -591,12 +827,7 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul else { cache_refresh(address); - bool unavailable; - IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_isAbiObject, pValue, &unavailable)); - if (!unavailable) - { - evalResultFlags |= DkmEvaluationResultFlags::Expandable; - } + IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_objectType, pValue)); } com_ptr pAddress; @@ -631,11 +862,10 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul } HRESULT object_visualizer::GetChildren( - _In_ UINT32 /*InitialRequestSize*/, + _In_ UINT32 InitialRequestSize, _In_ DkmInspectionContext* pInspectionContext, _Out_ DkmArray* pInitialChildren, - _Deref_out_ DkmEvaluationResultEnumContext** ppEnumContext -) + _Deref_out_ DkmEvaluationResultEnumContext** ppEnumContext) { // Ignore metadata errors to ensure that Raw Data is always available if (m_propertyData.empty()) @@ -667,32 +897,34 @@ HRESULT object_visualizer::GetChildren( this, pEnumContext.put())); - DkmAllocArray(0, pInitialChildren); + IF_FAIL_RET(GetItems(m_pVisualizedExpression.get(), pEnumContext.get(), 0, InitialRequestSize, pInitialChildren)); + *ppEnumContext = pEnumContext.detach(); return S_OK; } HRESULT object_visualizer::GetItems( - _In_ DkmVisualizedExpression* /*pVisualizedExpression*/, + _In_ DkmVisualizedExpression* pVisualizedExpression, _In_ DkmEvaluationResultEnumContext* /*pEnumContext*/, _In_ UINT32 StartIndex, _In_ UINT32 Count, - _Out_ DkmArray* pItems -) + _Out_ DkmArray* pItems) { - std::list> childItems; + CAutoDkmArray resultValues; + IF_FAIL_RET(DkmAllocArray(std::min(m_propertyData.size(), size_t(Count)), &resultValues)); - auto pParent = m_pVisualizedExpression.get(); - for( auto childIndex = StartIndex; childIndex < StartIndex + Count; ++childIndex) + auto pParent = pVisualizedExpression; + auto childCount = std::min(m_propertyData.size() - StartIndex, (size_t)Count); + for(size_t i = 0; i < childCount; ++i) { - auto& prop = m_propertyData[childIndex]; + auto& prop = m_propertyData[i + (size_t)StartIndex]; com_ptr pPropertyVisualized; - if(FAILED(CreateChildVisualizedExpression(prop, pParent, m_isAbiObject, pPropertyVisualized.put()))) + if(FAILED(CreateChildVisualizedExpression(prop, pParent, m_objectType, pPropertyVisualized.put()))) { com_ptr pErrorMessage; IF_FAIL_RET(DkmString::Create(L"", pErrorMessage.put())); - + com_ptr pDisplayName; IF_FAIL_RET(DkmString::Create(prop.displayName.c_str(), pDisplayName.put())); @@ -701,9 +933,9 @@ HRESULT object_visualizer::GetItems( pParent->InspectionContext(), pParent->StackFrame(), pDisplayName.get(), - nullptr, + nullptr, pErrorMessage.get(), - DkmEvaluationResultFlags::ExceptionThrown, + DkmEvaluationResultFlags::ExceptionThrown, DkmDataItem::Null(), pVisualizedResult.put() )); @@ -721,22 +953,9 @@ HRESULT object_visualizer::GetItems( pPropertyVisualized.put() )); } - childItems.push_back(pPropertyVisualized); - } - - CAutoDkmArray resultValues; - IF_FAIL_RET(DkmAllocArray(childItems.size(), &resultValues)); - - UINT32 j = 0; - auto pos = childItems.begin(); - while (pos != childItems.end()) - { - com_ptr pCurr = *pos; - resultValues.Members[j++] = pCurr.detach(); - pos++; + resultValues.Members[i] = pPropertyVisualized.detach(); } *pItems = resultValues.Detach(); - return S_OK; } diff --git a/natvis/object_visualizer.h b/natvis/object_visualizer.h index 2c84a4a94..6d1a0f00c 100644 --- a/natvis/object_visualizer.h +++ b/natvis/object_visualizer.h @@ -20,7 +20,18 @@ enum class PropertyCategory Class, }; -// Metatdata for resolving a runtime class property value +inline constexpr bool IsBuiltIn(PropertyCategory value) noexcept +{ + return PropertyCategory::Bool <= value && value < PropertyCategory::Value; +} + +enum class ObjectType +{ + Abi, + Projection, +}; + +// Metadata for resolving a runtime class property value struct PropertyData { std::wstring iid; @@ -36,17 +47,17 @@ struct PropertyData struct __declspec(uuid("c7da92da-3bc9-4312-8a93-46f480663980")) object_visualizer : winrt::implements { - object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, bool isAbiObject) + object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, ObjectType objectType) { m_pVisualizedExpression = make_com_ptr(pVisualizedExpression); - m_isAbiObject = isAbiObject; + m_objectType = objectType; } ~object_visualizer() { } - static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject); + static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ ObjectType objectType, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject); HRESULT CreateEvaluationResult(_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject); @@ -69,7 +80,7 @@ object_visualizer : winrt::implements void GetPropertyData(); void GetTypeProperties(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& type_name); winrt::com_ptr m_pVisualizedExpression; - bool m_isAbiObject; + ObjectType m_objectType; std::vector m_propertyData; bool m_isStringable{ false }; }; diff --git a/natvis/packages.config b/natvis/packages.config index 356e82f7f..7907cba44 100644 --- a/natvis/packages.config +++ b/natvis/packages.config @@ -2,5 +2,5 @@ - + \ No newline at end of file diff --git a/natvis/pch.h b/natvis/pch.h index c687b1f09..3de6807b3 100644 --- a/natvis/pch.h +++ b/natvis/pch.h @@ -4,11 +4,15 @@ #define NOMINMAX #include +#pragma warning(push) +#pragma warning(disable : 4471) #include +#pragma warning(pop) #include #include #include "base_includes.h" #include "base_macros.h" +#include "base_source_location.h" #include "base_types.h" #include "base_extern.h" #include "base_meta.h" @@ -40,6 +44,7 @@ #include #include #include +#include #ifndef IF_FAIL_RET #define IF_FAIL_RET(expr) { HRESULT _hr = (expr); if(FAILED(_hr)) { return(_hr); } } @@ -88,8 +93,9 @@ inline bool starts_with(std::string_view const& value, std::string_view const& m return 0 == value.compare(0, match.size(), match); } -winmd::reader::TypeDef FindType(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& typeName); -winmd::reader::TypeDef FindType(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& typeNamespace, std::string_view const& typeName); +winmd::reader::TypeDef FindSimpleType(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& typeName); +winmd::reader::TypeDef FindSimpleType(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& typeNamespace, std::string_view const& typeName); +winmd::reader::TypeSig FindType(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& typeName); inline winmd::reader::TypeDef ResolveType(Microsoft::VisualStudio::Debugger::DkmProcess* process, winmd::reader::coded_index index) noexcept { @@ -98,13 +104,13 @@ inline winmd::reader::TypeDef ResolveType(Microsoft::VisualStudio::Debugger::Dkm case winmd::reader::TypeDefOrRef::TypeDef: return index.TypeDef(); case winmd::reader::TypeDefOrRef::TypeRef: - return FindType(process, index.TypeRef().TypeNamespace(), index.TypeRef().TypeName()); + return FindSimpleType(process, index.TypeRef().TypeNamespace(), index.TypeRef().TypeName()); default: //case TypeDefOrRef::TypeSpec: return winmd::reader::find_required(index.TypeSpec().Signature(). GenericTypeInst().GenericType().TypeRef()); } } -std::pair ResolveTypeInterface(Microsoft::VisualStudio::Debugger::DkmProcess* process, winmd::reader::coded_index index); +std::pair ResolveTypeInterface(Microsoft::VisualStudio::Debugger::DkmProcess* process, winmd::reader::TypeSig const& typeSig); void ClearTypeResolver(); diff --git a/natvis/type_resolver.cpp b/natvis/type_resolver.cpp index 17999997f..de8af71f4 100644 --- a/natvis/type_resolver.cpp +++ b/natvis/type_resolver.cpp @@ -98,6 +98,18 @@ struct signature_generator } } + static std::string get_signature(GenericTypeInstSig const& type) + { + std::string sig = "pinterface(" + get_guid_signature(type.GenericType()); + for (auto&& arg : type.GenericArgs()) + { + sig += ";"; + sig += get_signature(arg); + } + sig += ")"; + return sig; + } + private: static std::string get_class_signature(TypeDef const& type) { @@ -152,20 +164,8 @@ struct signature_generator case TypeDefOrRef::TypeRef: return get_guid_signature(find_required(type.TypeRef())); default: //case TypeDefOrRef::TypeSpec: - return get_guid_signature(type.TypeSpec().Signature().GenericTypeInst().GenericType()); - } - } - - static std::string get_signature(GenericTypeInstSig const& type) - { - std::string sig = "pinterface(" + get_guid_signature(type.GenericType()); - for (auto&& arg : type.GenericArgs()) - { - sig += ";"; - sig += get_signature(arg); + return get_signature(type.TypeSpec().Signature().GenericTypeInst()); } - sig += ")"; - return sig; } static std::string get_signature(TypeSig::value_type const& type) @@ -266,7 +266,7 @@ static auto calculate_sha1(std::vector const& input) return get_result(intermediate_hash); } -static guid generate_guid(coded_index const& type) +static guid generate_guid(GenericTypeInstSig const& type) { constexpr guid namespace_guid = { 0xd57af411, 0x737b, 0xc042,{ 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee } }; constexpr auto namespace_bytes = winrt::impl::to_array(namespace_guid); @@ -278,25 +278,38 @@ static guid generate_guid(coded_index const& type) return set_named_guid_fields(endian_swap(to_guid(calculate_sha1(buffer)))); } -std::pair ResolveTypeInterface(DkmProcess* process, coded_index index) +std::pair ResolveTypeInterface(DkmProcess* process, winmd::reader::TypeSig const& typeSig) { - if (auto found = _cache.find(index); found != _cache.end()) + coded_index index; + if (auto ptrIndex = std::get_if>(&typeSig.Type())) { - return found->second; - } + index = *ptrIndex; + // TODO: Cache on the whole TypeSig, not just the generic index + if (auto found = _cache.find(index); found != _cache.end()) + { + return found->second; + } - TypeDef type = ResolveType(process, index); - if (!type) - { - return {}; - } + TypeDef type = ResolveType(process, index); + if (!type) + { + return {}; + } - auto guid = index.type() == TypeDefOrRef::TypeSpec ? - format_guid(generate_guid(index)) : format_guid(get_guid(type)); + auto guid = index.type() == TypeDefOrRef::TypeSpec ? + format_guid(generate_guid(index.TypeSpec().Signature().GenericTypeInst())) : format_guid(get_guid(type)); - auto type_guid = std::pair{ type, guid }; - _cache[index] = type_guid; - return type_guid; + auto type_guid = std::pair{ type, guid }; + _cache[index] = type_guid; + return type_guid; + } + else if (auto* ptrGeneric = std::get_if(&typeSig.Type())) + { + index = ptrGeneric->GenericType(); + auto guid = format_guid(generate_guid(*ptrGeneric)); + return { ResolveType(process, index), guid }; + } + return {}; }; void ClearTypeResolver() diff --git a/nuget.config b/nuget.config new file mode 100644 index 000000000..a7584f8d9 --- /dev/null +++ b/nuget.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/nuget/CppWinrtRules.Project.xml b/nuget/CppWinrtRules.Project.xml index 7f69fcd74..43a712d21 100644 --- a/nuget/CppWinrtRules.Project.xml +++ b/nuget/CppWinrtRules.Project.xml @@ -3,6 +3,7 @@ + @@ -81,9 +82,29 @@ Description="Enables or disables the default for copying binaries to the output folder to be false" Category="General" /> - + + + + + + + + diff --git a/nuget/Microsoft.Windows.CppWinRT.nuspec b/nuget/Microsoft.Windows.CppWinRT.nuspec index a49f1eb8f..52151fc08 100644 --- a/nuget/Microsoft.Windows.CppWinRT.nuspec +++ b/nuget/Microsoft.Windows.CppWinRT.nuspec @@ -2,7 +2,7 @@ Microsoft.Windows.CppWinRT - 1.0.0.0 + $target_version$ C++/WinRT Build Support Microsoft Microsoft @@ -12,6 +12,7 @@ native C++ WinRT nativepackage Š Microsoft Corporation. All rights reserved. LICENSE + readme.md https://github.com/Microsoft/cppwinrt https://aka.ms/cppwinrt.ico @@ -20,11 +21,12 @@ - + + diff --git a/nuget/Microsoft.Windows.CppWinRT.props b/nuget/Microsoft.Windows.CppWinRT.props index d7e2c652c..60736e177 100644 --- a/nuget/Microsoft.Windows.CppWinRT.props +++ b/nuget/Microsoft.Windows.CppWinRT.props @@ -13,7 +13,6 @@ Copyright (C) Microsoft Corporation. All rights reserved. - x64 true true false @@ -43,6 +42,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. nul nul + true + -modules + -module_include $(CppWinRTModuleInclude.Replace(';', ' ')) + $(CppWinRTCommandModuleFilter) -module_exclude $(CppWinRTModuleExclude.Replace(';', ' ')) "$(CppWinRTPackageDir)bin\" "$(CppWinRTPackageDir)" - + true C++ @@ -132,7 +136,7 @@ Copyright (C) Microsoft Corporation. All rights reserved. <_FilesToDelete Include="$(GeneratedFilesDir)**"/> <_FilesToDelete Include="$(CppWinRTMergedDir)**"/> <_FilesToDelete Include="$(CppWinRTUnmergedDir)**"/> - <_FilesToDelete Include="$(CppWinRTProjectWinMD)"/> + <_FilesToDelete Include="$(CppWinRTProjectWinMD)" Condition="'$(CppWinRTGenerateWindowsMetadata)' == 'true'"/> @@ -475,7 +479,10 @@ $(XamlMetaDataProviderPch) <_MidlReferences Include="@(CppWinRTPlatformWinMDReferences)"/> <_MidlReferencesDistinct Remove="@(_MidlReferencesDistinct)" /> <_MidlReferencesDistinct Include="@(_MidlReferences->'%(WinMDPath)'->Distinct())" /> - + + %(Midl.AdditionalOptions) /nomidl + + %(Midl.AdditionalOptions) %40"$(CppWinRTMidlResponseFile)" @@ -648,6 +655,9 @@ $(XamlMetaDataProviderPch) <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) + + <_CppwinrtParameters Condition="'$(_CppWinRTConsumesPlatformModules)'!='true'">$(_CppwinrtParameters) $(CppWinRTCommandModules) $(CppWinRTCommandModuleFilter) <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtInputs->'-in "%(WinMDPath)"', ' ') <_CppwinrtParameters>$(_CppwinrtParameters) -out "$(GeneratedFilesDir)." @@ -726,7 +736,7 @@ $(XamlMetaDataProviderPch) <_CppwinrtRefRefs Include="@(CppWinRTPlatformWinMDReferences)"/> - <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) + <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) $(CppWinRTCommandModules) $(CppWinRTCommandModuleFilter) <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtRefInputs->'-in "%(WinMDPath)"', ' ') <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtRefRefs->'-ref "%(WinMDPath)"', ' ') <_CppwinrtParameters>$(_CppwinrtParameters) -out "$(GeneratedFilesDir)." @@ -832,7 +842,7 @@ $(XamlMetaDataProviderPch) <_CppwinrtCompRefs Include="@(CppWinRTPlatformWinMDReferences)"/> - <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) -overwrite -name $(RootNamespace) $(CppWinRTCommandPrecompiledHeader) $(CppWinRTCommandUsePrefixes) -comp "$(GeneratedFilesDir)sources" + <_CppwinrtParameters>$(CppWinRTCommandVerbosity) $(CppWinRTParameters) $(CppWinRTCommandModules) $(CppWinRTCommandModuleFilter) -overwrite -name $(RootNamespace) $(CppWinRTCommandPrecompiledHeader) $(CppWinRTCommandUsePrefixes) -comp "$(GeneratedFilesDir)sources" <_CppwinrtParameters Condition="'$(CppWinRTOptimized)'=='true'">$(_CppwinrtParameters) -opt <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtCompInputs->'-in "%(WinMDPath)"', ' ') <_CppwinrtParameters>$(_CppwinrtParameters) @(_CppwinrtCompRefs->'-ref "%(WinMDPath)"', ' ') @@ -856,9 +866,11 @@ $(XamlMetaDataProviderPch) + DependsOnTargets="$(CppWinRTAddXamlReferencesDependsOn);CppWinRTGetResolvedWinMD;GetCppWinRTProjectWinMDReferences"> + + @@ -877,13 +889,12 @@ $(XamlMetaDataProviderPch) %(AdditionalOptions) /bigobj - %(AdditionalOptions) /await + %(AdditionalOptions) /await:strict %(AdditionalIncludeDirectories);$(GeneratedFilesDir) $(WindowsSDK_MetadataFoundationPath);%(AdditionalMetadataDirectories) $(WindowsSDK_MetadataPath);%(AdditionalMetadataDirectories) - %(AdditionalOptions) /nomidl %(AdditionalDependencies);WindowsApp.lib @@ -891,4 +902,88 @@ $(XamlMetaDataProviderPch) + + + + + CompileAsCppModule + true + NotUsing + + + + + + + + + $(GeneratedFilesDir) + $(IntDir) + $(OutDir) + + + + + + + + + <_CppWinRTModuleProviders Remove="@(_CppWinRTModuleProviders)" /> + <_CppWinRTModuleProviders Include="@(ProjectReference)" + Condition="'%(ProjectReference.CppWinRTConsumeModule)' == 'true'" /> + + + + + <_CppWinRTConsumesPlatformModules>true + + + + + + + + + + + + + <_CppWinRTModuleIfcSearchDirs>@(_CppWinRTResolvedModuleRefs->'%(CppWinRTModuleIfcDir)') + + + + $(_CppWinRTModuleIfcSearchDirs);%(ClCompile.AdditionalBMIDirectories) + + + + diff --git a/nuget/modules.md b/nuget/modules.md new file mode 100644 index 000000000..4f0eebb95 --- /dev/null +++ b/nuget/modules.md @@ -0,0 +1,524 @@ +# C++/WinRT C++20 Modules Guide + +## Overview + +C++/WinRT can generate per-namespace C++20 named modules (`.ixx` files) alongside the traditional projection headers. This allows you to write: + +```cpp +import winrt.Windows.Foundation; +``` + +instead of: + +```cpp +#include +``` + +Benefits include: + +- **Smaller intermediate artifacts.** The IFC representation of a C++/WinRT projection is significantly smaller than the equivalent precompiled header (PCH). +- **Shared compilation across projects.** PCHs eliminate redundant parsing *within* a project, but each project rebuilds its own PCH. Module IFCs can be built once in a shared module builder project and consumed by all dependent projects, eliminating redundant work across the entire solution. +- **Better isolation.** Module imports don't leak macros into the importing translation unit. + +> **Real-world experience:** The guidance in this document was hardened against a prototype conversion of the Windows Terminal codebase (~250 files across 15+ projects) from textual `#include`s to module imports. + +## Prerequisites + +- **MSVC v145 toolset** (Visual Studio 2026) or later with C++20 module support +- **C++/WinRT 3.x** NuGet package with `CppWinRTBuildModule` support +- `/std:c++20` or later (`/std:c++latest` recommended for `import std;`) +- `BuildStlModules=true` for `import std;` support + +## Three Fundamental Constraints + +These three rules drive almost every pattern in this guide. Understanding them up front makes the rest of the document much easier to follow: + +1. **`import` in a PCH breaks the compiler.** MSVC cannot handle module `import` declarations inside a precompiled header — it produces internal compiler errors (ICE). All module imports must live outside the PCH. + +2. **Include-then-import is safe, but has a cost.** MSVC handles the case where you `#include` a header and then `import` the same content. For STL headers this is a reasonable workaround (the compilation cost is modest), but C++/WinRT projection headers can be extremely expensive to parse textually. Include-then-import with winrt headers defeats the build-cost improvements of adopting modules, so it should be avoided where possible. + +3. **Import-then-include is not supported.** When a module has already been imported, `#include`-ing a header that declares the same types causes errors — the compiler sees conflicting declarations. C++/WinRT provides a workaround: defining `WINRT_IMPORT_MODULE` before including a winrt header causes the header to be (mostly) a no-op, defining only its include-guard macro. This makes it safe to include winrt headers *after* importing modules, which is essential for lighting up header-guard-based features in libraries like WIL, and for interoperating with external code that includes winrt headers out of your control (e.g. the XAML compiler). STL headers do not have an equivalent workaround, but can fall back on the "generally safe" include-then-import pattern. + +The patterns throughout this guide are direct consequences of these constraints: + +- The PCH is stripped of all winrt content. +- A separate "module preamble" header centralizes imports. +- Wrapper headers define `WINRT_IMPORT_MODULE` before including winrt headers. +- STL headers are sometimes pre-included in the PCH, but only as a workaround. + +## Quick Start — Single Project + +For a small project that builds and consumes its own modules: + +1. Set `CppWinRTBuildModule` to `true` in your project: + ```xml + + true + + ``` + +2. Optionally limit which namespaces get modules: + ```xml + + Windows.Foundation;Windows.Storage + + ``` + + By default, C++/WinRT generates and builds `.ixx` files for **every** namespace reachable from your WinMD inputs — for a typical Windows SDK projection, that's hundreds of namespaces and can add upwards of a minute to your build. If build speed matters, prune the set with `CppWinRTModuleInclude` (or `CppWinRTModuleExclude`) so that only the namespaces you actually `import` are produced. See [Understanding the Include and Exclude Filters](#understanding-the-include-and-exclude-filters) for the full discussion. + +3. Enable `BuildStlModules` for `import std;` support: + ```xml + + true + + ``` + +4. In your `.cpp` files: + ```cpp + import winrt.Windows.Foundation; + + int main() { + winrt::init_apartment(); + winrt::Windows::Foundation::Uri uri(L"https://example.com"); + } + ``` + +For a single vcxproj — or a handful of projects that don't share many namespaces — this is all you need. A dedicated module builder is only worth the overhead when multiple projects need the same platform and third-party WinRT modules. + +## Architecture — Module Builder (Recommended for Multi-Project Solutions) + +For solutions with multiple projects, the recommended approach is a dedicated **module builder** project that builds the shared IFC files once, consumed by all other projects. This avoids each project redundantly compiling the same module interfaces. + +### The Module Builder Project + +Create a dedicated static library project whose sole purpose is to build the shared platform module IFC files. This project has no source files of its own — the C++/WinRT NuGet targets generate `.ixx` files automatically. + +```xml + + StaticLibrary + true + true + +``` + +Key configuration: + +- **`CppWinRTBuildModule=true`** generates per-namespace `.ixx` module interface files. +- **`BuildStlModules=true`** is required because the generated `.ixx` files use `import std;`. +- **`WINRT_ENABLE_LEGACY_COM`** — define this preprocessor macro if your project uses classic COM interfaces (`IUnknown`, `IInspectable`). It causes `` and `` to be included within the `winrt_base` module. +- **PCH**: don't bother. The module builder can use a PCH, but there is little benefit — its content is almost entirely C++/WinRT headers, and most non-C++/WinRT headers are only used once in `winrt_base`. + +### Consumer Project Configuration + +Each project that uses modules needs: + +```xml + + true + MyCompany.MyComponent + Microsoft.UI;Microsoft.Web + + + + true + + +``` + +- **`CppWinRTBuildModule=true`** is required on consumers too. It enables the C++/WinRT targets to generate `.ixx` module interface files for the project's own component namespaces (filtered by `CppWinRTModuleInclude` / `CppWinRTModuleExclude`) and wires up module consumption from referenced projects. +- **`CppWinRTConsumeModule=true`** on the `ProjectReference` tells the build system to use the builder's pre-built platform IFCs instead of compiling platform `.ixx` files again, and skip generating platform `.ixx` files in the consumer's own projection. + +### Adding Third-Party WinMDs to the Module Builder + +If your project uses third-party WinRT components (e.g., WinUI/MUX, WebView2), build their modules in the shared builder by adding their WinMDs as platform inputs: + +```xml + + + + + + +``` + +**Important:** Add these WinMDs as `CppWinRTPlatformWinMDReferences`, **not** as NuGet `` items. In practice, adding third-party WinMDs via NuGet `` items on the module builder has been observed to cause empty path errors in the reference projection step. Adding them directly as `CppWinRTPlatformWinMDReferences` feeds them into the platform projection, which is the correct pipeline for a module builder project. + +### Component DLLs + +WinRT component projects can also use modules. Set `CppWinRTBuildModule=true` and all three projections (platform, reference, component) will generate `.ixx` files. + +```xml + + true + MyComponent + + + + true + + +``` + +If project A references a component DLL from project B, project A builds its own reference projection modules from B's `.winmd`: + +```cpp +// These modules are built locally from the component's .winmd +import winrt.MyComponent; + +auto obj = winrt::MyComponent::MyClass(); +``` + +## MSBuild Properties + +| Property | Default | Description | +|-|-|-| +| `CppWinRTBuildModule` | `false` | Generate `.ixx` module interface units from projections | +| `CppWinRTModuleInclude` | (all) | Semicolon-delimited namespace prefixes to include in module generation | +| `CppWinRTModuleExclude` | (none) | Semicolon-delimited namespace prefixes to exclude from module generation | + +| `ProjectReference` Metadata | Default | Description | +|-|-|-| +| `CppWinRTConsumeModule` | `false` | Consume pre-built platform module IFCs from this project reference | + +### Understanding the Include and Exclude Filters + +These filters control which C++/WinRT module `.ixx` files are generated from WinMD inputs. They only affect modules produced by the C++/WinRT NuGet targets from `.winmd` files — hand-authored modules or modules unrelated to WinRT are not affected. + +- **`CppWinRTModuleInclude`** — semicolon-separated namespace prefixes. Only matching namespaces will have `.ixx` files generated. Without this, *all* namespaces from the project's WinMD inputs are candidates. +- **`CppWinRTModuleExclude`** — semicolon-separated namespace prefixes to suppress `.ixx` generation for. **Import statements are still generated** in the modules that remain; only the `.ixx` file creation is suppressed. + +#### Why Filter at All? + +There are three distinct reasons to set these filters. Most non-trivial projects will hit more than one: + +1. **Build performance.** By default, enabling `CppWinRTBuildModule=true` generates and compiles `.ixx` files for *every* namespace reachable from your WinMD inputs. For a typical Windows SDK projection that's hundreds of namespaces, and the IFC compilation step can easily add upwards of a minute to a clean build. Use `CppWinRTModuleInclude` to narrow generation to namespaces you (or your consumers) actually `import`, or `CppWinRTModuleExclude` to drop large subtrees you don't use (e.g., `Windows.Devices`, `Windows.Media`). For a dedicated module builder project that other projects consume, this is typically the dominant reason to filter. + +2. **Avoiding ambiguous IFC errors (C7684).** An IFC is ambiguous when the same module name resolves to two different `.ifc` files — typically one built locally and one from a referenced project. See [When to Set an Exclude for Ambiguity](#when-to-set-an-exclude-for-ambiguity) below. + +3. **Avoiding modules with unsatisfied dependencies.** Filtering to a subset of namespaces does *not* prune the `import` statements those modules emit for their dependencies — so a generated module whose dependencies fall outside your filter will fail to compile. See [Module Filtering and Transitive Dependencies](#module-filtering-and-transitive-dependencies) below. + +#### When to Set an Exclude for Ambiguity + +Exclude a namespace when its IFC is already provided by a project you reference: + +| Scenario | Action | +|----------|--------| +| You reference a **static library** with `CppWinRTBuildModule=true` | Exclude namespaces that static lib produces (its IFCs propagate via `AdditionalBMIDirectories`) | +| You reference a **DLL** with `CppWinRTBuildModule=true` | **No exclude needed** — DLL IFCs don't propagate by default | +| The **module builder** produces a namespace (e.g., `Microsoft.UI`) | Exclude it — the module builder's IFCs propagate via `CppWinRTConsumeModule` | + +Example — a project that references both the module builder (which provides `Microsoft.UI.*`) and a `TerminalCore` static library (which provides `Microsoft.Terminal.Core`): + +```xml +Microsoft.Terminal +Microsoft.Terminal.Core;Microsoft.UI;Microsoft.Web +``` + +### Module Filtering and Transitive Dependencies + +`CppWinRTModuleInclude` and `CppWinRTModuleExclude` control which namespace `.ixx` files are **generated**, but they do not suppress `import` statements for dependencies. If namespace A is included in the filter and depends on namespace B, the generated `winrt.A.ixx` will contain `import winrt.B;` even if B is excluded from the filter. This is by design — the module for B must exist *somewhere* (either from the same project or from a referenced project). + +Implications: + +- **Transitive closure must be satisfied.** If you filter to a subset of namespaces, any dependencies that fall outside the filter must be available from another source (e.g., a module builder project referenced via `CppWinRTConsumeModule`, or MSBuild's automatic `ReferencedModuleBMIs` from a static library reference). Otherwise, compilation will fail with "could not find module" errors. + +- **Use `CppWinRTModuleExclude` to avoid generating modules that have unsatisfied dependencies.** For example, `Windows.Foundation.Diagnostics` depends on `Windows.Storage`. If you filter to `CppWinRTModuleInclude=Windows.Foundation`, the Diagnostics `.ixx` will be generated (it matches the prefix) but will fail to compile because `winrt.Windows.Storage` doesn't exist. Add `CppWinRTModuleExclude=Windows.Foundation.Diagnostics` to prevent this. + +- **In multi-project scenarios with static libraries, use `CppWinRTModuleExclude` to avoid duplicate modules.** MSBuild automatically propagates all module IFCs from static library references to consuming projects (via the `AllProjectBMIsArePublic` property, which defaults to `true` for static libraries). If project A is a static library that builds modules for namespace X, and project B references A, then B already has A's IFCs available. If B also has `CppWinRTBuildModule=true`, its reference projection will generate a second `winrt.X.ixx`, causing an ambiguous module error. Set `CppWinRTModuleExclude=X` on project B to prevent this. B's own `.ixx` files will still emit `import winrt.X;`, which resolves to A's IFC via MSBuild's automatic propagation. Note: this issue does not affect DLL references — MSBuild does not propagate module IFCs from DLLs by default. + +## Module Names + +| Module | Contents | +|-|-| +| `winrt_base` | Core C++/WinRT types (`hstring`, `com_ptr`, `IUnknown`, etc.) — re-exported by all namespace modules | +| `winrt_numerics` | `Windows::Foundation::Numerics` types — re-exported by `winrt_base` | +| `winrt.` | Per-namespace projection (e.g., `winrt.Windows.Foundation`) | + +## Converting an Existing Project: Step by Step + +### 1. Strip winrt from the PCH + +Module `import` declarations inside a precompiled header cause compiler ICEs. All C++/WinRT content must be moved out of the PCH and into the module preamble header (see next step). + +Remove the following from your PCH: + +- `#include ` — all winrt projection headers +- `#include ` and `` +- Any header that depends on C++/WinRT types, **including headers that conditionally enable behavior based on C++/WinRT header guards.** For example, `wil/cppwinrt_helpers.h` checks for `WINRT_Windows_UI_Core_H` and uses types from `Windows.UI.Core` when defined — this header must move out of the PCH. + +**Keep** in the PCH: + +- Platform SDK headers (``, ``, etc.) +- Non-winrt third-party headers + +**STL headers and `import std;`** — STL headers are safe to include *before* `import std;` (include-then-import works). Problems arise when STL headers are included *after* `import std;`, which can cause redefinition warnings (C4348, C5028). In most cases it is preferable to use `import std;` instead of putting STL headers in the PCH. However, if you depend on libraries that internally `#include` STL headers *after* modules have been imported, you may need to pre-include the offending STL headers in the PCH to make the later inclusion inert: + +```cpp +// Pre-include STL headers that other libraries include after import std; +#include +#include +``` + +Ideally, the offending library code would also adopt `import std;`, but that's not always immediately practical. + +### 2. Create a Module Preamble Header + +A module preamble header centralizes the module imports and library setup that are shared across a project's source files. It is not strictly required — you could add imports directly to each `.cpp` file — but it speeds up migration significantly and becomes necessary if you need to deal with generated files outside your control (see [XAML Projects](#xaml-projects)). + +Create a preamble header in each project that contains the module imports commonly used across that project: + +```cpp +// ModulePreamble.h (or whatever name you prefer) +#pragma once + +#define WINRT_IMPORT_MODULE + +// Import the C++/WinRT namespaces used across this project +import winrt.Windows.Foundation; +import winrt.Windows.Foundation.Collections; +import winrt.Windows.System; +// ... other namespaces your project needs + +// Component modules +import winrt.MyCompany.MyComponent; +``` + +Importing modules is cheap, so don't hesitate to list every namespace the project uses. You can add library wrapper headers and other setup to this file as needed (see next section). + +Include the preamble in each `.cpp` file after the PCH: + +```cpp +#include "pch.h" +#include "ModulePreamble.h" +// ... rest of the file +``` + +### 3. Wrap Library Headers That Depend on C++/WinRT Types + +Libraries like WIL use `#ifdef WINRT_Windows_Foundation_H` guards to conditionally enable winrt-dependent features. With modules, those header guards are never defined because the winrt headers are never textually included. To light up this behavior, define the appropriate header guards before including the library header — or, equivalently, include the now-inert winrt headers under `WINRT_IMPORT_MODULE`, which defines the guards as a side effect. + +You can do this directly in the module preamble: + +```cpp +// In your module preamble header +import winrt.Windows.Foundation; +#define WINRT_IMPORT_MODULE +#define WINRT_Windows_Foundation_H // Lights up WIL's Foundation support +#include +``` + +If you include the library from many places, you can author a **wrapper header** that bundles the imports, guard definitions, and library include together: + +```cpp +// wil_cppwinrt_module.h +#pragma once + +import winrt_base; +import winrt.Windows.Foundation; +import winrt.Windows.Foundation.Collections; + +#define WINRT_IMPORT_MODULE +// Define header guards to light up WIL's conditional winrt features. +// You can either define the guards directly, or include the now-inert +// winrt headers (which define the guards as a side effect): +#include +#include + +#include +#include +``` + +Include this wrapper in your module preamble as needed. Re-importing modules and re-defining header guards is harmless, so there's no issue with including the wrapper from multiple places. + +This pattern applies to any library that conditionally uses winrt types based on header include guards. + +### 4. Update the vcxproj + +```xml + +true +MyCompany.MyComponent +Microsoft.UI;Microsoft.Web + + + + true + +``` + +### 5. Add Solution Build Dependency + +If using `.slnx` or `.sln`, add a build dependency to ensure the module builder, if using, compiles first: + +```xml + +``` + +## Special Cases + +### XAML Projects + +XAML projects have a two-pass compilation model that complicates module adoption. The XAML compiler generates source files (`XamlTypeInfo.g.cpp`, `XamlTypeInfo.Impl.g.cpp`, `XamlMetaDataProvider.cpp`) that use winrt types but don't know about modules. + +The solution is to inject `ModulePreamble.h` via the `/FI` (forced include) compiler flag on these generated files, using MSBuild targets: + +```xml + + + + + NotUsing + $(MSBuildProjectDirectory)\ModulePreamble.h + + + +``` + +For static library projects, the XAML build system has a second compilation pass (`CompileXamlGeneratedFiles`) that runs after `ClCompile` but before `Lib`. For DLLs and EXEs, the same targets run after the build compile phase. In either case, you need a second target to ensure the `/FI` metadata is applied before `CompileXamlGeneratedFiles`: + +```xml + + + + NotUsing + $(MSBuildProjectDirectory)\ModulePreamble.h + + + +``` + +**Critical MSBuild detail:** Use ``, not just ``. Without `Update`, MSBuild adds new items instead of modifying metadata on existing ones. + +**Why the preamble header needs `#include "pch.h"` for XAML:** When used as `/FI`, the preamble header is processed *before* the generated file's own `#include "pch.h"`. Adding `#include "pch.h"` at the top of the preamble ensures platform headers are available. For regular `.cpp` files that already include pch.h before the preamble, it's a `#pragma once` no-op. If your project doesn't use the `/FI` approach for XAML, you don't need pch.h in the preamble. + +#### Understanding the XAML Build Order + +The XAML build targets schedule `MarkupCompilePass2` and `CompileXamlGeneratedFiles` differently depending on project type: + +- **Static libraries** (`AfterClCompileTargets`): Pass2 runs after `ClCompile`, before `Lib` +- **DLLs/EXEs** (`AfterBuildCompileTargets`): Pass2 runs after the build compile phase, before `Link` + +In both cases, the order is: + +1. **MarkupCompilePass1** (before `ClCompile`): Generates `.xaml.g.h` declarations +2. **ClCompile**: Compiles your source files +3. **MarkupCompilePass2**: Generates `.xaml.g.hpp` implementations +4. **CompileXamlGeneratedFiles**: Compiles `XamlTypeInfo.g.cpp` (which `#include`s the `.xaml.g.hpp` files) + +The XAML-generated items (`XamlTypeInfo.g.cpp`, etc.) are added to `ClCompile` by the `ComputeXamlGeneratedCompileInputs` target, which is why the `/FI` target uses `AfterTargets="ComputeXamlGeneratedCompileInputs"`. + +### Headers with Conditional winrt Conversions + +If you have utility types (like a `color` struct) with conversion operators gated behind winrt header guards: + +```cpp +#ifdef WINRT_Windows_UI_H + operator winrt::Windows::UI::Color() const { ... } +#endif +``` + +These guards must be defined **before** the header is first included (`#pragma once` means it won't be processed again). Create a dedicated wrapper that imports the module, sets the guard, then re-includes the header: + +```cpp +// color_module.h +#pragma once +import winrt.Windows.UI; +#define WINRT_IMPORT_MODULE +#include // Sets WINRT_Windows_UI_H +#include // Now sees the guard, enables converters +``` + +Include this wrapper in your `ModulePreamble.h` **before** any other header that might include the guarded file. + +### Win32 Macro Conflicts + +Some Win32 macros (e.g., `GetObject` from `wingdi.h`) conflict with WinRT method names. With headers, the macro was applied to both the projection types and the call site. With modules, the WinRT types don't have the macro applied (they were compiled in the module without the macro), but your source file still has the macro defined. Use: + +```cpp +#pragma push_macro("GetObject") +#undef GetObject +// ... code using winrt types with GetObject method +#pragma pop_macro("GetObject") +``` + +## Caution: Module Reuse Across Projects + +Pre-built IFCs (via `CppWinRTConsumeModule`) should only be shared when the builder and consumer use the same compilation context. In particular: + +- **Component modules are project-private.** A component projection built with `CppWinRTOptimized=true` generates modules that bypass activation factories for in-component type instantiation (`-opt`). If a consuming project accidentally imports these modules instead of building its own reference projection, the consumer will attempt direct instantiation across DLL boundaries, resulting in linker errors or incorrect behavior. Each project should build its own modules from the component's `.winmd` — do not tag component `ProjectReference`s with `CppWinRTConsumeModule`. + +- **`CppWinRTConsumeModule` is intended for platform module builders only.** The builder project is a dedicated static library whose sole purpose is compiling platform SDK modules. Its compilation flags (no `-opt`, no `-comp`) produce modules safe for any consumer. Only tag this builder's `ProjectReference` with `CppWinRTConsumeModule=true`. + +- **Module filter scope matters.** `CppWinRTModuleInclude` / `CppWinRTModuleExclude` applies to all three projections (platform, reference, component). If you set `CppWinRTModuleInclude=MyComponent`, only `MyComponent` namespaces will get `.ixx` files — platform and reference namespace modules will not be generated. Make sure your filter includes all namespaces you intend to import as modules, or use `CppWinRTConsumeModule` to get platform modules from a builder that was configured with the appropriate filter. + +- **Compilation settings must be compatible between builder and consumer.** Module IFCs encode assumptions about the compilation environment. While the compiler may not always diagnose mismatches, the following differences between the module builder and consumer may cause subtle or hard-to-diagnose issues: + - **Debug vs Release** — mixing Debug and Release configurations can produce mismatched code generation, iterator debugging levels, and runtime library selections. + - **Preprocessor definitions** — definitions that affect type layout, conditional compilation, or feature flags should match between builder and consumer. + - **Struct alignment / packing** — different `/Zp` settings between projects can change struct layout, causing silent ABI mismatches. + - **Language standard** — while C++20 and later are generally compatible, mixing `/std:c++20` and `/std:c++23` and/or `/std:c++latest` can affect type definitions if language features differ. + + As a general rule, the module builder project should try to use the same configuration, preprocessor definitions, and compiler options as its consumers. + +## Limitations + +- Module IFCs are not compatible across toolset versions. All projects must use the same toolset. +- Cyclic namespace dependencies (e.g., `Windows.Foundation` ↔ `Windows.Foundation.Collections`) are handled automatically via SCC consolidation, but the resulting module name is chosen alphabetically. Adding new APIs could change SCC groupings. + +## Common Errors and Solutions + +| Error | Cause | Solution | +|-------|-------|----------| +| **C2230**: could not find module `winrt.X` | Missing import or the module IFC wasn't built | Add the import; verify the module builder or consumer produces it; check `CppWinRTModuleInclude` | +| **C7684**: ambiguous resolution to IFC | Same module built by multiple projects visible to the consumer | Add the namespace to `CppWinRTModuleExclude` | +| **C4348**: redefinition of default parameter | STL header included after `import std;` | Pre-include the STL header in the PCH (e.g., `#include `) | +| **C5028**: alignment specified in prior declaration | Same root cause as C4348 | Pre-include the STL header (e.g., `#include `) | +| **C4430 / C2039**: missing type / not a member | Type not visible because module not imported | Add the missing `import winrt.Namespace;` to ModulePreamble | +| **LNK2019**: unresolved external for `InitializeComponent` | XAML-generated code compiled without module imports | Ensure the `/FI` targets are present and use `Update="@(ClCompile)"` | +| **LNK2005**: symbol already defined | XAML-generated file compiled both directly and via a wrapper | Use the `/FI` injection approach instead of wrapper `.cpp` files | +| Redefinition errors when mixing `#include` and `import` | Same namespace included textually after being imported | Define `WINRT_IMPORT_MODULE` before the winrt header, or remove the `#include` | +| **"could not find module 'winrt.X'"** in cross-project consumer | Builder's `IntDir` not visible to consumer | Verify `ProjectReference` to the builder has `CppWinRTConsumeModule=true` | +| Linker errors for component constructors | Importing a component's internal module instead of building your own reference projection | Remove explicit `/reference` flags for component IFCs and ensure your project has `CppWinRTBuildModule=true` so it builds reference projection modules from the component's `.winmd` | + +## Tips + +- **Clean build after configuration changes.** Stale IFC files from previous builds cause confusing ambiguity errors. Clean the intermediate directory when changing module include/exclude filters. +- **Start from leaf projects.** Convert projects with no WinRT component dependencies first (e.g., utility libraries), then work up the dependency graph. +- **One project at a time.** Each conversion may surface new missing imports or exclude requirements. Building incrementally makes errors easier to diagnose. +- **Watch for transitive IFC propagation.** Static library IFCs become visible to all consumers in the reference chain. This is correct behavior but requires `CppWinRTModuleExclude` entries in consumers. +- **`CppWinRTModuleInclude` is usually needed.** Without it, projects with `CppWinRTModuleExclude` may not generate any `.ixx` files at all. Specify the namespace prefix for your component (e.g., `Microsoft.Terminal`). +- **DLL wrapper projects typically need no changes.** If you have a pattern of "static lib + thin DLL wrapper", the DLL wrapper usually just links the lib and doesn't need module conversion. + +## Approaches Tried and Abandoned + +For posterity, these patterns were attempted during the Terminal prototype but proved problematic. Avoid them. + +### Wrapper `.module.cpp` files for XAML-generated code + +The idea was to create wrapper `.cpp` files that would `#include` the XAML-generated files after setting up module imports, then remove the original generated items from `ClCompile` and replace them with the wrappers. + +**Why it failed:** The XAML build system generates files across two compilation passes. `XamlTypeInfo.g.cpp` `#include`s `.xaml.g.hpp` files that don't exist until Pass2, but the wrapper needed to compile during the first `ClCompile` pass. `__has_include` guards to make wrappers compile empty initially and recompile later proved unreliable — `CompileXamlGeneratedFiles` is a separate compilation step, and the wrapper items weren't correctly routed through it. + +**The `/FI` approach works** because it modifies the compiler flags on the *existing* generated items rather than replacing them, working with the XAML build system's two-pass compilation. + +### `AllProjectBMIsArePublic=false` on static libraries + +The idea was to prevent IFC propagation from static libraries by setting `AllProjectBMIsArePublic=false`, hiding the static lib's IFCs from consumers. + +**Why we moved away:** This fights against the intended VC++ build model. If a project consumes a static library, it should also consume that library's IFC files. Using different IFCs for the same types risks ODR violations. The `CppWinRTModuleExclude` approach is better — the consumer avoids building duplicate IFCs while still consuming the producer's IFCs. + +### Moving wrapper items into MSBuild targets + +The idea was to add wrapper `.cpp` `ClCompile` items inside a `` (dynamically) instead of a static ``, so they'd only enter `ClCompile` after generated files existed. + +**Why it failed:** Items added inside targets don't get the same metadata processing (module dependency scanning, IFC reference resolution) as items in static `ItemGroup`s. The compiler couldn't find any modules. diff --git a/nuget/readme.md b/nuget/readme.md index 566a4fd18..16eb5d2bb 100644 --- a/nuget/readme.md +++ b/nuget/readme.md @@ -41,7 +41,7 @@ It sets the following project properties and item metadata: | Link.AdditionalDependencies | WindowsApp.lib | Umbrella library for Windows Runtime imports | | Midl.AdditionalOptions | /reference ... | Enables faster compilation with winmd references (versus idl imports) | | Midl.EnableWindowsRuntime | true | Enables Windows Runtime semantics | -| Midl.MetadataFileName | Unmerged\%(Filename).winmd | Generates unmerged metadata in a tempoary location | +| Midl.MetadataFileName | Unmerged\%(Filename).winmd | Generates unmerged metadata in a temporary location | | Midl.GenerateClientFiles, GenerateServerFiles, GenerateStublessProxies, GenerateTypeLibrary, HeaderFileName, DllDataFileName, InterfaceIdentifierFileName, ProxyFileName, TypeLibraryName | *nul, *None, *false | Disable unnecessary output | \*If not already set @@ -70,6 +70,9 @@ C++/WinRT behavior can be customized with these project properties: | CppWinRTOptimized | true \| *false | Enables component projection [optimization features](https://kennykerr.ca/2019/06/07/cppwinrt-optimizing-components/) | | CppWinRTGenerateWindowsMetadata | true \| *false | Indicates whether this project produces Windows Metadata | | CppWinRTEnableDefaultPrivateFalse | true \| *false | Indicates whether this project uses C++/WinRT optimized default for copying binaries to the output directory | +| CppWinRTBuildModule | true \| *false | Generates per-namespace C++20 module interface units (.ixx) alongside projection headers | +| CppWinRTModuleInclude | namespace list | Semicolon-delimited namespaces to include in module generation (default: all) | +| CppWinRTModuleExclude | namespace list | Semicolon-delimited namespaces to exclude from module generation | \*Default value To customize common C++/WinRT project properties: @@ -77,6 +80,72 @@ To customize common C++/WinRT project properties: * expand the Common Properties item * select the C++/WinRT property page +## InitializeComponent + +In older versions of C++/WinRT, Xaml objects called InitializeComponent from constructors. This can lead to memory corruption if InitializeComponent throws an exception. + +```cpp +void MainPage::MainPage() +{ + // This pattern should no longer be used + InitializeComponent(); +} +``` + +C++/WinRT now calls InitializeComponent automatically and safely, after object construction. Explicit calls to InitializeComponent from constructors in existing code should now be removed. Multiple calls to InitializeComponent are idempotent. + +If a Xaml object needs to access a Xaml property during initialization, it should override InitializeComponent: + +```cpp +void MainPage::InitializeComponent() +{ + // Call base InitializeComponent() to register with the Xaml runtime + MainPageT::InitializeComponent(); + // Can now access Xaml properties + MyButton().Content(box_value(L"Click")); +} +``` + +A non-Xaml object can also participate in two-phase construction by defining an InitializeComponent method. + +```cpp +void MyComponent::InitializeComponent() +{ + // Execute initialization logic that may throw +} +``` + +***[Windows|Microsoft]::UI::Xaml::Markup::ComponentConnectorT*** + +A consequence of calling InitializeComponent outside construction is that Xaml runtime callbacks to IComponentConnector::Connect and IComponentConnector2::GetBindingConnector are now dispatched to the most derived implementations. Previously, these calls were dispatched directly to the class under construction, as the vtable had yet to be initialized. For objects with markup that derive from composable base classes with markup, this is a breaking change. Derived classes must now implement IComponentConnector::Connect and IComponentConnector2::GetBindingConnector by explicitly calling into the base class. The ComponentConnectorT template provides a correct implementation for these interfaces: + +```cpp +struct DerivedPage : winrt::Windows::UI::Xaml::Markup::ComponentConnectorT> +``` + +If overriding DerivedPage::InitializeComponent, ComponentConnectorT::InitializeComponent should be called instead of DerivedPageT::InitializeComponent: + +```cpp +void DerivedPage::InitializeComponent() +{ + // Call base InitializeComponent() to register with the Xaml runtime + ComponentConnectorT::InitializeComponent(); + // Can now access Xaml properties from base or derived class + MyBaseButton().Content(box_value(L"Click")); +} +``` + +## C++20 Modules + +C++/WinRT supports C++20 named modules as an alternative to `#include`-based consumption. Instead of `#include `, you can write `import winrt.Windows.Foundation;`. + +See the [C++/WinRT C++20 Modules Guide](https://github.com/microsoft/cppwinrt/blob/master/nuget/modules.md) for the full guide (also shipped alongside this file as `modules.md`). + +| ProjectReference metadata | Description | +|-|-| +| CppWinRTConsumeModule | true \| *false | When set on a ProjectReference, consumes pre-built platform module IFCs from the referenced project | +\*Default value + ## Troubleshooting The msbuild verbosity level maps to msbuild message importance as follows: @@ -92,7 +161,7 @@ For example, if the verbosity is set to minimal, then only messages with high im The default importance of C++/WinRT build messages is 'normal', but this can be overridden with the CppWinRTVerbosity property to enable throttling of C++/WinRT messages independent of the overall verbosity level. Example: -> msbuild project.vcxproj /vebosity:minimal /property:CppWinRTVerbosity=high ... +> msbuild project.vcxproj /verbosity:minimal /property:CppWinRTVerbosity=high ... For more complex analysis of build errors, the [MSBuild Binary and Structured Log Viewer](http://msbuildlog.com/) is highly recommended. diff --git a/nuget/readme.txt b/nuget/readme.txt index 049ab13b8..8d2681b6b 100644 --- a/nuget/readme.txt +++ b/nuget/readme.txt @@ -19,4 +19,7 @@ In addition, C++/WinRT generates templates and skeleton implementations for each ======================================================================== For more information, visit: https://github.com/Microsoft/cppwinrt/tree/master/nuget + +The full documentation is also included in this package as readme.md, and +the C++20 modules guide as modules.md. ======================================================================== diff --git a/prebuild/CMakeLists.txt b/prebuild/CMakeLists.txt new file mode 100644 index 000000000..da2162d44 --- /dev/null +++ b/prebuild/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.16) + +project(cppwinrt-prebuild LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +if(NOT DEFINED CPPWINRT_BUILD_VERSION) + message(FATAL_ERROR "CPPWINRT_BUILD_VERSION has not been defined. You should build the top-level project instead.") +endif() + + +set(PREBUILD_SRCS + main.cpp + pch.h +) +add_executable(cppwinrt-prebuild ${PREBUILD_SRCS}) +target_compile_definitions(cppwinrt-prebuild PRIVATE CPPWINRT_VERSION_STRING="${CPPWINRT_BUILD_VERSION}") +target_include_directories(cppwinrt-prebuild PRIVATE ../cppwinrt/) + +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + install(TARGETS cppwinrt-prebuild) +endif() diff --git a/prebuild/main.cpp b/prebuild/main.cpp index d446c02d4..1295f8f69 100644 --- a/prebuild/main.cpp +++ b/prebuild/main.cpp @@ -19,9 +19,11 @@ int main(int const argc, char** argv) strings_h.write(R"( #pragma once namespace cppwinrt::strings { +extern "C++" { )"); strings_cpp.write(R"( +#include "strings.h" namespace cppwinrt::strings { )"); @@ -41,7 +43,7 @@ namespace cppwinrt::strings { strings_h.write(R"(extern char const %[%]; )", name.string(), - static_cast(view.size())); + static_cast(view.size() + 1)); strings_cpp.write(R"(extern char const %[] = R"xyz()xyz" )", @@ -49,7 +51,7 @@ namespace cppwinrt::strings { std::string_view remainder = view; - while (remainder.size()) + while (!remainder.empty()) { auto const size = std::min(size_t{ 16'000 }, remainder.size()); auto const chunk = remainder.substr(0, size); @@ -66,6 +68,7 @@ namespace cppwinrt::strings { strings_h.write(R"( } +} )"); strings_cpp.write(R"( @@ -74,12 +77,19 @@ namespace cppwinrt::strings { writer version_rc; + // Extract major.minor substrings from CPPWINRT_VERSION_STRING (e.g. "3.0.250316.1") + std::string_view const full_version{ CPPWINRT_VERSION_STRING }; + auto const first_dot = full_version.find('.'); + auto const second_dot = full_version.find('.', first_dot + 1); + auto const ver_major = full_version.substr(0, first_dot); + auto const ver_minor = full_version.substr(first_dot + 1, second_dot - first_dot - 1); + version_rc.write(R"( #include "winres.h" VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,0,0,0 - PRODUCTVERSION 2,0,0,0 + FILEVERSION %,%,0,0 + PRODUCTVERSION %,%,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -96,7 +106,7 @@ BEGIN BEGIN VALUE "CompanyName", "Microsoft Corporation" VALUE "FileDescription", "C++/WinRT" - VALUE "FileVersion", "2.0.0.0" + VALUE "FileVersion", "%.%.0.0" VALUE "LegalCopyright", "Microsoft Corporation. All rights reserved." VALUE "OriginalFilename", "cppwinrt.exe" VALUE "ProductName", "C++/WinRT" @@ -109,7 +119,10 @@ BEGIN END END )", - CPPWINRT_VERSION_STRING); + ver_major, ver_minor, // FILEVERSION + ver_major, ver_minor, // PRODUCTVERSION + ver_major, ver_minor, // FileVersion string + CPPWINRT_VERSION_STRING); // ProductVersion string std::filesystem::create_directories(argv[2]); auto const output = std::filesystem::canonical(argv[2]); diff --git a/prebuild/prebuild.vcxproj b/prebuild/prebuild.vcxproj index 92df71b65..9fad91fd8 100644 --- a/prebuild/prebuild.vcxproj +++ b/prebuild/prebuild.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -38,17 +30,12 @@ 15.0 {FB239623-7D19-4025-BCEA-B43298D4A315} cppwinrt - 10.0 - + Application true - - Application - true - Application true @@ -58,11 +45,6 @@ false true - - Application - false - true - Application false @@ -85,18 +67,12 @@ - - - - - - @@ -107,35 +83,13 @@ - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - Disabled ..\cppwinrt MultiThreadedDebug - - - Console - - - - - Disabled - ..\cppwinrt - MultiThreadedDebug + Level4 + true Console @@ -146,6 +100,8 @@ Disabled ..\cppwinrt MultiThreadedDebug + Level4 + true Console @@ -156,6 +112,8 @@ Disabled ..\cppwinrt MultiThreadedDebug + Level4 + true Console @@ -168,20 +126,9 @@ true ..\cppwinrt MultiThreaded - - - Console - true - true - - - - - MaxSpeed - true - true - ..\cppwinrt - MultiThreaded + Guard + Level4 + true Console @@ -196,6 +143,9 @@ true ..\cppwinrt MultiThreaded + Guard + Level4 + true Console @@ -210,6 +160,9 @@ true ..\cppwinrt MultiThreaded + Guard + Level4 + true Console diff --git a/prepare_versionless_diffs.cmd b/prepare_versionless_diffs.cmd new file mode 100644 index 000000000..05cb6dd0b --- /dev/null +++ b/prepare_versionless_diffs.cmd @@ -0,0 +1,40 @@ +@echo off + +setlocal ENABLEDELAYEDEXPANSION + +set target_platform=%1 +set target_configuration=%2 +if "%target_platform%"=="" set target_platform=x64 + +if /I "%target_platform%" equ "all" ( + if "%target_configuration%"=="" ( + set target_configuration=all + ) + call %0 x86 !target_configuration! + call %0 x64 !target_configuration! + call %0 arm64 !target_configuration! + goto :eof +) + +if /I "%target_configuration%" equ "all" ( + call %0 %target_platform% Debug + call %0 %target_platform% Release + goto :eof +) + +if "%target_configuration%"=="" ( + set target_configuration=Debug +) + +set reference_output=%~p0\_reference\%target_platform%\%target_configuration% +set build_output=%~p0\_build\%target_platform%\%target_configuration% + +echo Removing version stamps from %reference_output%\winrt +pushd %reference_output%\winrt +powershell -Command "gci -r -include *.h,*.ixx | %%{ (get-content $_) -replace 'was generated by.*|CPPWINRT_VERSION.*','' | set-content $_ }" +popd + +echo Removing version stamps from %build_output%\winrt +pushd %build_output%\winrt +powershell -Command "gci -r -include *.h,*.ixx | %%{ (get-content $_) -replace 'was generated by.*|CPPWINRT_VERSION.*','' | set-content $_ }" +popd diff --git a/run_tests.cmd b/run_tests.cmd index 86ec520e1..58e3c5524 100644 --- a/run_tests.cmd +++ b/run_tests.cmd @@ -9,8 +9,9 @@ if "%target_platform%"=="" set target_platform=x64 if "%target_configuration%"=="" set target_configuration=Debug call :run_test test +call :run_test test_nocoro call :run_test test_cpp20 -call :run_test test_win7 +call :run_test test_cpp20_no_sourcelocation call :run_test test_fast call :run_test test_slow call :run_test test_old @@ -21,5 +22,11 @@ goto :eof :run_test if not "%target_version%"=="" set args=-o %1-%target_version%.xml -r junit rem Buffer output and redirect to stdout/stderr depending whether the test executable exits successfully. Pipeline will fail if there's any output to stderr. -_build\%target_platform%\%target_configuration%\%1.exe %args% > %1_results.txt && type %1_results.txt || type %1_results.txt >&2 +_build\%target_platform%\%target_configuration%\%1.exe %args% > %1_results.txt +if %ERRORLEVEL% EQU 0 ( + type %1_results.txt +) else ( + type %1_results.txt >&2 + echo %1 >> test_failures.txt +) goto :eof diff --git a/scratch/scratch.vcxproj b/scratch/scratch.vcxproj index 237ca4eeb..84f6ce3d8 100644 --- a/scratch/scratch.vcxproj +++ b/scratch/scratch.vcxproj @@ -1,10 +1,7 @@ + - - Debug - ARM - Debug ARM64 @@ -13,10 +10,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -35,292 +28,69 @@ + true + true + true + true 16.0 {E893622C-47DE-4F83-B422-0A26711590A4} scratch scratch - 10.0 - - - - Application - true - - - Application - true - - - Application - true - - Application - false - true - - - Application - false - true - - - Application - false - true + + ..\_build\$(Platform)\$(Configuration) + false - - Application + + true - - Application + false true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..\..\..\library - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - %(AdditionalOptions) - MultiThreaded - - - Console - true - true - - - - - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\..\..\library - _MBCS;%(PreprocessorDefinitions) - %(AdditionalOptions) - MultiThreadedDebug - - - Console - - - - - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\..\..\library - _MBCS;%(PreprocessorDefinitions) - %(AdditionalOptions) - MultiThreadedDebug - - - Console - - - - - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\..\..\library - _MBCS;%(PreprocessorDefinitions) - %(AdditionalOptions) - MultiThreadedDebug - - - Console - - - - - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\..\..\library - _MBCS;%(PreprocessorDefinitions) - %(AdditionalOptions) - MultiThreadedDebug - - - Console - - - - - - - - - - - + - MaxSpeed - true - true - $(OutputPath);Generated Files;..\..\..\library - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - %(AdditionalOptions) - MultiThreaded + $(OutputPath);Generated Files; + Level4 + true Console - true - true - - - - - - - - - + MaxSpeed true true - $(OutputPath);Generated Files;..\..\..\library NOMINMAX;_MBCS;%(PreprocessorDefinitions) - %(AdditionalOptions) MultiThreaded - Console true true - - - - - - - - - + - MaxSpeed - true - true - $(OutputPath);Generated Files;..\..\..\library - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - %(AdditionalOptions) - MultiThreaded + Disabled + _MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug - - Console - true - true - - - - - - - - - - NotUsing - Use - Use - Use - Use - Use - Use - Use - Use + Use - Create - Create - Create - Create - Create - Create - Create - Create + Create + + + diff --git a/strings/base_abi.h b/strings/base_abi.h index b14e8d85f..4b7b8f77f 100644 --- a/strings/base_abi.h +++ b/strings/base_abi.h @@ -1,13 +1,13 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template <> struct abi { - struct __declspec(novtable) type + struct WINRT_IMPL_ABI_DECL type { - virtual int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; - virtual uint32_t __stdcall AddRef() noexcept = 0; - virtual uint32_t __stdcall Release() noexcept = 0; + virtual std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; + virtual std::uint32_t __stdcall AddRef() noexcept = 0; + virtual std::uint32_t __stdcall Release() noexcept = 0; }; }; @@ -15,11 +15,11 @@ namespace winrt::impl template <> struct abi { - struct __declspec(novtable) type : unknown_abi + struct WINRT_IMPL_ABI_DECL type : unknown_abi { - virtual int32_t __stdcall GetIids(uint32_t* count, guid** ids) noexcept = 0; - virtual int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; - virtual int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* level) noexcept = 0; + virtual std::int32_t __stdcall GetIids(std::uint32_t* count, guid** ids) noexcept = 0; + virtual std::int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; + virtual std::int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* level) noexcept = 0; }; }; @@ -27,119 +27,119 @@ namespace winrt::impl template <> struct abi { - struct __declspec(novtable) type : inspectable_abi + struct WINRT_IMPL_ABI_DECL type : inspectable_abi { - virtual int32_t __stdcall ActivateInstance(void** instance) noexcept = 0; + virtual std::int32_t __stdcall ActivateInstance(void** instance) noexcept = 0; }; }; - struct __declspec(novtable) IAgileObject : unknown_abi {}; + struct WINRT_IMPL_ABI_DECL IAgileObject : unknown_abi {}; - struct __declspec(novtable) IAgileReference : unknown_abi + struct WINRT_IMPL_ABI_DECL IAgileReference : unknown_abi { - virtual int32_t __stdcall Resolve(guid const& id, void** object) noexcept = 0; + virtual std::int32_t __stdcall Resolve(guid const& id, void** object) noexcept = 0; }; - struct __declspec(novtable) IMarshal : unknown_abi + struct WINRT_IMPL_ABI_DECL IMarshal : unknown_abi { - virtual int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, guid* pCid) noexcept = 0; - virtual int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, uint32_t* pSize) noexcept = 0; - virtual int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags) noexcept = 0; - virtual int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept = 0; - virtual int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept = 0; - virtual int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept = 0; + virtual std::int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags, guid* pCid) noexcept = 0; + virtual std::int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags, std::uint32_t* pSize) noexcept = 0; + virtual std::int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags) noexcept = 0; + virtual std::int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept = 0; + virtual std::int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept = 0; + virtual std::int32_t __stdcall DisconnectObject(std::uint32_t dwReserved) noexcept = 0; }; - struct __declspec(novtable) IGlobalInterfaceTable : unknown_abi + struct WINRT_IMPL_ABI_DECL IGlobalInterfaceTable : unknown_abi { - virtual int32_t __stdcall RegisterInterfaceInGlobal(void* object, guid const& iid, uint32_t* cookie) noexcept = 0; - virtual int32_t __stdcall RevokeInterfaceFromGlobal(uint32_t cookie) noexcept = 0; - virtual int32_t __stdcall GetInterfaceFromGlobal(uint32_t cookie, guid const& iid, void** object) noexcept = 0; + virtual std::int32_t __stdcall RegisterInterfaceInGlobal(void* object, guid const& iid, std::uint32_t* cookie) noexcept = 0; + virtual std::int32_t __stdcall RevokeInterfaceFromGlobal(std::uint32_t cookie) noexcept = 0; + virtual std::int32_t __stdcall GetInterfaceFromGlobal(std::uint32_t cookie, guid const& iid, void** object) noexcept = 0; }; - struct __declspec(novtable) IStaticLifetime : inspectable_abi + struct WINRT_IMPL_ABI_DECL IStaticLifetime : inspectable_abi { - virtual int32_t __stdcall unused() noexcept = 0; - virtual int32_t __stdcall GetCollection(void** value) noexcept = 0; + virtual std::int32_t __stdcall unused() noexcept = 0; + virtual std::int32_t __stdcall GetCollection(void** value) noexcept = 0; }; - struct __declspec(novtable) IStaticLifetimeCollection : inspectable_abi + struct WINRT_IMPL_ABI_DECL IStaticLifetimeCollection : inspectable_abi { - virtual int32_t __stdcall Lookup(void*, void**) noexcept = 0; - virtual int32_t __stdcall unused() noexcept = 0; - virtual int32_t __stdcall unused2() noexcept = 0; - virtual int32_t __stdcall unused3() noexcept = 0; - virtual int32_t __stdcall Insert(void*, void*, bool*) noexcept = 0; - virtual int32_t __stdcall Remove(void*) noexcept = 0; - virtual int32_t __stdcall unused4() noexcept = 0; + virtual std::int32_t __stdcall Lookup(void*, void**) noexcept = 0; + virtual std::int32_t __stdcall unused() noexcept = 0; + virtual std::int32_t __stdcall unused2() noexcept = 0; + virtual std::int32_t __stdcall unused3() noexcept = 0; + virtual std::int32_t __stdcall Insert(void*, void*, bool*) noexcept = 0; + virtual std::int32_t __stdcall Remove(void*) noexcept = 0; + virtual std::int32_t __stdcall unused4() noexcept = 0; }; - struct __declspec(novtable) IWeakReference : unknown_abi + struct WINRT_IMPL_ABI_DECL IWeakReference : unknown_abi { - virtual int32_t __stdcall Resolve(guid const& iid, void** objectReference) noexcept = 0; + virtual std::int32_t __stdcall Resolve(guid const& iid, void** objectReference) noexcept = 0; }; - struct __declspec(novtable) IWeakReferenceSource : unknown_abi + struct WINRT_IMPL_ABI_DECL IWeakReferenceSource : unknown_abi { - virtual int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept = 0; + virtual std::int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept = 0; }; - struct __declspec(novtable) IRestrictedErrorInfo : unknown_abi + struct WINRT_IMPL_ABI_DECL IRestrictedErrorInfo : unknown_abi { - virtual int32_t __stdcall GetErrorDetails(bstr* description, int32_t* error, bstr* restrictedDescription, bstr* capabilitySid) noexcept = 0; - virtual int32_t __stdcall GetReference(bstr* reference) noexcept = 0; + virtual std::int32_t __stdcall GetErrorDetails(bstr* description, std::int32_t* error, bstr* restrictedDescription, bstr* capabilitySid) noexcept = 0; + virtual std::int32_t __stdcall GetReference(bstr* reference) noexcept = 0; }; - struct __declspec(novtable) IErrorInfo : unknown_abi + struct WINRT_IMPL_ABI_DECL IErrorInfo : unknown_abi { - virtual int32_t __stdcall GetGUID(guid* value) noexcept = 0; - virtual int32_t __stdcall GetSource(bstr* value) noexcept = 0; - virtual int32_t __stdcall GetDescription(bstr* value) noexcept = 0; - virtual int32_t __stdcall GetHelpFile(bstr* value) noexcept = 0; - virtual int32_t __stdcall GetHelpContext(uint32_t* value) noexcept = 0; + virtual std::int32_t __stdcall GetGUID(guid* value) noexcept = 0; + virtual std::int32_t __stdcall GetSource(bstr* value) noexcept = 0; + virtual std::int32_t __stdcall GetDescription(bstr* value) noexcept = 0; + virtual std::int32_t __stdcall GetHelpFile(bstr* value) noexcept = 0; + virtual std::int32_t __stdcall GetHelpContext(std::uint32_t* value) noexcept = 0; }; - struct __declspec(novtable) ILanguageExceptionErrorInfo2 : unknown_abi + struct WINRT_IMPL_ABI_DECL ILanguageExceptionErrorInfo2 : unknown_abi { - virtual int32_t __stdcall GetLanguageException(void** exception) noexcept = 0; - virtual int32_t __stdcall GetPreviousLanguageExceptionErrorInfo(ILanguageExceptionErrorInfo2** previous) noexcept = 0; - virtual int32_t __stdcall CapturePropagationContext(void* exception) noexcept = 0; - virtual int32_t __stdcall GetPropagationContextHead(ILanguageExceptionErrorInfo2** head) noexcept = 0; + virtual std::int32_t __stdcall GetLanguageException(void** exception) noexcept = 0; + virtual std::int32_t __stdcall GetPreviousLanguageExceptionErrorInfo(ILanguageExceptionErrorInfo2** previous) noexcept = 0; + virtual std::int32_t __stdcall CapturePropagationContext(void* exception) noexcept = 0; + virtual std::int32_t __stdcall GetPropagationContextHead(ILanguageExceptionErrorInfo2** head) noexcept = 0; }; struct ICallbackWithNoReentrancyToApplicationSTA; - struct __declspec(novtable) IContextCallback : unknown_abi + struct WINRT_IMPL_ABI_DECL IContextCallback : unknown_abi { - virtual int32_t __stdcall ContextCallback(int32_t(__stdcall* callback)(com_callback_args*), com_callback_args* args, guid const& iid, int method, void* reserved) noexcept = 0; + virtual std::int32_t __stdcall ContextCallback(std::int32_t(__stdcall* callback)(com_callback_args*), com_callback_args* args, guid const& iid, int method, void* reserved) noexcept = 0; }; - struct __declspec(novtable) IServerSecurity : unknown_abi + struct WINRT_IMPL_ABI_DECL IServerSecurity : unknown_abi { - virtual int32_t __stdcall QueryBlanket(uint32_t*, uint32_t*, wchar_t**, uint32_t*, uint32_t*, void**, uint32_t*) noexcept = 0; - virtual int32_t __stdcall ImpersonateClient() noexcept = 0; - virtual int32_t __stdcall RevertToSelf() noexcept = 0; - virtual int32_t __stdcall IsImpersonating() noexcept = 0; + virtual std::int32_t __stdcall QueryBlanket(std::uint32_t*, std::uint32_t*, wchar_t**, std::uint32_t*, std::uint32_t*, void**, std::uint32_t*) noexcept = 0; + virtual std::int32_t __stdcall ImpersonateClient() noexcept = 0; + virtual std::int32_t __stdcall RevertToSelf() noexcept = 0; + virtual std::int32_t __stdcall IsImpersonating() noexcept = 0; }; - struct __declspec(novtable) IBufferByteAccess : unknown_abi + struct WINRT_IMPL_ABI_DECL IBufferByteAccess : unknown_abi { - virtual int32_t __stdcall Buffer(uint8_t** value) noexcept = 0; + virtual std::int32_t __stdcall Buffer(std::uint8_t** value) noexcept = 0; }; - struct __declspec(novtable) IMemoryBufferByteAccess : unknown_abi + struct WINRT_IMPL_ABI_DECL IMemoryBufferByteAccess : unknown_abi { - virtual int32_t __stdcall GetBuffer(uint8_t** value, uint32_t* capacity) noexcept = 0; + virtual std::int32_t __stdcall GetBuffer(std::uint8_t** value, std::uint32_t* capacity) noexcept = 0; }; template <> struct abi { - using type = int64_t; + using type = std::int64_t; }; template <> struct abi { - using type = int64_t; + using type = std::int64_t; }; template <> inline constexpr guid guid_v{ 0x00000000, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; diff --git a/strings/base_activation.h b/strings/base_activation.h index 8d8eb5e92..c657c692d 100644 --- a/strings/base_activation.h +++ b/strings/base_activation.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct library_traits { @@ -18,13 +18,6 @@ namespace winrt::impl using library_handle = handle_type; - inline int32_t __stdcall fallback_RoGetActivationFactory(void*, guid const&, void** factory) noexcept - { - *factory = nullptr; - return error_class_not_available; - } - - template WINRT_IMPL_NOINLINE hresult get_runtime_activation_factory_impl(param::hstring const& name, winrt::guid const& guid, void** result) noexcept { @@ -33,13 +26,11 @@ namespace winrt::impl return winrt_activation_handler(*(void**)(&name), guid, result); } - static int32_t(__stdcall * handler)(void* classId, winrt::guid const& iid, void** factory) noexcept; - impl::load_runtime_function(L"combase.dll", "RoGetActivationFactory", handler, fallback_RoGetActivationFactory); - hresult hr = handler(*(void**)(&name), guid, result); + hresult hr = WINRT_IMPL_RoGetActivationFactory(*(void**)(&name), guid, result); if (hr == impl::error_not_initialized) { - auto usage = reinterpret_cast(WINRT_IMPL_GetProcAddress(WINRT_IMPL_LoadLibraryW(L"combase.dll"), "CoIncrementMTAUsage")); + auto usage = reinterpret_cast(WINRT_IMPL_GetProcAddress(load_library(L"combase.dll"), "CoIncrementMTAUsage")); if (!usage) { @@ -48,7 +39,7 @@ namespace winrt::impl void* cookie; usage(&cookie); - hr = handler(*(void**)(&name), guid, result); + hr = WINRT_IMPL_RoGetActivationFactory(*(void**)(&name), guid, result); } if (hr == 0) @@ -66,7 +57,7 @@ namespace winrt::impl { path.resize(count); path += L".dll"; - library_handle library(WINRT_IMPL_LoadLibraryW(path.c_str())); + library_handle library(load_library(path.c_str())); path.resize(path.size() - 4); if (!library) @@ -74,7 +65,7 @@ namespace winrt::impl continue; } - auto library_call = reinterpret_cast(WINRT_IMPL_GetProcAddress(library.get(), "DllGetActivationFactory")); + auto library_call = reinterpret_cast(WINRT_IMPL_GetProcAddress(library.get(), "DllGetActivationFactory")); if (!library_call) { @@ -128,22 +119,26 @@ WINRT_EXPORT namespace winrt #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif -#if defined _M_ARM -#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM_BARRIER_ISH)); +#if defined(__GNUC__) && defined(__aarch64__) +#define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER __asm__ __volatile__ ("dmb ish"); #elif defined _M_ARM64 #define WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER (__dmb(_ARM64_BARRIER_ISH)); #endif -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { - inline int32_t interlocked_read_32(int32_t const volatile* target) noexcept + inline std::int32_t interlocked_read_32(std::int32_t const volatile* target) noexcept { #if defined _M_IX86 || defined _M_X64 - int32_t const result = *target; + std::int32_t const result = *target; _ReadWriteBarrier(); return result; -#elif defined _M_ARM || defined _M_ARM64 - int32_t const result = __iso_volatile_load32(reinterpret_cast(target)); +#elif defined _M_ARM64 +#if defined(__GNUC__) + std::int32_t const result = *target; +#else + std::int32_t const result = __iso_volatile_load32(reinterpret_cast(target)); +#endif WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER return result; #else @@ -152,14 +147,18 @@ namespace winrt::impl } #if defined _WIN64 - inline int64_t interlocked_read_64(int64_t const volatile* target) noexcept + inline std::int64_t interlocked_read_64(std::int64_t const volatile* target) noexcept { #if defined _M_X64 - int64_t const result = *target; + std::int64_t const result = *target; _ReadWriteBarrier(); return result; #elif defined _M_ARM64 - int64_t const result = __iso_volatile_load64(target); +#if defined(__GNUC__) + std::int64_t const result = *target; +#else + std::int64_t const result = __iso_volatile_load64(target); +#endif WINRT_IMPL_INTERLOCKED_READ_MEMORY_BARRIER return result; #else @@ -178,16 +177,18 @@ namespace winrt::impl T* interlocked_read_pointer(T* const volatile* target) noexcept { #ifdef _WIN64 - return (T*)interlocked_read_64((int64_t*)target); + return (T*)interlocked_read_64((std::int64_t*)target); #else - return (T*)interlocked_read_32((int32_t*)target); + return (T*)interlocked_read_32((std::int32_t*)target); #endif } #ifdef _WIN64 - inline constexpr uint32_t memory_allocation_alignment{ 16 }; + inline constexpr std::uint32_t memory_allocation_alignment{ 16 }; +#ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4324) // structure was padded due to alignment specifier +#endif struct alignas(16) slist_entry { slist_entry* next; @@ -196,32 +197,34 @@ namespace winrt::impl { struct { - uint64_t reserved1; - uint64_t reserved2; + std::uint64_t reserved1; + std::uint64_t reserved2; } reserved1; struct { - uint64_t reserved1 : 16; - uint64_t reserved2 : 48; - uint64_t reserved3 : 4; - uint64_t reserved4 : 60; + std::uint64_t reserved1 : 16; + std::uint64_t reserved2 : 48; + std::uint64_t reserved3 : 4; + std::uint64_t reserved4 : 60; } reserved2; }; +#ifdef _MSC_VER #pragma warning(pop) +#endif #else - inline constexpr uint32_t memory_allocation_alignment{ 8 }; + inline constexpr std::uint32_t memory_allocation_alignment{ 8 }; struct slist_entry { slist_entry* next; }; union slist_header { - uint64_t reserved1; + std::uint64_t reserved1; struct { slist_entry reserved1; - uint16_t reserved2; - uint16_t reserved3; + std::uint16_t reserved2; + std::uint16_t reserved3; } reserved2; }; #endif @@ -231,11 +234,11 @@ namespace winrt::impl factory_count_guard(factory_count_guard const&) = delete; factory_count_guard& operator=(factory_count_guard const&) = delete; - explicit factory_count_guard(size_t& count) noexcept : m_count(count) + explicit factory_count_guard(std::size_t& count) noexcept : m_count(count) { #ifndef WINRT_NO_MODULE_LOCK #ifdef _WIN64 - _InterlockedIncrement64((int64_t*)&m_count); + _InterlockedIncrement64((std::int64_t*)&m_count); #else _InterlockedIncrement((long*)&m_count); #endif @@ -246,7 +249,7 @@ namespace winrt::impl { #ifndef WINRT_NO_MODULE_LOCK #ifdef _WIN64 - _InterlockedDecrement64((int64_t*)&m_count); + _InterlockedDecrement64((std::int64_t*)&m_count); #else _InterlockedDecrement((long*)&m_count); #endif @@ -254,8 +257,7 @@ namespace winrt::impl } private: - - size_t& m_count; + [[maybe_unused]] std::size_t& m_count; // Field is unused when WINRT_NO_MODULE_LOCK is defined. }; struct factory_cache_entry_base @@ -263,7 +265,7 @@ namespace winrt::impl struct alignas(sizeof(void*) * 2) object_and_count { unknown_abi* object; - size_t count; + std::size_t count; }; object_and_count m_value; @@ -281,14 +283,19 @@ namespace winrt::impl object_and_count current_value{ pointer_value, 0 }; #if defined _WIN64 - if (1 == _InterlockedCompareExchange128((int64_t*)this, 0, 0, (int64_t*)¤t_value)) +#if defined(__GNUC__) + bool exchanged = __sync_bool_compare_and_swap((__int128*)this, *(__int128*)¤t_value, (__int128)0); +#else + bool exchanged = 1 == _InterlockedCompareExchange128((std::int64_t*)this, 0, 0, (std::int64_t*)¤t_value); +#endif + if (exchanged) { pointer_value->Release(); } #else - int64_t const result = _InterlockedCompareExchange64((int64_t*)this, 0, *(int64_t*)¤t_value); + std::int64_t const result = _InterlockedCompareExchange64((std::int64_t*)this, 0, *(std::int64_t*)¤t_value); - if (result == *(int64_t*)¤t_value) + if (result == *(std::int64_t*)¤t_value) { pointer_value->Release(); } @@ -298,7 +305,7 @@ namespace winrt::impl static_assert(std::is_standard_layout_v); -#if !defined _M_IX86 && !defined _M_X64 && !defined _M_ARM && !defined _M_ARM64 +#if !defined _M_IX86 && !defined _M_X64 && !defined _M_ARM64 #error Unsupported architecture: verify that zero-initialization of SLIST_HEADER is still safe #endif @@ -323,7 +330,7 @@ namespace winrt::impl // entry->next must be read before entry->clear() is called since the InterlockedCompareExchange // inside clear() will allow another thread to add the entry back to the cache. slist_entry* next = entry->next; - reinterpret_cast(reinterpret_cast(entry) - offsetof(factory_cache_entry_base, m_next))->clear(); + reinterpret_cast(reinterpret_cast(entry) - offsetof(factory_cache_entry_base, m_next))->clear(); entry = next; } } @@ -436,7 +443,7 @@ namespace winrt::impl template struct produce : produce_base { - int32_t __stdcall ActivateInstance(void** instance) noexcept final try + std::int32_t __stdcall ActivateInstance(void** instance) noexcept final try { *instance = nullptr; typename D::abi_guard guard(this->shim()); @@ -449,7 +456,7 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { - enum class apartment_type : int32_t + enum class apartment_type : std::int32_t { multi_threaded = 0, single_threaded = 2, @@ -457,7 +464,7 @@ WINRT_EXPORT namespace winrt inline void init_apartment(apartment_type const type = apartment_type::multi_threaded) { - hresult const result = WINRT_IMPL_CoInitializeEx(nullptr, static_cast(type)); + hresult const result = WINRT_IMPL_CoInitializeEx(nullptr, static_cast(type)); if (result < 0) { @@ -512,13 +519,13 @@ WINRT_EXPORT namespace winrt } template - auto try_create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) + auto try_create_instance(guid const& clsid, std::uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) { return try_capture(WINRT_IMPL_CoCreateInstance, clsid, outer, context); } template - auto create_instance(guid const& clsid, uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) + auto create_instance(guid const& clsid, std::uint32_t context = 0x1 /*CLSCTX_INPROC_SERVER*/, void* outer = nullptr) { return capture(WINRT_IMPL_CoCreateInstance, clsid, outer, context); } @@ -541,7 +548,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template T fast_activate(Windows::Foundation::IActivationFactory const& factory) diff --git a/strings/base_agile_ref.h b/strings/base_agile_ref.h index eb5bfe245..14447706a 100644 --- a/strings/base_agile_ref.h +++ b/strings/base_agile_ref.h @@ -10,12 +10,12 @@ WINRT_EXPORT namespace winrt { struct lock { - constexpr uint32_t operator++() noexcept + constexpr std::uint32_t operator++() noexcept { return 1; } - constexpr uint32_t operator--() noexcept + constexpr std::uint32_t operator--() noexcept { return 0; } @@ -47,7 +47,7 @@ WINRT_EXPORT namespace winrt #endif } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct module_lock_updater; @@ -71,109 +71,14 @@ namespace winrt::impl using update_module_lock = module_lock_updater; - struct agile_ref_fallback final : IAgileReference, update_module_lock + inline void* load_library(wchar_t const* library) noexcept { - agile_ref_fallback(com_ptr&& git, uint32_t cookie) noexcept : - m_git(std::move(git)), - m_cookie(cookie) - { - } - - ~agile_ref_fallback() noexcept - { - m_git->RevokeInterfaceFromGlobal(m_cookie); - } - - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final - { - if (is_guid_of(id) || is_guid_of(id) || is_guid_of(id)) - { - *object = static_cast(this); - AddRef(); - return 0; - } - - *object = nullptr; - return error_no_interface; - } - - uint32_t __stdcall AddRef() noexcept final - { - return ++m_references; - } - - uint32_t __stdcall Release() noexcept final - { - auto const remaining = --m_references; - - if (remaining == 0) - { - delete this; - } - - return remaining; - } - - int32_t __stdcall Resolve(guid const& id, void** object) noexcept final - { - return m_git->GetInterfaceFromGlobal(m_cookie, id, object); - } - - private: - - com_ptr m_git; - uint32_t m_cookie{}; - atomic_ref_count m_references{ 1 }; - }; - - template - void load_runtime_function(wchar_t const* library, char const* name, F& result, L fallback) noexcept - { - if (result) - { - return; - } - - result = reinterpret_cast(WINRT_IMPL_GetProcAddress(WINRT_IMPL_LoadLibraryW(library), name)); - - if (result) - { - return; - } - - result = fallback; - } - - inline int32_t __stdcall fallback_RoGetAgileReference(uint32_t, winrt::guid const& iid, void* object, void** reference) noexcept - { - *reference = nullptr; - static constexpr guid git_clsid{ 0x00000323, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } }; - - com_ptr git; - hresult hr = WINRT_IMPL_CoCreateInstance(git_clsid, nullptr, 1 /*CLSCTX_INPROC_SERVER*/, guid_of(), git.put_void()); - - if (hr < 0) - { - return hr; - } - - uint32_t cookie{}; - hr = git->RegisterInterfaceInGlobal(object, iid, &cookie); - - if (hr < 0) - { - return hr; - } - - *reference = new agile_ref_fallback(std::move(git), cookie); - return 0; + return WINRT_IMPL_LoadLibraryExW(library, nullptr, 0x00001000 /* LOAD_LIBRARY_SEARCH_DEFAULT_DIRS */); } inline hresult get_agile_reference(winrt::guid const& iid, void* object, void** reference) noexcept { - static int32_t(__stdcall * handler)(uint32_t options, winrt::guid const& iid, void* object, void** reference) noexcept; - load_runtime_function(L"combase.dll", "RoGetAgileReference", handler, fallback_RoGetAgileReference); - return handler(0, iid, object, reference); + return WINRT_IMPL_RoGetAgileReference(0, iid, object, reference); } } diff --git a/strings/base_array.h b/strings/base_array.h index 5f0904efe..d29bee883 100644 --- a/strings/base_array.h +++ b/strings/base_array.h @@ -5,7 +5,7 @@ WINRT_EXPORT namespace winrt struct array_view { using value_type = T; - using size_type = uint32_t; + using size_type = std::uint32_t; using reference = value_type&; using const_reference = value_type const&; using pointer = value_type*; @@ -31,6 +31,20 @@ WINRT_EXPORT namespace winrt array_view(value.begin(), static_cast(value.size())) {} +#ifdef __cpp_lib_span + template + array_view(std::span span) noexcept : + array_view(span.data(), static_cast(span.size())) + { + WINRT_ASSERT(span.size() <= (std::numeric_limits::max)()); + } + + operator std::span() const noexcept + { + return { m_data, m_size }; + } +#endif + template array_view(C(&value)[N]) noexcept : array_view(value, N) @@ -48,12 +62,12 @@ WINRT_EXPORT namespace winrt { } - template + template array_view(std::array& value) noexcept : array_view(value.data(), static_cast(value.size())) {} - template + template array_view(std::array const& value) noexcept : array_view(value.data(), static_cast(value.size())) {} @@ -217,11 +231,16 @@ WINRT_EXPORT namespace winrt } }; - template array_view(C(&value)[N]) -> array_view; + template array_view(C(&value)[N]) -> array_view; template array_view(std::vector& value) -> array_view; template array_view(std::vector const& value) -> array_view; - template array_view(std::array& value) -> array_view; - template array_view(std::array const& value) -> array_view; + template array_view(std::array& value) -> array_view; + template array_view(std::array const& value) -> array_view; + +#ifdef __cpp_lib_span + template array_view(std::span& value) -> array_view; + template array_view(std::span const& value) -> array_view; +#endif template struct com_array : array_view @@ -246,7 +265,7 @@ WINRT_EXPORT namespace winrt com_array(count, value_type()) {} - com_array(void* ptr, uint32_t const count, take_ownership_from_abi_t) noexcept : + com_array(void* ptr, std::uint32_t const count, take_ownership_from_abi_t) noexcept : array_view(static_cast(ptr), static_cast(ptr) + count) { } @@ -269,12 +288,21 @@ WINRT_EXPORT namespace winrt com_array(value.begin(), value.end()) {} - template + template explicit com_array(std::array const& value) : com_array(value.begin(), value.end()) {} - template +#ifdef __cpp_lib_span + template + explicit com_array(std::span span) noexcept : + com_array(span.data(), span.data() + span.size()) + { + WINRT_ASSERT(span.size() <= (std::numeric_limits::max)()); + } +#endif + + template explicit com_array(U const(&value)[N]) : com_array(value, value + N) {} @@ -345,16 +373,41 @@ WINRT_EXPORT namespace winrt this->m_size = size; } } + + std::pair> detach_abi() noexcept + { +#if defined(_MSC_VER) && !defined(__clang__) + // https://github.com/microsoft/cppwinrt/pull/1165 + std::pair> result; + std::memset(&result, 0, sizeof(result)); + result.first = this->size(); + result.second = *reinterpret_cast*>(this); + std::memset(this, 0, sizeof(com_array)); +#else + std::pair> result(this->size(), *reinterpret_cast*>(this)); + this->m_data = nullptr; + this->m_size = 0; +#endif + return result; + } + + template + friend std::pair> detach_abi(com_array& object) noexcept; }; - template com_array(uint32_t, C const&) -> com_array>; + template com_array(std::uint32_t, C const&) -> com_array>; template ::difference_type>> com_array(InIt, InIt) -> com_array::value_type>>; template com_array(std::vector const&) -> com_array>; - template com_array(std::array const&) -> com_array>; - template com_array(C const(&)[N]) -> com_array>; + template com_array(std::array const&) -> com_array>; + template com_array(C const(&)[N]) -> com_array>; template com_array(std::initializer_list) -> com_array>; +#ifdef __cpp_lib_span + template com_array(std::span const& value) -> com_array>; +#endif + + namespace impl { template @@ -418,11 +471,9 @@ WINRT_EXPORT namespace winrt } template - auto detach_abi(com_array& object) noexcept + std::pair> detach_abi(com_array& object) noexcept { - std::pair> result(object.size(), *reinterpret_cast*>(&object)); - memset(&object, 0, sizeof(com_array)); - return result; + return object.detach_abi(); } template @@ -432,7 +483,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct array_size_proxy @@ -445,10 +496,10 @@ namespace winrt::impl ~array_size_proxy() noexcept { WINRT_ASSERT(m_value.data() || (!m_value.data() && m_size == 0)); - *reinterpret_cast(reinterpret_cast(&m_value) + 1) = m_size; + *reinterpret_cast(reinterpret_cast(&m_value) + 1) = m_size; } - operator uint32_t*() noexcept + operator std::uint32_t*() noexcept { return &m_size; } @@ -461,7 +512,7 @@ namespace winrt::impl private: com_array& m_value; - uint32_t m_size{ 0 }; + std::uint32_t m_size{ 0 }; }; template @@ -473,7 +524,7 @@ namespace winrt::impl template struct com_array_proxy { - com_array_proxy(uint32_t* size, winrt::impl::arg_out* value) noexcept : m_size(size), m_value(value) + com_array_proxy(std::uint32_t* size, winrt::impl::arg_out* value) noexcept : m_size(size), m_value(value) {} ~com_array_proxy() noexcept @@ -494,7 +545,7 @@ namespace winrt::impl private: - uint32_t* m_size; + std::uint32_t* m_size; arg_out* m_value; com_array m_temp; }; @@ -503,7 +554,7 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { template - auto detach_abi(uint32_t* __valueSize, impl::arg_out* value) noexcept + auto detach_abi(std::uint32_t* __valueSize, impl::arg_out* value) noexcept { return impl::com_array_proxy(__valueSize, value); } diff --git a/strings/base_chrono.h b/strings/base_chrono.h index 8af906176..7934ac5b2 100644 --- a/strings/base_chrono.h +++ b/strings/base_chrono.h @@ -3,17 +3,17 @@ WINRT_EXPORT namespace winrt { struct file_time { - uint64_t value{}; + std::uint64_t value{}; file_time() noexcept = default; - constexpr explicit file_time(uint64_t const value) noexcept : value(value) + constexpr explicit file_time(std::uint64_t const value) noexcept : value(value) { } #ifdef _FILETIME_ constexpr file_time(FILETIME const& value) noexcept - : value(value.dwLowDateTime | (static_cast(value.dwHighDateTime) << 32)) + : value(value.dwLowDateTime | (static_cast(value.dwHighDateTime) << 32)) { } @@ -26,7 +26,7 @@ WINRT_EXPORT namespace winrt struct clock { - using rep = int64_t; + using rep = std::int64_t; using period = impl::filetime_period; using duration = Windows::Foundation::TimeSpan; using time_point = Windows::Foundation::DateTime; @@ -42,17 +42,17 @@ WINRT_EXPORT namespace winrt static time_t to_time_t(time_point const& time) noexcept { - return static_cast(std::chrono::system_clock::to_time_t(to_sys(time))); + return static_cast(std::chrono::system_clock::to_time_t(std::chrono::time_point_cast(to_sys(time)))); } static time_point from_time_t(time_t time) noexcept { - return from_sys(std::chrono::system_clock::from_time_t(time)); + return from_sys(std::chrono::time_point_cast(std::chrono::system_clock::from_time_t(time))); } static file_time to_file_time(time_point const& time) noexcept { - return file_time{ static_cast(time.time_since_epoch().count()) }; + return file_time{ static_cast(time.time_since_epoch().count()) }; } static time_point from_file_time(file_time const& time) noexcept diff --git a/strings/base_collections.h b/strings/base_collections.h index cba0864b3..7d8dc2e77 100644 --- a/strings/base_collections.h +++ b/strings/base_collections.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { namespace wfc = Windows::Foundation::Collections; @@ -101,10 +101,10 @@ namespace winrt::impl private: - uint32_t const m_snapshot; + std::uint32_t const m_snapshot; }; - uint32_t get_version() const noexcept + std::uint32_t get_version() const noexcept { return m_version; } @@ -116,7 +116,7 @@ namespace winrt::impl private: - std::atomic m_version{}; + std::atomic m_version{}; }; template diff --git a/strings/base_collections_base.h b/strings/base_collections_base.h index b2d58f602..d299cc0c8 100644 --- a/strings/base_collections_base.h +++ b/strings/base_collections_base.h @@ -1,4 +1,4 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct nop_lock_guard {}; @@ -108,7 +108,7 @@ WINRT_EXPORT namespace winrt auto First() { // NOTE: iterator's constructor requires shared access - auto guard = static_cast(*this).acquire_shared(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); return make(static_cast(this)); } @@ -161,7 +161,7 @@ WINRT_EXPORT namespace winrt T Current() const { - auto guard = m_owner->acquire_shared(); + [[maybe_unused]] auto guard = m_owner->acquire_shared(); this->check_version(*m_owner); if (m_current == m_end) @@ -174,14 +174,14 @@ WINRT_EXPORT namespace winrt bool HasCurrent() const { - auto guard = m_owner->acquire_shared(); + [[maybe_unused]] auto guard = m_owner->acquire_shared(); this->check_version(*m_owner); return m_current != m_end; } bool MoveNext() { - auto guard = m_owner->acquire_exclusive(); + [[maybe_unused]] auto guard = m_owner->acquire_exclusive(); this->check_version(*m_owner); if (m_current != m_end) { @@ -191,9 +191,9 @@ WINRT_EXPORT namespace winrt return m_current != m_end; } - uint32_t GetMany(array_view values) + std::uint32_t GetMany(array_view values) { - auto guard = m_owner->acquire_exclusive(); + [[maybe_unused]] auto guard = m_owner->acquire_exclusive(); this->check_version(*m_owner); return GetMany(values, typename std::iterator_traits::iterator_category()); } @@ -213,15 +213,15 @@ WINRT_EXPORT namespace winrt } } - uint32_t GetMany(array_view values, std::random_access_iterator_tag) + std::uint32_t GetMany(array_view values, std::random_access_iterator_tag) { - uint32_t const actual = (std::min)(static_cast(m_end - m_current), values.size()); + std::uint32_t const actual = (std::min)(static_cast(m_end - m_current), values.size()); m_owner->copy_n(m_current, actual, values.begin()); m_current += actual; return actual; } - uint32_t GetMany(array_view values, std::input_iterator_tag) + std::uint32_t GetMany(array_view values, std::input_iterator_tag) { auto output = values.begin(); @@ -232,7 +232,7 @@ WINRT_EXPORT namespace winrt ++m_current; } - return static_cast(output - values.begin()); + return static_cast(output - values.begin()); } using iterator_type = decltype(std::declval().get_container().begin()); @@ -246,9 +246,9 @@ WINRT_EXPORT namespace winrt template struct vector_view_base : iterable_base { - T GetAt(uint32_t const index) const + T GetAt(std::uint32_t const index) const { - auto guard = static_cast(*this).acquire_shared(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); if (index >= container_size()) { throw hresult_out_of_bounds(); @@ -257,42 +257,42 @@ WINRT_EXPORT namespace winrt return static_cast(*this).unwrap_value(*std::next(static_cast(*this).get_container().begin(), index)); } - uint32_t Size() const noexcept + std::uint32_t Size() const noexcept { - auto guard = static_cast(*this).acquire_shared(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); return container_size(); } - bool IndexOf(T const& value, uint32_t& index) const noexcept + bool IndexOf(T const& value, std::uint32_t& index) const noexcept { - auto guard = static_cast(*this).acquire_shared(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); auto first = std::find_if(static_cast(*this).get_container().begin(), static_cast(*this).get_container().end(), [&](auto&& match) { return value == static_cast(*this).unwrap_value(match); }); - index = static_cast(first - static_cast(*this).get_container().begin()); + index = static_cast(first - static_cast(*this).get_container().begin()); return index < container_size(); } - uint32_t GetMany(uint32_t const startIndex, array_view values) const + std::uint32_t GetMany(std::uint32_t const startIndex, array_view values) const { - auto guard = static_cast(*this).acquire_shared(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); if (startIndex >= container_size()) { return 0; } - uint32_t const actual = (std::min)(container_size() - startIndex, values.size()); + std::uint32_t const actual = (std::min)(container_size() - startIndex, values.size()); this->copy_n(static_cast(*this).get_container().begin() + startIndex, actual, values.begin()); return actual; } private: - uint32_t container_size() const noexcept + std::uint32_t container_size() const noexcept { - return static_cast(std::distance(static_cast(*this).get_container().begin(), static_cast(*this).get_container().end())); + return static_cast(std::distance(static_cast(*this).get_container().begin(), static_cast(*this).get_container().end())); } }; @@ -304,11 +304,11 @@ WINRT_EXPORT namespace winrt return static_cast(*this); } - void SetAt(uint32_t const index, T const& value) + void SetAt(std::uint32_t const index, T const& value) { impl::removed_value::value_type> oldValue; - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); if (index >= static_cast(*this).get_container().size()) { throw hresult_out_of_bounds(); @@ -320,9 +320,9 @@ WINRT_EXPORT namespace winrt pos = static_cast(*this).wrap_value(value); } - void InsertAt(uint32_t const index, T const& value) + void InsertAt(std::uint32_t const index, T const& value) { - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); if (index > static_cast(*this).get_container().size()) { throw hresult_out_of_bounds(); @@ -332,11 +332,11 @@ WINRT_EXPORT namespace winrt static_cast(*this).get_container().insert(static_cast(*this).get_container().begin() + index, static_cast(*this).wrap_value(value)); } - void RemoveAt(uint32_t const index) + void RemoveAt(std::uint32_t const index) { impl::removed_value::value_type> removedValue; - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); if (index >= static_cast(*this).get_container().size()) { throw hresult_out_of_bounds(); @@ -350,7 +350,7 @@ WINRT_EXPORT namespace winrt void Append(T const& value) { - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); this->increment_version(); static_cast(*this).get_container().push_back(static_cast(*this).wrap_value(value)); } @@ -359,7 +359,7 @@ WINRT_EXPORT namespace winrt { impl::removed_value::value_type> removedValue; - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); if (static_cast(*this).get_container().empty()) { throw hresult_out_of_bounds(); @@ -374,7 +374,7 @@ WINRT_EXPORT namespace winrt { impl::removed_values oldContainer; - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); this->increment_version(); oldContainer.assign(static_cast(*this).get_container()); } @@ -383,7 +383,7 @@ WINRT_EXPORT namespace winrt { impl::removed_values oldContainer; - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); this->increment_version(); oldContainer.assign(static_cast(*this).get_container()); assign(value.begin(), value.end()); @@ -425,19 +425,19 @@ WINRT_EXPORT namespace winrt m_changed.remove(cookie); } - void SetAt(uint32_t const index, T const& value) + void SetAt(std::uint32_t const index, T const& value) { vector_base::SetAt(index, value); call_changed(Windows::Foundation::Collections::CollectionChange::ItemChanged, index); } - void InsertAt(uint32_t const index, T const& value) + void InsertAt(std::uint32_t const index, T const& value) { vector_base::InsertAt(index, value); call_changed(Windows::Foundation::Collections::CollectionChange::ItemInserted, index); } - void RemoveAt(uint32_t const index) + void RemoveAt(std::uint32_t const index) { vector_base::RemoveAt(index); call_changed(Windows::Foundation::Collections::CollectionChange::ItemRemoved, index); @@ -469,7 +469,7 @@ WINRT_EXPORT namespace winrt protected: - void call_changed(Windows::Foundation::Collections::CollectionChange const change, uint32_t const index) + void call_changed(Windows::Foundation::Collections::CollectionChange const change, std::uint32_t const index) { m_changed(static_cast(*this), make(change, index)); } @@ -480,7 +480,7 @@ WINRT_EXPORT namespace winrt struct args : implements { - args(Windows::Foundation::Collections::CollectionChange const change, uint32_t const index) noexcept : + args(Windows::Foundation::Collections::CollectionChange const change, std::uint32_t const index) noexcept : m_change(change), m_index(index) { @@ -491,7 +491,7 @@ WINRT_EXPORT namespace winrt return m_change; } - uint32_t Index() const noexcept + std::uint32_t Index() const noexcept { return m_index; } @@ -499,16 +499,30 @@ WINRT_EXPORT namespace winrt private: Windows::Foundation::Collections::CollectionChange const m_change; - uint32_t const m_index; + std::uint32_t const m_index; }; }; template struct map_view_base : iterable_base, Version> { + // specialization of Lookup that avoids throwing the hresult + std::optional TryLookup(K const& key, trylookup_from_abi_t) const + { + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); + auto pair = static_cast(*this).get_container().find(static_cast(*this).wrap_value(key)); + + if (pair == static_cast(*this).get_container().end()) + { + return std::nullopt; + } + + return static_cast(*this).unwrap_value(pair->second); + } + V Lookup(K const& key) const { - auto guard = static_cast(*this).acquire_shared(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); auto pair = static_cast(*this).get_container().find(static_cast(*this).wrap_value(key)); if (pair == static_cast(*this).get_container().end()) @@ -519,15 +533,15 @@ WINRT_EXPORT namespace winrt return static_cast(*this).unwrap_value(pair->second); } - uint32_t Size() const noexcept + std::uint32_t Size() const noexcept { - auto guard = static_cast(*this).acquire_shared(); - return static_cast(static_cast(*this).get_container().size()); + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); + return static_cast(static_cast(*this).get_container().size()); } bool HasKey(K const& key) const noexcept { - auto guard = static_cast(*this).acquire_shared(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_shared(); return static_cast(*this).get_container().find(static_cast(*this).wrap_value(key)) != static_cast(*this).get_container().end(); } @@ -536,6 +550,7 @@ WINRT_EXPORT namespace winrt first = nullptr; second = nullptr; } + }; template @@ -550,7 +565,7 @@ WINRT_EXPORT namespace winrt { impl::removed_value::mapped_type> oldValue; - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); this->increment_version(); auto [itr, added] = static_cast(*this).get_container().emplace(static_cast(*this).wrap_value(key), static_cast(*this).wrap_value(value)); if (!added) @@ -566,7 +581,7 @@ WINRT_EXPORT namespace winrt { typename impl::container_type_t::node_type removedNode; - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); auto& container = static_cast(*this).get_container(); auto found = container.find(static_cast(*this).wrap_value(key)); if (found == container.end()) @@ -581,7 +596,7 @@ WINRT_EXPORT namespace winrt { impl::removed_values oldContainer; - auto guard = static_cast(*this).acquire_exclusive(); + [[maybe_unused]] auto guard = static_cast(*this).acquire_exclusive(); this->increment_version(); oldContainer.assign(static_cast(*this).get_container()); } @@ -619,15 +634,17 @@ WINRT_EXPORT namespace winrt call_changed(Windows::Foundation::Collections::CollectionChange::Reset, impl::empty_value()); } - private: - - event> m_changed; + protected: void call_changed(Windows::Foundation::Collections::CollectionChange const change, K const& key) { m_changed(static_cast(*this), make(change, key)); } + private: + + event> m_changed; + struct args : implements> { args(Windows::Foundation::Collections::CollectionChange const change, K const& key) noexcept : diff --git a/strings/base_collections_input_iterable.h b/strings/base_collections_input_iterable.h index e75211c30..e9d3af251 100644 --- a/strings/base_collections_input_iterable.h +++ b/strings/base_collections_input_iterable.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct input_iterable : diff --git a/strings/base_collections_input_map.h b/strings/base_collections_input_map.h index b33975fe6..3fe146bf6 100644 --- a/strings/base_collections_input_map.h +++ b/strings/base_collections_input_map.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct map_impl : diff --git a/strings/base_collections_input_map_view.h b/strings/base_collections_input_map_view.h index bfd8d82a9..d79eed61d 100644 --- a/strings/base_collections_input_map_view.h +++ b/strings/base_collections_input_map_view.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct input_map_view : diff --git a/strings/base_collections_input_vector.h b/strings/base_collections_input_vector.h index 2482db968..a06e73b33 100644 --- a/strings/base_collections_input_vector.h +++ b/strings/base_collections_input_vector.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct vector_impl : @@ -88,7 +88,7 @@ WINRT_EXPORT namespace winrt::param private: interface_type m_interface; - bool m_owned{ true }; + bool m_owned = true; }; template diff --git a/strings/base_collections_input_vector_view.h b/strings/base_collections_input_vector_view.h index 3793e239a..30768c18e 100644 --- a/strings/base_collections_input_vector_view.h +++ b/strings/base_collections_input_vector_view.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct input_vector_view : diff --git a/strings/base_collections_map.h b/strings/base_collections_map.h index f4bd74baf..6bf884236 100644 --- a/strings/base_collections_map.h +++ b/strings/base_collections_map.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template using multi_threaded_map = map_impl; @@ -116,15 +116,15 @@ WINRT_EXPORT namespace winrt } } -namespace std +WINRT_EXPORT namespace std { template struct tuple_size> - : integral_constant + : integral_constant { }; - template + template struct tuple_element> { static_assert(Idx < 2, "key-value pair index out of bounds"); @@ -132,9 +132,9 @@ namespace std }; } -namespace winrt::Windows::Foundation::Collections +WINRT_EXPORT namespace winrt::Windows::Foundation::Collections { - template + template std::tuple_element_t> get(IKeyValuePair const& kvp) { static_assert(Idx < 2, "key-value pair index out of bounds"); diff --git a/strings/base_collections_vector.h b/strings/base_collections_vector.h index ff0ad6bec..3388806af 100644 --- a/strings/base_collections_vector.h +++ b/strings/base_collections_vector.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template using multi_threaded_vector = vector_impl; @@ -82,7 +82,7 @@ namespace winrt::impl operator wfc::IIterator() { - auto guard = container->acquire_shared(); + [[maybe_unused]] auto guard = container->acquire_shared(); return make(container); } }; @@ -90,12 +90,12 @@ namespace winrt::impl return result{ this }; } - auto GetAt(uint32_t const index) const + auto GetAt(std::uint32_t const index) const { struct result { base_type const* container; - uint32_t const index; + std::uint32_t const index; operator T() const { @@ -113,7 +113,7 @@ namespace winrt::impl using base_type::IndexOf; - bool IndexOf(Windows::Foundation::IInspectable const& value, uint32_t& index) const + bool IndexOf(Windows::Foundation::IInspectable const& value, std::uint32_t& index) const { if constexpr (is_com_interface_v) { @@ -139,15 +139,15 @@ namespace winrt::impl using base_type::GetMany; - uint32_t GetMany(uint32_t const startIndex, array_view values) const + std::uint32_t GetMany(std::uint32_t const startIndex, array_view values) const { - auto guard = this->acquire_shared(); + [[maybe_unused]] auto guard = this->acquire_shared(); if (startIndex >= m_values.size()) { return 0; } - uint32_t const actual = (std::min)(static_cast(m_values.size() - startIndex), values.size()); + std::uint32_t const actual = (std::min)(static_cast(m_values.size() - startIndex), values.size()); std::transform(m_values.begin() + startIndex, m_values.begin() + startIndex + actual, values.begin(), [&](auto && value) { @@ -179,14 +179,14 @@ namespace winrt::impl using base_type::SetAt; - void SetAt(uint32_t const index, Windows::Foundation::IInspectable const& value) + void SetAt(std::uint32_t const index, Windows::Foundation::IInspectable const& value) { SetAt(index, unbox_value(value)); } using base_type::InsertAt; - void InsertAt(uint32_t const index, Windows::Foundation::IInspectable const& value) + void InsertAt(std::uint32_t const index, Windows::Foundation::IInspectable const& value) { InsertAt(index, unbox_value(value)); } @@ -239,7 +239,7 @@ namespace winrt::impl Windows::Foundation::IInspectable Current() const { - auto guard = m_owner->acquire_shared(); + [[maybe_unused]] auto guard = m_owner->acquire_shared(); check_version(*m_owner); if (m_current == m_end) { @@ -251,14 +251,14 @@ namespace winrt::impl bool HasCurrent() const { - auto guard = m_owner->acquire_shared(); + [[maybe_unused]] auto guard = m_owner->acquire_shared(); check_version(*m_owner); return m_current != m_end; } bool MoveNext() { - auto guard = m_owner->acquire_exclusive(); + [[maybe_unused]] auto guard = m_owner->acquire_exclusive(); check_version(*m_owner); if (m_current != m_end) { @@ -268,11 +268,11 @@ namespace winrt::impl return m_current != m_end; } - uint32_t GetMany(array_view values) + std::uint32_t GetMany(array_view values) { - auto guard = m_owner->acquire_exclusive(); + [[maybe_unused]] auto guard = m_owner->acquire_exclusive(); check_version(*m_owner); - uint32_t const actual = (std::min)(static_cast(std::distance(m_current, m_end)), values.size()); + std::uint32_t const actual = (std::min)(static_cast(std::distance(m_current, m_end)), values.size()); std::transform(m_current, m_current + actual, values.begin(), [&](auto && value) { diff --git a/strings/base_com_ptr.h b/strings/base_com_ptr.h index 66dd2c9e7..0f02fabeb 100644 --- a/strings/base_com_ptr.h +++ b/strings/base_com_ptr.h @@ -5,22 +5,33 @@ WINRT_EXPORT namespace winrt struct com_ptr; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { + struct capture_decay + { + void** result; + + template + operator T** () + { + return reinterpret_cast(result); + } + }; + template - int32_t capture_to(void**result, F function, Args&& ...args) + std::int32_t capture_to(void**result, F function, Args&& ...args) { - return function(args..., guid_of(), result); + return function(args..., guid_of(), capture_decay{ result }); } template || std::is_union_v, int> = 0> - int32_t capture_to(void** result, O* object, M method, Args&& ...args) + std::int32_t capture_to(void** result, O* object, M method, Args&& ...args) { - return (object->*method)(args..., guid_of(), result); + return (object->*method)(args..., guid_of(), capture_decay{ result }); } template - int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args); + std::int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args); } WINRT_EXPORT namespace winrt @@ -338,12 +349,12 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template - int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args) + std::int32_t capture_to(void** result, com_ptr const& object, M method, Args&& ...args) { - return (object.get()->*(method))(args..., guid_of(), result); + return (object.get()->*(method))(args..., guid_of(), capture_decay{ result }); } } diff --git a/strings/base_composable.h b/strings/base_composable.h index efeb55877..5a7712ef7 100644 --- a/strings/base_composable.h +++ b/strings/base_composable.h @@ -1,9 +1,13 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct composable_factory { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4702) // Compiler bug causing spurious "unreachable code" warnings +#endif template static I CreateInstance(const Windows::Foundation::IInspectable& outer, Windows::Foundation::IInspectable& inner, Args&&... args) { @@ -11,6 +15,9 @@ namespace winrt::impl inner = CreateInstanceImpl(outer, std::forward(args)...); return inner.as(); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif private: template @@ -27,7 +34,7 @@ namespace winrt::impl }; template - class __declspec(empty_bases) produce_dispatch_to_overridable_base + class WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable_base { protected: D& shim() noexcept diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h index 3c309256c..82582ee64 100644 --- a/strings/base_coroutine_foundation.h +++ b/strings/base_coroutine_foundation.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct async_completed_handler; @@ -42,11 +42,12 @@ namespace winrt::impl std::pair make_delegate_with_shared_state(H&& handler) { auto d = make_delegate(std::forward(handler)); - return { std::move(d), reinterpret_cast*>(get_abi(d)) }; + auto abi = reinterpret_cast*>(get_abi(d)); + return { std::move(d), abi }; } template - auto wait_for_completed(Async const& async, uint32_t const timeout) + auto wait_for_completed(Async const& async, std::uint32_t const timeout) { struct shared_type { @@ -71,8 +72,8 @@ namespace winrt::impl { check_sta_blocking_wait(); auto const milliseconds = std::chrono::duration_cast(timeout).count(); - WINRT_ASSERT((milliseconds >= 0) && (static_cast(milliseconds) < 0xFFFFFFFFull)); // Within uint32_t range and not INFINITE - return wait_for_completed(async, static_cast(milliseconds)); + WINRT_ASSERT((milliseconds >= 0) && (static_cast(milliseconds) < 0xFFFFFFFFull)); // Within std::uint32_t range and not INFINITE + return wait_for_completed(async, static_cast(milliseconds)); } inline void check_status_canceled(Windows::Foundation::AsyncStatus status) @@ -98,58 +99,80 @@ namespace winrt::impl return async.GetResults(); } - template - struct disconnect_aware_handler + template + auto wait_get_bypass_sta_check(Async const& async) { - disconnect_aware_handler(Awaiter* awaiter, coroutine_handle<> handle) noexcept + auto status = async.Status(); + if (status == Windows::Foundation::AsyncStatus::Started) + { + status = wait_for_completed(async, 0xFFFFFFFF); // INFINITE + } + check_status_canceled(status); + + return async.GetResults(); + } + +#ifdef WINRT_IMPL_COROUTINES + struct ignore_apartment_context {}; + + template + struct disconnect_aware_handler : private std::conditional_t + { + disconnect_aware_handler(Awaiter* awaiter, std::coroutine_handle<> handle) noexcept : m_awaiter(awaiter), m_handle(handle) { } - disconnect_aware_handler(disconnect_aware_handler&& other) noexcept - : m_context(std::move(other.m_context)) - , m_awaiter(std::exchange(other.m_awaiter, {})) - , m_handle(std::exchange(other.m_handle, {})) { } + disconnect_aware_handler(disconnect_aware_handler&& other) = default; ~disconnect_aware_handler() { - if (m_handle) Complete(); + if (m_handle.value) Complete(); } template void operator()(Async&&, Windows::Foundation::AsyncStatus status) { - m_awaiter->status = status; + m_awaiter.value->status = status; Complete(); } private: - resume_apartment_context m_context; - Awaiter* m_awaiter; - coroutine_handle<> m_handle; + movable_primitive m_awaiter; + movable_primitive, nullptr> m_handle; void Complete() { - if (m_awaiter->suspending.exchange(false, std::memory_order_release)) + if (m_awaiter.value->suspending.exchange(false, std::memory_order_release)) { - m_handle = nullptr; // resumption deferred to await_suspend + m_handle.value = nullptr; // resumption deferred to await_suspend } else { - resume_apartment(m_context, std::exchange(m_handle, {}), &m_awaiter->failure); + auto handle = m_handle.detach(); + if constexpr (preserve_context) + { + if (!resume_apartment(*this, handle, &m_awaiter.value->failure)) + { + handle.resume(); + } + } + else + { + handle.resume(); + } } - } }; -#ifdef WINRT_IMPL_COROUTINES - template - struct await_adapter : enable_await_cancellation + template + struct await_adapter : cancellable_awaiter> { - await_adapter(Async const& async) : async(async) { } + template + await_adapter(T&& async) : async(std::forward(async)) { } - Async const& async; + std::conditional_t async; Windows::Foundation::AsyncStatus status = Windows::Foundation::AsyncStatus::Started; - int32_t failure = 0; - std::atomic suspending{ true }; + std::int32_t failure = 0; + std::atomic suspending = true; void enable_cancellation(cancellable_promise* promise) { @@ -164,18 +187,11 @@ namespace winrt::impl return false; } - auto await_suspend(coroutine_handle<> handle) + template + bool await_suspend(std::coroutine_handle handle) { - auto extend_lifetime = async; - async.Completed(disconnect_aware_handler(this, handle)); -#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED - if (!suspending.exchange(false, std::memory_order_acquire)) - { - handle.resume(); - } -#else - return suspending.exchange(false, std::memory_order_acquire); -#endif + this->set_cancellable_promise_from_handle(handle); + return register_completed_callback(handle); } auto await_resume() const @@ -186,6 +202,17 @@ namespace winrt::impl } private: + bool register_completed_callback(std::coroutine_handle<> handle) + { + if constexpr (!preserve_context) + { + // Ensure that the illegal delegate assignment propagates properly. + suspending.store(true, std::memory_order_relaxed); + } + async.Completed(disconnect_aware_handler(this, handle)); + return suspending.exchange(false, std::memory_order_acquire); + } + static fire_and_forget cancel_asynchronously(Async async) { co_await winrt::resume_background(); @@ -206,6 +233,11 @@ namespace winrt::impl impl::wait_get(static_cast(static_cast(*this))); } template + auto consume_Windows_Foundation_IAsyncAction::get_unchecked() const + { + impl::wait_get_bypass_sta_check(static_cast(static_cast(*this))); + } + template auto consume_Windows_Foundation_IAsyncAction::wait_for(Windows::Foundation::TimeSpan const& timeout) const { return impl::wait_for(static_cast(static_cast(*this)), timeout); @@ -217,6 +249,11 @@ namespace winrt::impl return impl::wait_get(static_cast const&>(static_cast(*this))); } template + auto consume_Windows_Foundation_IAsyncOperation::get_unchecked() const + { + return impl::wait_get_bypass_sta_check(static_cast const&>(static_cast(*this))); + } + template auto consume_Windows_Foundation_IAsyncOperation::wait_for(Windows::Foundation::TimeSpan const& timeout) const { return impl::wait_for(static_cast const&>(static_cast(*this)), timeout); @@ -228,6 +265,11 @@ namespace winrt::impl impl::wait_get(static_cast const&>(static_cast(*this))); } template + auto consume_Windows_Foundation_IAsyncActionWithProgress::get_unchecked() const + { + impl::wait_get_bypass_sta_check(static_cast const&>(static_cast(*this))); + } + template auto consume_Windows_Foundation_IAsyncActionWithProgress::wait_for(Windows::Foundation::TimeSpan const& timeout) const { return impl::wait_for(static_cast const&>(static_cast(*this)), timeout); @@ -239,6 +281,11 @@ namespace winrt::impl return impl::wait_get(static_cast const&>(static_cast(*this))); } template + auto consume_Windows_Foundation_IAsyncOperationWithProgress::get_unchecked() const + { + return impl::wait_get_bypass_sta_check(static_cast const&>(static_cast(*this))); + } + template auto consume_Windows_Foundation_IAsyncOperationWithProgress::wait_for(Windows::Foundation::TimeSpan const& timeout) const { return impl::wait_for(static_cast const&>(static_cast(*this)), timeout); @@ -246,6 +293,15 @@ namespace winrt::impl } #ifdef WINRT_IMPL_COROUTINES +WINRT_EXPORT namespace winrt +{ + template>> + inline impl::await_adapter, false> resume_agile(Async&& async) + { + return { std::forward(async) }; + }; +} + WINRT_EXPORT namespace winrt::Windows::Foundation { inline impl::await_adapter operator co_await(IAsyncAction const& async) @@ -271,7 +327,6 @@ WINRT_EXPORT namespace winrt::Windows::Foundation return{ async }; } } -#endif WINRT_EXPORT namespace winrt { @@ -290,7 +345,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct cancellation_token @@ -304,7 +359,7 @@ namespace winrt::impl return true; } - void await_suspend(coroutine_handle<>) const noexcept + void await_suspend(std::coroutine_handle<>) const noexcept { } @@ -328,6 +383,10 @@ namespace winrt::impl return m_promise->enable_cancellation_propagation(value); } + bool originate_on_cancel(bool value = true) const noexcept + { + return m_promise->originate_on_cancel(value); + } private: Promise* m_promise; @@ -346,7 +405,7 @@ namespace winrt::impl return true; } - void await_suspend(coroutine_handle<>) const noexcept + void await_suspend(std::coroutine_handle<>) const noexcept { } @@ -373,18 +432,18 @@ namespace winrt::impl }; template - struct promise_base : implements + struct promise_base : implements, cancellable_promise { using AsyncStatus = Windows::Foundation::AsyncStatus; unsigned long __stdcall Release() noexcept { - uint32_t const remaining = this->subtract_reference(); + std::uint32_t const remaining = this->subtract_reference(); if (remaining == 0) { std::atomic_thread_fence(std::memory_order_acquire); - coroutine_handle::from_promise(*static_cast(this)).destroy(); + std::coroutine_handle::from_promise(*static_cast(this)).destroy(); } return remaining; @@ -414,7 +473,7 @@ namespace winrt::impl if (handler) { - invoke(handler, *this, status); + winrt::impl::invoke(handler, *this, status); } } @@ -424,7 +483,7 @@ namespace winrt::impl return m_completed; } - uint32_t Id() const noexcept + std::uint32_t Id() const noexcept { return 1; } @@ -461,7 +520,14 @@ namespace winrt::impl if (m_status.load(std::memory_order_relaxed) == AsyncStatus::Started) { m_status.store(AsyncStatus::Canceled, std::memory_order_relaxed); - m_exception = std::make_exception_ptr(hresult_canceled()); + if (cancellable_promise::originate_on_cancel()) + { + m_exception = std::make_exception_ptr(hresult_canceled()); + } + else + { + m_exception = std::make_exception_ptr(hresult_canceled(hresult_error::no_originate)); + } cancel = std::move(m_cancel); } } @@ -471,7 +537,7 @@ namespace winrt::impl cancel(); } - m_cancellable.cancel(); + cancellable_promise::cancel(); } void Close() const noexcept @@ -539,11 +605,11 @@ namespace winrt::impl if (handler) { - invoke(handler, *this, status); + winrt::impl::invoke(handler, *this, status); } } - suspend_never initial_suspend() const noexcept + std::suspend_never initial_suspend() const noexcept { return{}; } @@ -561,10 +627,10 @@ namespace winrt::impl { } - bool await_suspend(coroutine_handle<>) const noexcept + bool await_suspend(std::coroutine_handle<>) const noexcept { promise->set_completed(); - uint32_t const remaining = promise->subtract_reference(); + std::uint32_t const remaining = promise->subtract_reference(); if (remaining == 0) { @@ -577,11 +643,6 @@ namespace winrt::impl auto final_suspend() noexcept { - if (winrt_suspend_handler) - { - winrt_suspend_handler(this); - } - return final_suspend_awaiter{ this }; } @@ -606,14 +667,21 @@ namespace winrt::impl } template - auto await_transform(Expression&& expression) + Expression&& await_transform(Expression&& expression) { if (Status() == AsyncStatus::Canceled) { - throw winrt::hresult_canceled(); + if (cancellable_promise::originate_on_cancel()) + { + throw winrt::hresult_canceled(); + } + else + { + throw winrt::hresult_canceled(hresult_error::no_originate); + } } - return notify_awaiter{ static_cast(expression), m_propagate_cancellation ? &m_cancellable : nullptr }; + return std::forward(expression); } cancellation_token await_transform(get_cancellation_token_t) noexcept @@ -644,11 +712,6 @@ namespace winrt::impl } } - bool enable_cancellation_propagation(bool value) noexcept - { - return std::exchange(m_propagate_cancellation, value); - } - #if defined(_DEBUG) && !defined(WINRT_NO_MAKE_DETECTION) void use_make_function_to_create_this_object() final { @@ -669,18 +732,12 @@ namespace winrt::impl slim_mutex m_lock; async_completed_handler_t m_completed; winrt::delegate<> m_cancel; - cancellable_promise m_cancellable; std::atomic m_status; bool m_completed_assigned{ false }; - bool m_propagate_cancellation{ false }; }; } -#ifdef __cpp_lib_coroutine -namespace std -#else -namespace std::experimental -#endif +WINRT_IMPL_STD_EXPORT namespace std { template struct coroutine_traits @@ -815,7 +872,6 @@ namespace std::experimental WINRT_EXPORT namespace winrt { -#ifdef WINRT_IMPL_COROUTINES template Windows::Foundation::IAsyncAction when_all(T... async) { @@ -861,5 +917,5 @@ WINRT_EXPORT namespace winrt impl::check_status_canceled(shared->status); co_return shared->result.GetResults(); } -#endif } +#endif diff --git a/strings/base_coroutine_system.h b/strings/base_coroutine_system.h index b893bd1b5..f79fe0671 100644 --- a/strings/base_coroutine_system.h +++ b/strings/base_coroutine_system.h @@ -1,4 +1,5 @@ +#ifdef WINRT_IMPL_COROUTINES WINRT_EXPORT namespace winrt { [[nodiscard]] inline auto resume_foreground( @@ -23,7 +24,7 @@ WINRT_EXPORT namespace winrt return m_queued; } - bool await_suspend(impl::coroutine_handle<> handle) + bool await_suspend(std::coroutine_handle<> handle) { return m_dispatcher.TryEnqueue(m_priority, [handle, this] { @@ -41,10 +42,9 @@ WINRT_EXPORT namespace winrt return awaitable{ dispatcher, priority }; }; -#ifdef WINRT_IMPL_COROUTINES inline auto operator co_await(Windows::System::DispatcherQueue const& dispatcher) { return resume_foreground(dispatcher); } -#endif } +#endif diff --git a/strings/base_coroutine_system_winui.h b/strings/base_coroutine_system_winui.h deleted file mode 100644 index ecb3cf766..000000000 --- a/strings/base_coroutine_system_winui.h +++ /dev/null @@ -1,50 +0,0 @@ - -WINRT_EXPORT namespace winrt -{ - [[nodiscard]] inline auto resume_foreground( - Microsoft::System::DispatcherQueue const& dispatcher, - Microsoft::System::DispatcherQueuePriority const priority = Microsoft::System::DispatcherQueuePriority::Normal) noexcept - { - struct awaitable - { - awaitable(Microsoft::System::DispatcherQueue const& dispatcher, Microsoft::System::DispatcherQueuePriority const priority) noexcept : - m_dispatcher(dispatcher), - m_priority(priority) - { - } - - bool await_ready() const noexcept - { - return false; - } - - bool await_resume() const noexcept - { - return m_queued; - } - - bool await_suspend(impl::coroutine_handle<> handle) - { - return m_dispatcher.TryEnqueue(m_priority, [handle, this] - { - m_queued = true; - handle(); - }); - } - - private: - Microsoft::System::DispatcherQueue const& m_dispatcher; - Microsoft::System::DispatcherQueuePriority const m_priority; - bool m_queued{}; - }; - - return awaitable{ dispatcher, priority }; - }; - -#ifdef WINRT_IMPL_COROUTINES - inline auto operator co_await(Microsoft::System::DispatcherQueue const& dispatcher) - { - return resume_foreground(dispatcher); - } -#endif -} diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h index ae77512d7..c901b94ba 100644 --- a/strings/base_coroutine_threadpool.h +++ b/strings/base_coroutine_threadpool.h @@ -1,6 +1,7 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { +#ifdef WINRT_IMPL_COROUTINES inline auto submit_threadpool_callback(void(__stdcall* callback)(void*, void* context), void* context) { if (!WINRT_IMPL_TrySubmitThreadpoolCallback(callback, context, nullptr)) @@ -11,18 +12,19 @@ namespace winrt::impl inline void __stdcall resume_background_callback(void*, void* context) noexcept { - coroutine_handle<>::from_address(context)(); + std::coroutine_handle<>::from_address(context)(); }; - inline auto resume_background(coroutine_handle<> handle) + inline auto resume_background(std::coroutine_handle<> handle) { submit_threadpool_callback(resume_background_callback, handle.address()); } +#endif - inline std::pair get_apartment_type() noexcept + inline std::pair get_apartment_type() noexcept { - int32_t aptType; - int32_t aptTypeQualifier; + std::int32_t aptType; + std::int32_t aptTypeQualifier; if (0 == WINRT_IMPL_CoGetApartmentType(&aptType, &aptTypeQualifier)) { return { aptType, aptTypeQualifier }; @@ -48,36 +50,28 @@ namespace winrt::impl return false; } +#ifdef WINRT_IMPL_COROUTINES struct resume_apartment_context { resume_apartment_context() = default; resume_apartment_context(std::nullptr_t) : m_context(nullptr), m_context_type(-1) {} - resume_apartment_context(resume_apartment_context const&) = default; - resume_apartment_context(resume_apartment_context&& other) noexcept : - m_context(std::move(other.m_context)), m_context_type(std::exchange(other.m_context_type, -1)) {} - resume_apartment_context& operator=(resume_apartment_context const&) = default; - resume_apartment_context& operator=(resume_apartment_context&& other) noexcept - { - m_context = std::move(other.m_context); - m_context_type = std::exchange(other.m_context_type, -1); - return *this; - } + bool valid() const noexcept { - return m_context_type >= 0; + return m_context_type.value >= 0; } com_ptr m_context = try_capture(WINRT_IMPL_CoGetObjectContext); - int32_t m_context_type = get_apartment_type().first; + movable_primitive m_context_type = get_apartment_type().first; }; - inline int32_t __stdcall resume_apartment_callback(com_callback_args* args) noexcept + inline std::int32_t __stdcall resume_apartment_callback(com_callback_args* args) noexcept { - coroutine_handle<>::from_address(args->data)(); + std::coroutine_handle<>::from_address(args->data)(); return 0; }; - inline void resume_apartment_sync(com_ptr const& context, coroutine_handle<> handle, int32_t* failure) + [[nodiscard]] inline bool resume_apartment_sync(com_ptr const& context, std::coroutine_handle<> handle, std::int32_t* failure) { com_callback_args args{}; args.data = handle.address(); @@ -87,74 +81,62 @@ namespace winrt::impl { // Resume the coroutine on the wrong apartment, but tell it why. *failure = result; - handle(); + return false; } + return true; } struct threadpool_resume { - threadpool_resume(com_ptr const& context, coroutine_handle<> handle, int32_t* failure) : + threadpool_resume(com_ptr const& context, std::coroutine_handle<> handle, std::int32_t* failure) : m_context(context), m_handle(handle), m_failure(failure) { } com_ptr m_context; - coroutine_handle<> m_handle; - int32_t* m_failure; + std::coroutine_handle<> m_handle; + std::int32_t* m_failure; }; inline void __stdcall fallback_submit_threadpool_callback(void*, void* p) noexcept { std::unique_ptr state{ static_cast(p) }; - resume_apartment_sync(state->m_context, state->m_handle, state->m_failure); + if (!resume_apartment_sync(state->m_context, state->m_handle, state->m_failure)) + { + state->m_handle.resume(); + } } - inline void resume_apartment_on_threadpool(com_ptr const& context, coroutine_handle<> handle, int32_t* failure) + inline void resume_apartment_on_threadpool(com_ptr const& context, std::coroutine_handle<> handle, std::int32_t* failure) { auto state = std::make_unique(context, handle, failure); submit_threadpool_callback(fallback_submit_threadpool_callback, state.get()); state.release(); } - inline auto resume_apartment(resume_apartment_context const& context, coroutine_handle<> handle, int32_t* failure) + [[nodiscard]] inline auto resume_apartment(resume_apartment_context const& context, std::coroutine_handle<> handle, std::int32_t* failure) { WINRT_ASSERT(context.valid()); if ((context.m_context == nullptr) || (context.m_context == try_capture(WINRT_IMPL_CoGetObjectContext))) { - handle(); + return false; } - else if (context.m_context_type == 1 /* APTTYPE_MTA */) + else if (context.m_context_type.value == 1 /* APTTYPE_MTA */) { resume_background(handle); + return true; } else if (is_sta_thread()) { resume_apartment_on_threadpool(context.m_context, handle, failure); + return true; } else { - resume_apartment_sync(context.m_context, handle, failure); + return resume_apartment_sync(context.m_context, handle, failure); } } - - template - class awaiter_finder - { - template static constexpr bool find_awaitable_member(...) { return false; } - template static constexpr bool find_co_await_member(...) { return false; } - template static constexpr bool find_co_await_free(...) { return false; } - -#ifdef WINRT_IMPL_COROUTINES - template ().await_ready())> static constexpr bool find_awaitable_member(int) { return true; } - template ().operator co_await())> static constexpr bool find_co_await_member(int) { return true; } - template ()))> static constexpr bool find_co_await_free(int) { return true; } #endif - - public: - - static constexpr bool has_awaitable_member = find_awaitable_member(0); - static constexpr bool has_co_await_member = find_co_await_member(0); - static constexpr bool has_co_await_free = find_co_await_free(0); - }; } +#ifdef WINRT_IMPL_COROUTINES WINRT_EXPORT namespace winrt { struct cancellable_promise @@ -164,140 +146,113 @@ WINRT_EXPORT namespace winrt void set_canceller(canceller_t canceller, void* context) { m_context = context; - m_canceller.store(canceller, std::memory_order_release); + canceller_t expected = nullptr; + m_canceller.compare_exchange_strong(expected, canceller, std::memory_order_release, std::memory_order_relaxed); } void revoke_canceller() { - while (m_canceller.exchange(nullptr, std::memory_order_acquire) == cancelling_ptr) + auto existing = m_canceller.load(std::memory_order_relaxed); + do { - std::this_thread::yield(); + while (existing == cancelling_ptr) + { + std::this_thread::yield(); + existing = m_canceller.load(std::memory_order_relaxed); + } } + while (!m_canceller.compare_exchange_weak(existing, nullptr, std::memory_order_acquire, std::memory_order_relaxed)); } void cancel() { auto canceller = m_canceller.exchange(cancelling_ptr, std::memory_order_acquire); - struct unique_cancellation_lock + if (canceller != cancelling_ptr) { - cancellable_promise* promise; - ~unique_cancellation_lock() + struct unique_cancellation_lock { - promise->m_canceller.store(nullptr, std::memory_order_release); - } - } lock{ this }; + cancellable_promise* promise; + ~unique_cancellation_lock() + { + promise->m_canceller.store(nullptr, std::memory_order_release); + } + } lock{ this }; - if ((canceller != nullptr) && (canceller != cancelling_ptr)) - { - canceller(m_context); + if (canceller != nullptr) + { + canceller(m_context); + } } } - private: - static inline auto const cancelling_ptr = reinterpret_cast(1); - - std::atomic m_canceller{ nullptr }; - void* m_context{ nullptr }; - }; - - struct enable_await_cancellation - { - enable_await_cancellation() noexcept = default; - enable_await_cancellation(enable_await_cancellation const&) = default; + bool enable_cancellation_propagation(bool value) noexcept + { + return std::exchange(m_propagate_cancellation, value); + } - ~enable_await_cancellation() + bool cancellation_propagation_enabled() const noexcept { - if (m_promise) - { - m_promise->revoke_canceller(); - } + return m_propagate_cancellation; } - void operator=(enable_await_cancellation const&) = delete; + bool originate_on_cancel(bool value = true) noexcept + { + return std::exchange(m_originate_on_cancel, value); + } - void set_cancellable_promise(cancellable_promise* promise) noexcept + bool should_originate_on_cancel() const noexcept { - m_promise = promise; + return m_originate_on_cancel; } private: + static inline auto const cancelling_ptr = reinterpret_cast(1); - cancellable_promise* m_promise = nullptr; + std::atomic m_canceller{ nullptr }; + void* m_context{ nullptr }; + bool m_propagate_cancellation{ false }; + bool m_originate_on_cancel{ true }; // By default, will call RoOriginateError before throwing a cancel error code. }; -} -namespace winrt::impl -{ - template - decltype(auto) get_awaiter(T&& value) noexcept + template + struct cancellable_awaiter { -#ifdef WINRT_IMPL_COROUTINES - if constexpr (awaiter_finder::has_co_await_member) - { - static_assert(!awaiter_finder::has_co_await_free, "Ambiguous operator co_await (as both member and free function)."); - return static_cast(value).operator co_await(); - } - else if constexpr (awaiter_finder::has_co_await_free) - { - return operator co_await(static_cast(value)); - } - else - { - static_assert(awaiter_finder::has_awaitable_member, "Not an awaitable type"); - return static_cast(value); - } -#else - return static_cast(value); -#endif - } + cancellable_awaiter() noexcept = default; + cancellable_awaiter(cancellable_awaiter const&) = default; - template - struct notify_awaiter - { - decltype(get_awaiter(std::declval())) awaitable; - - notify_awaiter(T&& awaitable_arg, [[maybe_unused]] cancellable_promise* promise = nullptr) : awaitable(get_awaiter(static_cast(awaitable_arg))) + ~cancellable_awaiter() { - if constexpr (std::is_convertible_v&, enable_await_cancellation&>) + if (m_promise) { - if (promise) - { - static_cast(awaitable).set_cancellable_promise(promise); - awaitable.enable_cancellation(promise); - } + m_promise->revoke_canceller(); } } - bool await_ready() + void operator=(cancellable_awaiter const&) = delete; + + protected: + template + void set_cancellable_promise_from_handle(std::coroutine_handle const& handle) { - if (winrt_suspend_handler) + if constexpr (std::is_base_of_v) { - winrt_suspend_handler(this); + set_cancellable_promise(&handle.promise()); } - - return awaitable.await_ready(); } - template - auto await_suspend(coroutine_handle handle) - { - return awaitable.await_suspend(handle); - } - - decltype(auto) await_resume() + private: + void set_cancellable_promise(cancellable_promise* promise) { - if (winrt_resume_handler) + if (promise->cancellation_propagation_enabled()) { - winrt_resume_handler(this); + m_promise = promise; + static_cast(this)->enable_cancellation(m_promise); } - - return awaitable.await_resume(); } + + cancellable_promise* m_promise = nullptr; }; -} -WINRT_EXPORT namespace winrt -{ [[nodiscard]] inline auto resume_background() noexcept { struct awaitable @@ -311,7 +266,7 @@ WINRT_EXPORT namespace winrt { } - void await_suspend(impl::coroutine_handle<> handle) const + void await_suspend(std::coroutine_handle<> handle) const { impl::resume_background(handle); } @@ -338,7 +293,7 @@ WINRT_EXPORT namespace winrt { } - void await_suspend(impl::coroutine_handle<> resume) + void await_suspend(std::coroutine_handle<> resume) { m_resume = resume; @@ -358,7 +313,7 @@ WINRT_EXPORT namespace winrt } T const& m_context; - impl::coroutine_handle<> m_resume{ nullptr }; + std::coroutine_handle<> m_resume{ nullptr }; }; return awaitable{ context }; @@ -376,12 +331,12 @@ WINRT_EXPORT namespace winrt }; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct apartment_awaiter { - apartment_context context; // make a copy because resuming may destruct the original - int32_t failure = 0; + apartment_context const& context; + std::int32_t failure = 0; bool await_ready() const noexcept { @@ -393,229 +348,254 @@ namespace winrt::impl check_hresult(failure); } - void await_suspend(impl::coroutine_handle<> handle) + bool await_suspend(std::coroutine_handle<> handle) { - impl::resume_apartment(context.context, handle, &failure); + auto context_copy = context; + return impl::resume_apartment(context_copy.context, handle, &failure); } }; -} -WINRT_EXPORT namespace winrt -{ -#ifdef WINRT_IMPL_COROUTINES - inline impl::apartment_awaiter operator co_await(apartment_context const& context) + struct timespan_awaiter : cancellable_awaiter { - return{ context }; - } + explicit timespan_awaiter(Windows::Foundation::TimeSpan duration) noexcept : + m_duration(duration) + { + } + +#if defined(__GNUC__) && !defined(__clang__) + // HACK: GCC seems to require a move when calling operator co_await + // on the return value of resume_after. + // This might be related to upstream bug: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99575 + timespan_awaiter(timespan_awaiter &&other) noexcept : + m_timer{std::move(other.m_timer)}, + m_duration{std::move(other.m_duration)}, + m_handle{std::move(other.m_handle)}, + m_state{other.m_state.load()} + {} #endif - [[nodiscard]] inline auto resume_after(Windows::Foundation::TimeSpan duration) noexcept - { - struct awaitable : enable_await_cancellation + void enable_cancellation(cancellable_promise* promise) { - explicit awaitable(Windows::Foundation::TimeSpan duration) noexcept : - m_duration(duration) + promise->set_canceller([](void* context) { - } - - void enable_cancellation(cancellable_promise* promise) - { - promise->set_canceller([](void* context) + auto that = static_cast(context); + if (that->m_state.exchange(state::canceled, std::memory_order_acquire) == state::pending) { - auto that = static_cast(context); - if (that->m_state.exchange(state::canceled, std::memory_order_acquire) == state::pending) - { - that->fire_immediately(); - } - }, this); - } + that->fire_immediately(); + } + }, this); + } - bool await_ready() const noexcept - { - return m_duration.count() <= 0; - } + bool await_ready() const noexcept + { + return m_duration.count() <= 0; + } - void await_suspend(impl::coroutine_handle<> handle) - { - m_handle = handle; - m_timer.attach(check_pointer(WINRT_IMPL_CreateThreadpoolTimer(callback, this, nullptr))); - int64_t relative_count = -m_duration.count(); - WINRT_IMPL_SetThreadpoolTimer(m_timer.get(), &relative_count, 0, 0); + template + void await_suspend(std::coroutine_handle handle) + { + set_cancellable_promise_from_handle(handle); - state expected = state::idle; - if (!m_state.compare_exchange_strong(expected, state::pending, std::memory_order_release)) - { - fire_immediately(); - } - } + m_handle = handle; + create_threadpool_timer(); + } - void await_resume() + void await_resume() + { + if (m_state.exchange(state::idle, std::memory_order_relaxed) == state::canceled) { - if (m_state.exchange(state::idle, std::memory_order_relaxed) == state::canceled) - { - throw hresult_canceled(); - } + throw hresult_canceled(); } + } - private: + private: + void create_threadpool_timer() + { + m_timer.attach(check_pointer(WINRT_IMPL_CreateThreadpoolTimer(callback, this, nullptr))); + std::int64_t relative_count = -m_duration.count(); + WINRT_IMPL_SetThreadpoolTimer(m_timer.get(), &relative_count, 0, 0); - static int32_t __stdcall fallback_SetThreadpoolTimerEx(winrt::impl::ptp_timer, void*, uint32_t, uint32_t) noexcept + state expected = state::idle; + if (!m_state.compare_exchange_strong(expected, state::pending, std::memory_order_release)) { - return 0; // pretend timer has already triggered and a callback is on its way + fire_immediately(); } + } - void fire_immediately() noexcept + void fire_immediately() noexcept + { + if (WINRT_IMPL_SetThreadpoolTimerEx(m_timer.get(), nullptr, 0, 0)) { - static int32_t(__stdcall* handler)(winrt::impl::ptp_timer, void*, uint32_t, uint32_t) noexcept; - impl::load_runtime_function(L"kernel32.dll", "SetThreadpoolTimerEx", handler, fallback_SetThreadpoolTimerEx); - - if (handler(m_timer.get(), nullptr, 0, 0)) - { - int64_t now = 0; - WINRT_IMPL_SetThreadpoolTimer(m_timer.get(), &now, 0, 0); - } + std::int64_t now = 0; + WINRT_IMPL_SetThreadpoolTimer(m_timer.get(), &now, 0, 0); } + } + + static void __stdcall callback(void*, void* context, void*) noexcept + { + auto that = reinterpret_cast(context); + that->m_handle(); + } + + struct timer_traits + { + using type = impl::ptp_timer; - static void __stdcall callback(void*, void* context, void*) noexcept + static void close(type value) noexcept { - auto that = reinterpret_cast(context); - that->m_handle(); + WINRT_IMPL_CloseThreadpoolTimer(value); } - struct timer_traits + static constexpr type invalid() noexcept { - using type = impl::ptp_timer; - - static void close(type value) noexcept - { - WINRT_IMPL_CloseThreadpoolTimer(value); - } - - static constexpr type invalid() noexcept - { - return nullptr; - } - }; - - enum class state { idle, pending, canceled }; - - handle_type m_timer; - Windows::Foundation::TimeSpan m_duration; - impl::coroutine_handle<> m_handle; - std::atomic m_state{ state::idle }; + return nullptr; + } }; - return awaitable{ duration }; - } + enum class state { idle, pending, canceled }; -#ifdef WINRT_IMPL_COROUTINES - inline auto operator co_await(Windows::Foundation::TimeSpan duration) + handle_type m_timer; + Windows::Foundation::TimeSpan m_duration; + std::coroutine_handle<> m_handle; + std::atomic m_state{ state::idle }; + }; + + struct signal_awaiter : cancellable_awaiter { - return resume_after(duration); - } + signal_awaiter(void* handle, Windows::Foundation::TimeSpan timeout) noexcept : + m_timeout(timeout), + m_handle(handle) + {} + +#if defined(__GNUC__) && !defined(__clang__) + // HACK: GCC seems to require a move when calling operator co_await + // on the return value of resume_on_signal. + // This might be related to upstream bug: + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99575 + signal_awaiter(signal_awaiter &&other) noexcept : + m_wait{std::move(other.m_wait)}, + m_timeout{std::move(other.m_timeout)}, + m_handle{std::move(other.m_handle)}, + m_result{std::move(other.m_result)}, + m_resume{std::move(other.m_resume)}, + m_state{other.m_state.load()} + {} #endif - [[nodiscard]] inline auto resume_on_signal(void* handle, Windows::Foundation::TimeSpan timeout = {}) noexcept - { - struct awaitable : enable_await_cancellation + void enable_cancellation(cancellable_promise* promise) { - awaitable(void* handle, Windows::Foundation::TimeSpan timeout) noexcept : - m_timeout(timeout), - m_handle(handle) - {} - - void enable_cancellation(cancellable_promise* promise) + promise->set_canceller([](void* context) { - promise->set_canceller([](void* context) + auto that = static_cast(context); + if (that->m_state.exchange(state::canceled, std::memory_order_acquire) == state::pending) { - auto that = static_cast(context); - if (that->m_state.exchange(state::canceled, std::memory_order_acquire) == state::pending) - { - that->fire_immediately(); - } - }, this); - } + that->fire_immediately(); + } + }, this); + } - bool await_ready() const noexcept + bool await_ready() const noexcept + { + return WINRT_IMPL_WaitForSingleObject(m_handle, 0) == 0; + } + + template + void await_suspend(std::coroutine_handle resume) + { + set_cancellable_promise_from_handle(resume); + + m_resume = resume; + create_threadpool_wait(); + } + + bool await_resume() + { + if (m_state.exchange(state::idle, std::memory_order_relaxed) == state::canceled) { - return WINRT_IMPL_WaitForSingleObject(m_handle, 0) == 0; + throw hresult_canceled(); } + return m_result == 0; + } - void await_suspend(impl::coroutine_handle<> resume) - { - m_resume = resume; - m_wait.attach(check_pointer(WINRT_IMPL_CreateThreadpoolWait(callback, this, nullptr))); - int64_t relative_count = -m_timeout.count(); - int64_t* file_time = relative_count != 0 ? &relative_count : nullptr; - WINRT_IMPL_SetThreadpoolWait(m_wait.get(), m_handle, file_time); + private: - state expected = state::idle; - if (!m_state.compare_exchange_strong(expected, state::pending, std::memory_order_release)) - { - fire_immediately(); - } - } + void create_threadpool_wait() + { + m_wait.attach(check_pointer(WINRT_IMPL_CreateThreadpoolWait(callback, this, nullptr))); + std::int64_t relative_count = -m_timeout.count(); + std::int64_t* file_time = relative_count != 0 ? &relative_count : nullptr; + WINRT_IMPL_SetThreadpoolWait(m_wait.get(), m_handle, file_time); - bool await_resume() + state expected = state::idle; + if (!m_state.compare_exchange_strong(expected, state::pending, std::memory_order_release)) { - if (m_state.exchange(state::idle, std::memory_order_relaxed) == state::canceled) - { - throw hresult_canceled(); - } - return m_result == 0; + fire_immediately(); } + } - private: - static int32_t __stdcall fallback_SetThreadpoolWaitEx(winrt::impl::ptp_wait, void*, void*, void*) noexcept + void fire_immediately() noexcept + { + if (WINRT_IMPL_SetThreadpoolWaitEx(m_wait.get(), nullptr, nullptr, nullptr)) { - return 0; // pretend wait has already triggered and a callback is on its way + std::int64_t now = 0; + WINRT_IMPL_SetThreadpoolWait(m_wait.get(), WINRT_IMPL_GetCurrentProcess(), &now); } + } - void fire_immediately() noexcept - { - static int32_t(__stdcall* handler)(winrt::impl::ptp_wait, void*, void*, void*) noexcept; - impl::load_runtime_function(L"kernel32.dll", "SetThreadpoolWaitEx", handler, fallback_SetThreadpoolWaitEx); + static void __stdcall callback(void*, void* context, void*, std::uint32_t result) noexcept + { + auto that = static_cast(context); + that->m_result = result; + that->m_resume(); + } - if (handler(m_wait.get(), nullptr, nullptr, nullptr)) - { - int64_t now = 0; - WINRT_IMPL_SetThreadpoolWait(m_wait.get(), WINRT_IMPL_GetCurrentProcess(), &now); - } - } + struct wait_traits + { + using type = impl::ptp_wait; - static void __stdcall callback(void*, void* context, void*, uint32_t result) noexcept + static void close(type value) noexcept { - auto that = static_cast(context); - that->m_result = result; - that->m_resume(); + WINRT_IMPL_CloseThreadpoolWait(value); } - struct wait_traits + static constexpr type invalid() noexcept { - using type = impl::ptp_wait; + return nullptr; + } + }; - static void close(type value) noexcept - { - WINRT_IMPL_CloseThreadpoolWait(value); - } + enum class state { idle, pending, canceled }; - static constexpr type invalid() noexcept - { - return nullptr; - } - }; + handle_type m_wait; + Windows::Foundation::TimeSpan m_timeout; + void* m_handle; + std::uint32_t m_result{}; + std::coroutine_handle<> m_resume{ nullptr }; + std::atomic m_state{ state::idle }; + }; +} - enum class state { idle, pending, canceled }; +WINRT_EXPORT namespace winrt +{ + inline impl::apartment_awaiter operator co_await(apartment_context const& context) + { + return{ context }; + } - handle_type m_wait; - Windows::Foundation::TimeSpan m_timeout; - void* m_handle; - uint32_t m_result{}; - impl::coroutine_handle<> m_resume{ nullptr }; - std::atomic m_state{ state::idle }; - }; + [[nodiscard]] inline impl::timespan_awaiter resume_after(Windows::Foundation::TimeSpan duration) noexcept + { + return impl::timespan_awaiter{ duration }; + } - return awaitable{ handle, timeout }; + inline impl::timespan_awaiter operator co_await(Windows::Foundation::TimeSpan duration) + { + return resume_after(duration); + } + + [[nodiscard]] inline impl::signal_awaiter resume_on_signal(void* handle, Windows::Foundation::TimeSpan timeout = {}) noexcept + { + return impl::signal_awaiter{ handle, timeout }; } struct thread_pool @@ -626,7 +606,7 @@ WINRT_EXPORT namespace winrt m_environment.Pool = m_pool.get(); } - void thread_limits(uint32_t const high, uint32_t const low) + void thread_limits(std::uint32_t const high, std::uint32_t const low) { WINRT_IMPL_SetThreadpoolThreadMaximum(m_pool.get(), high); check_bool(WINRT_IMPL_SetThreadpoolThreadMinimum(m_pool.get(), low)); @@ -641,7 +621,7 @@ WINRT_EXPORT namespace winrt { } - void await_suspend(impl::coroutine_handle<> handle) + void await_suspend(std::coroutine_handle<> handle) { if (!WINRT_IMPL_TrySubmitThreadpoolCallback(callback, handle.address(), &m_environment)) { @@ -653,7 +633,7 @@ WINRT_EXPORT namespace winrt static void __stdcall callback(void*, void* context) noexcept { - impl::coroutine_handle<>::from_address(context)(); + std::coroutine_handle<>::from_address(context)(); } struct pool_traits @@ -673,7 +653,7 @@ WINRT_EXPORT namespace winrt struct environment // TP_CALLBACK_ENVIRON { - uint32_t Version{ 3 }; + std::uint32_t Version{ 3 }; void* Pool{}; void* CleanupGroup{}; void* CleanupGroupCancelCallback{}; @@ -682,16 +662,16 @@ WINRT_EXPORT namespace winrt void* FinalizationCallback{}; union { - uint32_t Flags{}; + std::uint32_t Flags{}; struct { - uint32_t LongFunction : 1; - uint32_t Persistent : 1; - uint32_t Private : 30; + std::uint32_t LongFunction : 1; + std::uint32_t Persistent : 1; + std::uint32_t Private : 30; } s; } u; - int32_t CallbackPriority{ 1 }; - uint32_t Size{ sizeof(environment) }; + std::int32_t CallbackPriority{ 1 }; + std::uint32_t Size{ sizeof(environment) }; }; handle_type m_pool; @@ -701,11 +681,7 @@ WINRT_EXPORT namespace winrt struct fire_and_forget {}; } -#ifdef __cpp_lib_coroutine -namespace std -#else -namespace std::experimental -#endif +WINRT_IMPL_STD_EXPORT namespace std { template struct coroutine_traits @@ -721,18 +697,13 @@ namespace std::experimental { } - suspend_never initial_suspend() const noexcept + std::suspend_never initial_suspend() const noexcept { return{}; } - suspend_never final_suspend() const noexcept + std::suspend_never final_suspend() const noexcept { - if (winrt_suspend_handler) - { - winrt_suspend_handler(this); - } - return{}; } @@ -740,12 +711,7 @@ namespace std::experimental { winrt::terminate(); } - - template - auto await_transform(Expression&& expression) - { - return winrt::impl::notify_awaiter{ static_cast(expression) }; - } }; }; } +#endif diff --git a/strings/base_coroutine_ui_core.h b/strings/base_coroutine_ui_core.h index dab34c8de..7efed5174 100644 --- a/strings/base_coroutine_ui_core.h +++ b/strings/base_coroutine_ui_core.h @@ -1,4 +1,5 @@ +#ifdef WINRT_IMPL_COROUTINES WINRT_EXPORT namespace winrt { [[nodiscard]] inline auto resume_foreground( @@ -22,7 +23,7 @@ WINRT_EXPORT namespace winrt { } - void await_suspend(impl::coroutine_handle<> handle) const + void await_suspend(std::coroutine_handle<> handle) const { m_dispatcher.RunAsync(m_priority, [handle] { @@ -39,10 +40,9 @@ WINRT_EXPORT namespace winrt return awaitable{ dispatcher, priority }; }; -#ifdef WINRT_IMPL_COROUTINES inline auto operator co_await(Windows::UI::Core::CoreDispatcher const& dispatcher) { return resume_foreground(dispatcher); } -#endif } +#endif diff --git a/strings/base_deferral.h b/strings/base_deferral.h index ceab1cd4b..cc6f724e5 100644 --- a/strings/base_deferral.h +++ b/strings/base_deferral.h @@ -1,7 +1,7 @@ +#ifdef WINRT_IMPL_COROUTINES WINRT_EXPORT namespace winrt { -#ifdef WINRT_IMPL_COROUTINES template struct deferrable_event_args { @@ -22,9 +22,9 @@ WINRT_EXPORT namespace winrt [[nodiscard]] Windows::Foundation::IAsyncAction wait_for_deferrals() { - struct awaitable : impl::suspend_always + struct awaitable : std::suspend_always { - bool await_suspend(coroutine_handle handle) + bool await_suspend(std::coroutine_handle<> handle) { return m_deferrable.await_suspend(handle); } @@ -37,11 +37,9 @@ WINRT_EXPORT namespace winrt private: - using coroutine_handle = impl::coroutine_handle<>; - void one_deferral_completed() { - coroutine_handle resume = nullptr; + std::coroutine_handle<> resume = nullptr; { slim_lock_guard const guard(m_lock); @@ -62,7 +60,7 @@ WINRT_EXPORT namespace winrt } } - bool await_suspend(coroutine_handle handle) noexcept + bool await_suspend(std::coroutine_handle<> handle) noexcept { slim_lock_guard const guard(m_lock); m_handle = handle; @@ -70,8 +68,8 @@ WINRT_EXPORT namespace winrt } slim_mutex m_lock; - int32_t m_outstanding_deferrals = 0; - coroutine_handle m_handle = nullptr; + std::int32_t m_outstanding_deferrals = 0; + std::coroutine_handle<> m_handle = nullptr; }; -#endif } +#endif diff --git a/strings/base_delegate.h b/strings/base_delegate.h index 1ba8b4d69..1fe00ecd1 100644 --- a/strings/base_delegate.h +++ b/strings/base_delegate.h @@ -1,44 +1,65 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4458) // declaration hides class member (okay because we do not use named members of base class) #endif - template - struct implements_delegate : abi_t, H, update_module_lock + struct implements_delegate_base { - implements_delegate(H&& handler) : H(std::forward(handler)) + WINRT_IMPL_NOINLINE std::uint32_t increment_reference() noexcept + { + return ++m_references; + } + + WINRT_IMPL_NOINLINE std::uint32_t decrement_reference() noexcept { + return --m_references; } - int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final + WINRT_IMPL_NOINLINE std::uint32_t query_interface(guid const& id, void** result, unknown_abi* derivedAbiPtr, guid const& derivedId) noexcept { - if (is_guid_of(id) || is_guid_of(id) || is_guid_of(id)) + if (id == derivedId || is_guid_of(id) || is_guid_of(id)) { - *result = static_cast*>(this); - AddRef(); + *result = derivedAbiPtr; + increment_reference(); return 0; } if (is_guid_of(id)) { - return make_marshaler(this, result); + return make_marshaler(derivedAbiPtr, result); } *result = nullptr; return error_no_interface; } - uint32_t __stdcall AddRef() noexcept final + private: + atomic_ref_count m_references{ 1 }; + }; + + template + struct implements_delegate : abi_t, implements_delegate_base, H, update_module_lock + { + implements_delegate(H&& handler) : H(std::forward(handler)) { - return ++m_references; } - uint32_t __stdcall Release() noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final + { + return query_interface(id, result, static_cast*>(this), guid_of()); + } + + std::uint32_t __stdcall AddRef() noexcept final { - auto const remaining = --m_references; + return increment_reference(); + } + + std::uint32_t __stdcall Release() noexcept final + { + auto const remaining = decrement_reference(); if (remaining == 0) { @@ -47,10 +68,6 @@ namespace winrt::impl return remaining; } - - private: - - atomic_ref_count m_references{ 1 }; }; template @@ -73,15 +90,16 @@ namespace winrt::impl return delegate; } + const auto id = guid_of(); com_ptr ref; - get_agile_reference(guid_of(), get_abi(delegate), ref.put_void()); + get_agile_reference(id, get_abi(delegate), ref.put_void()); if (ref) { - return [ref = std::move(ref)](auto&& ... args) + return [ref = std::move(ref), id](auto&& ... args) { T delegate; - ref->Resolve(guid_of(), put_abi(delegate)); + ref->Resolve(id, put_abi(delegate)); return delegate(args...); }; } @@ -91,13 +109,13 @@ namespace winrt::impl } template - struct __declspec(novtable) variadic_delegate_abi : unknown_abi + struct WINRT_IMPL_ABI_DECL variadic_delegate_abi : unknown_abi { virtual R invoke(Args const& ...) = 0; }; template - struct variadic_delegate final : variadic_delegate_abi, H, update_module_lock + struct variadic_delegate final : variadic_delegate_abi, implements_delegate_base, H, update_module_lock { variadic_delegate(H&& handler) : H(std::forward(handler)) { @@ -115,27 +133,19 @@ namespace winrt::impl } } - int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final { - if (is_guid_of(id) || is_guid_of(id)) - { - *result = static_cast(this); - AddRef(); - return 0; - } - - *result = nullptr; - return error_no_interface; + return query_interface(id, result, static_cast(this), guid_of()); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { - return ++m_references; + return increment_reference(); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { - auto const remaining = --m_references; + auto const remaining = decrement_reference(); if (remaining == 0) { @@ -144,14 +154,10 @@ namespace winrt::impl return remaining; } - - private: - - atomic_ref_count m_references{ 1 }; }; template - struct __declspec(empty_bases) delegate_base : Windows::Foundation::IUnknown + struct WINRT_IMPL_EMPTY_BASES delegate_base : Windows::Foundation::IUnknown { delegate_base(std::nullptr_t = nullptr) noexcept {} delegate_base(void* ptr, take_ownership_from_abi_t) noexcept : IUnknown(ptr, take_ownership_from_abi) {} @@ -174,8 +180,24 @@ namespace winrt::impl { } - template delegate_base(winrt::weak_ref&& object, M method) : - delegate_base([o = std::move(object), method](auto&& ... args) { if (auto s = o.get()) { ((*s).*(method))(args...); } }) + template delegate_base(winrt::weak_ref&& object, LM&& lambda_or_method) : + delegate_base([o = std::move(object), lm = std::forward(lambda_or_method)](auto&&... args) { if (auto s = o.get()) { + if constexpr (std::is_member_function_pointer_v) ((*s).*(lm))(args...); + else lm(args...); + }}) + { + } + + template delegate_base(std::shared_ptr&& object, M method) : + delegate_base([o = std::move(object), method](auto&& ... args) { return ((*o).*(method))(args...); }) + { + } + + template delegate_base(std::weak_ptr&& object, LM&& lambda_or_method) : + delegate_base([o = std::move(object), lm = std::forward(lambda_or_method)](auto&&... args) { if (auto s = o.lock()) { + if constexpr (std::is_member_function_pointer_v) ((*s).*(lm))(args...); + else lm(args...); + }}) { } @@ -201,13 +223,13 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { template - struct __declspec(empty_bases) delegate : impl::delegate_base + struct WINRT_IMPL_EMPTY_BASES delegate : impl::delegate_base { using impl::delegate_base::delegate_base; }; template - struct __declspec(empty_bases) delegate : impl::delegate_base + struct WINRT_IMPL_EMPTY_BASES delegate : impl::delegate_base { using impl::delegate_base::delegate_base; }; diff --git a/strings/base_detect_numerics.h b/strings/base_detect_numerics.h new file mode 100644 index 000000000..6a93a8ffa --- /dev/null +++ b/strings/base_detect_numerics.h @@ -0,0 +1,4 @@ + +#if __has_include() +#define WINRT_IMPL_NUMERICS +#endif diff --git a/strings/base_error.h b/strings/base_error.h index 45ed39cd3..d42ca516b 100644 --- a/strings/base_error.h +++ b/strings/base_error.h @@ -1,6 +1,5 @@ #if defined(_MSC_VER) -#include #define WINRT_IMPL_RETURNADDRESS() _ReturnAddress() #elif defined(__GNUC__) #define WINRT_IMPL_RETURNADDRESS() __builtin_extract_return_addr(__builtin_return_address(0)) @@ -8,7 +7,7 @@ #define WINRT_IMPL_RETURNADDRESS() nullptr #endif -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct heap_traits { @@ -42,11 +41,11 @@ namespace winrt::impl using bstr_handle = handle_type; - inline hstring trim_hresult_message(wchar_t const* const message, uint32_t size) noexcept + inline hstring trim_hresult_message(wchar_t const* const message, std::uint32_t size) noexcept { wchar_t const* back = message + size - 1; - while (size&& iswspace(*back)) + while (size && std::iswspace(*back)) { --size; --back; @@ -59,7 +58,7 @@ namespace winrt::impl { handle_type message; - uint32_t const size = WINRT_IMPL_FormatMessageW(0x00001300, // FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS + std::uint32_t const size = WINRT_IMPL_FormatMessageW(0x00001300, // FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS nullptr, code, 0x00000400, // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) @@ -70,116 +69,14 @@ namespace winrt::impl return trim_hresult_message(message.get(), size); } - constexpr int32_t hresult_from_win32(uint32_t const x) noexcept + constexpr std::int32_t hresult_from_win32(std::uint32_t const x) noexcept { - return (int32_t)(x) <= 0 ? (int32_t)(x) : (int32_t)(((x) & 0x0000FFFF) | (7 << 16) | 0x80000000); + return (std::int32_t)(x) <= 0 ? (std::int32_t)(x) : (std::int32_t)(((x) & 0x0000FFFF) | (7 << 16) | 0x80000000); } - constexpr int32_t hresult_from_nt(uint32_t const x) noexcept + constexpr std::int32_t hresult_from_nt(std::uint32_t const x) noexcept { - return ((int32_t)((x) | 0x10000000)); - } - - struct error_info_fallback final : IErrorInfo, IRestrictedErrorInfo, update_module_lock - { - error_info_fallback(int32_t code, void* message) noexcept : - m_code(code), - m_message(message ? *reinterpret_cast(&message) : message_from_hresult(code)) - { - } - - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final - { - if (is_guid_of(id) || is_guid_of(id) || is_guid_of(id)) - { - *object = static_cast(this); - AddRef(); - return 0; - } - - if (is_guid_of(id)) - { - *object = static_cast(this); - AddRef(); - return 0; - } - - *object = nullptr; - return error_no_interface; - } - - uint32_t __stdcall AddRef() noexcept final - { - return ++m_references; - } - - uint32_t __stdcall Release() noexcept final - { - auto const remaining = --m_references; - - if (remaining == 0) - { - delete this; - } - - return remaining; - } - - int32_t __stdcall GetGUID(guid* value) noexcept final - { - *value = {}; - return 0; - } - - int32_t __stdcall GetSource(bstr* value) noexcept final - { - *value = nullptr; - return 0; - } - - int32_t __stdcall GetDescription(bstr* value) noexcept final - { - *value = WINRT_IMPL_SysAllocString(m_message.c_str()); - return *value ? error_ok : error_bad_alloc; - } - - int32_t __stdcall GetHelpFile(bstr* value) noexcept final - { - *value = nullptr; - return 0; - } - - int32_t __stdcall GetHelpContext(uint32_t* value) noexcept final - { - *value = 0; - return 0; - } - - int32_t __stdcall GetErrorDetails(bstr* fallback, int32_t* error, bstr* message, bstr* capability) noexcept final - { - *fallback = nullptr; - *error = m_code; - *capability = nullptr; - *message = WINRT_IMPL_SysAllocString(m_message.c_str()); - return *message ? error_ok : error_bad_alloc; - } - - int32_t __stdcall GetReference(bstr* value) noexcept final - { - *value = nullptr; - return 0; - } - - private: - - hresult const m_code; - hstring const m_message; - atomic_ref_count m_references{ 1 }; - }; - - [[noreturn]] inline void __stdcall fallback_RoFailFastWithErrorContext(int32_t) noexcept - { - abort(); + return ((std::int32_t)((x) | 0x10000000)); } } @@ -187,6 +84,9 @@ WINRT_EXPORT namespace winrt { struct hresult_error { + struct no_originate_t {}; + static constexpr no_originate_t no_originate{}; + using from_abi_t = take_ownership_from_abi_t; static constexpr auto from_abi{ take_ownership_from_abi }; @@ -207,17 +107,21 @@ WINRT_EXPORT namespace winrt return *this; } - explicit hresult_error(hresult const code) noexcept : m_code(verify_error(code)) + explicit hresult_error(hresult const code, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : m_code(verify_error(code)) { - originate(code, nullptr); + originate(code, nullptr, sourceInformation); } - hresult_error(hresult const code, param::hstring const& message) noexcept : m_code(verify_error(code)) + explicit hresult_error(hresult const code, no_originate_t) noexcept : m_code(verify_error(code)) { - originate(code, get_abi(message)); } - hresult_error(hresult const code, take_ownership_from_abi_t) noexcept : m_code(verify_error(code)) + hresult_error(hresult const code, param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : m_code(verify_error(code)) + { + originate(code, get_abi(message), sourceInformation); + } + + hresult_error(hresult const code, take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : m_code(verify_error(code)) { com_ptr info; WINRT_IMPL_GetErrorInfo(0, info.put_void()); @@ -247,7 +151,7 @@ WINRT_EXPORT namespace winrt message = impl::trim_hresult_message(legacy.get(), WINRT_IMPL_SysStringLen(legacy.get())); } - originate(code, get_abi(message)); + originate(code, get_abi(message), sourceInformation); } } @@ -260,7 +164,7 @@ WINRT_EXPORT namespace winrt { if (m_info) { - int32_t code{}; + std::int32_t code{}; impl::bstr_handle fallback; impl::bstr_handle message; impl::bstr_handle unused; @@ -302,22 +206,21 @@ WINRT_EXPORT namespace winrt private: - static int32_t __stdcall fallback_RoOriginateLanguageException(int32_t error, void* message, void*) noexcept + void originate(hresult const code, void* message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept { - com_ptr info(new (std::nothrow) impl::error_info_fallback(error, message), take_ownership_from_abi); - WINRT_VERIFY_(0, WINRT_IMPL_SetErrorInfo(0, info.get())); - return 1; - } + WINRT_VERIFY(WINRT_IMPL_RoOriginateLanguageException(code, message, nullptr)); - void originate(hresult const code, void* message) noexcept - { - static int32_t(__stdcall* handler)(int32_t error, void* message, void* exception) noexcept; - impl::load_runtime_function(L"combase.dll", "RoOriginateLanguageException", handler, fallback_RoOriginateLanguageException); - WINRT_VERIFY(handler(code, message, nullptr)); + // This is an extension point that can be filled in by other libraries (such as WIL) to get call outs when errors are + // originated. This is intended for logging purposes. When possible include the std::source_information so that accurate + // information is available on the caller who generated the error. + if (winrt_throw_hresult_handler) + { + winrt_throw_hresult_handler(sourceInformation.line(), sourceInformation.file_name(), sourceInformation.function_name(), WINRT_IMPL_RETURNADDRESS(), code); + } com_ptr info; - WINRT_VERIFY_(0, WINRT_IMPL_GetErrorInfo(0, info.put_void())); - WINRT_VERIFY(info.try_as(m_info)); + WINRT_IMPL_GetErrorInfo(0, info.put_void()); + info.try_as(m_info); } static hresult verify_error(hresult const code) noexcept @@ -333,7 +236,7 @@ WINRT_EXPORT namespace winrt #endif impl::bstr_handle m_debug_reference; - uint32_t m_debug_magic{ 0xAABBCCDD }; + std::uint32_t m_debug_magic{ 0xAABBCCDD }; hresult m_code{ impl::error_fail }; com_ptr m_info; @@ -344,100 +247,101 @@ WINRT_EXPORT namespace winrt struct hresult_access_denied : hresult_error { - hresult_access_denied() noexcept : hresult_error(impl::error_access_denied) {} - hresult_access_denied(param::hstring const& message) noexcept : hresult_error(impl::error_access_denied, message) {} - hresult_access_denied(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_access_denied, take_ownership_from_abi) {} + hresult_access_denied(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_access_denied, sourceInformation) {} + hresult_access_denied(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_access_denied, message, sourceInformation) {} + hresult_access_denied(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_access_denied, take_ownership_from_abi, sourceInformation) {} }; struct hresult_wrong_thread : hresult_error { - hresult_wrong_thread() noexcept : hresult_error(impl::error_wrong_thread) {} - hresult_wrong_thread(param::hstring const& message) noexcept : hresult_error(impl::error_wrong_thread, message) {} - hresult_wrong_thread(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_wrong_thread, take_ownership_from_abi) {} + hresult_wrong_thread(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_wrong_thread, sourceInformation) {} + hresult_wrong_thread(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_wrong_thread, message, sourceInformation) {} + hresult_wrong_thread(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_wrong_thread, take_ownership_from_abi, sourceInformation) {} }; struct hresult_not_implemented : hresult_error { - hresult_not_implemented() noexcept : hresult_error(impl::error_not_implemented) {} - hresult_not_implemented(param::hstring const& message) noexcept : hresult_error(impl::error_not_implemented, message) {} - hresult_not_implemented(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_not_implemented, take_ownership_from_abi) {} + hresult_not_implemented(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_not_implemented, sourceInformation) {} + hresult_not_implemented(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_not_implemented, message, sourceInformation) {} + hresult_not_implemented(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_not_implemented, take_ownership_from_abi, sourceInformation) {} }; struct hresult_invalid_argument : hresult_error { - hresult_invalid_argument() noexcept : hresult_error(impl::error_invalid_argument) {} - hresult_invalid_argument(param::hstring const& message) noexcept : hresult_error(impl::error_invalid_argument, message) {} - hresult_invalid_argument(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_invalid_argument, take_ownership_from_abi) {} + hresult_invalid_argument(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_invalid_argument, sourceInformation) {} + hresult_invalid_argument(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_invalid_argument, message, sourceInformation) {} + hresult_invalid_argument(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_invalid_argument, take_ownership_from_abi, sourceInformation) {} }; struct hresult_out_of_bounds : hresult_error { - hresult_out_of_bounds() noexcept : hresult_error(impl::error_out_of_bounds) {} - hresult_out_of_bounds(param::hstring const& message) noexcept : hresult_error(impl::error_out_of_bounds, message) {} - hresult_out_of_bounds(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_out_of_bounds, take_ownership_from_abi) {} + hresult_out_of_bounds(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_out_of_bounds, sourceInformation) {} + hresult_out_of_bounds(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_out_of_bounds, message, sourceInformation) {} + hresult_out_of_bounds(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_out_of_bounds, take_ownership_from_abi, sourceInformation) {} }; struct hresult_no_interface : hresult_error { - hresult_no_interface() noexcept : hresult_error(impl::error_no_interface) {} - hresult_no_interface(param::hstring const& message) noexcept : hresult_error(impl::error_no_interface, message) {} - hresult_no_interface(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_no_interface, take_ownership_from_abi) {} + hresult_no_interface(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_no_interface, sourceInformation) {} + hresult_no_interface(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_no_interface, message, sourceInformation) {} + hresult_no_interface(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_no_interface, take_ownership_from_abi, sourceInformation) {} }; struct hresult_class_not_available : hresult_error { - hresult_class_not_available() noexcept : hresult_error(impl::error_class_not_available) {} - hresult_class_not_available(param::hstring const& message) noexcept : hresult_error(impl::error_class_not_available, message) {} - hresult_class_not_available(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_class_not_available, take_ownership_from_abi) {} + hresult_class_not_available(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_available, sourceInformation) {} + hresult_class_not_available(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_available, message, sourceInformation) {} + hresult_class_not_available(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_available, take_ownership_from_abi, sourceInformation) {} }; struct hresult_class_not_registered : hresult_error { - hresult_class_not_registered() noexcept : hresult_error(impl::error_class_not_registered) {} - hresult_class_not_registered(param::hstring const& message) noexcept : hresult_error(impl::error_class_not_registered, message) {} - hresult_class_not_registered(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_class_not_registered, take_ownership_from_abi) {} + hresult_class_not_registered(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_registered, sourceInformation) {} + hresult_class_not_registered(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_registered, message, sourceInformation) {} + hresult_class_not_registered(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_class_not_registered, take_ownership_from_abi, sourceInformation) {} }; struct hresult_changed_state : hresult_error { - hresult_changed_state() noexcept : hresult_error(impl::error_changed_state) {} - hresult_changed_state(param::hstring const& message) noexcept : hresult_error(impl::error_changed_state, message) {} - hresult_changed_state(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_changed_state, take_ownership_from_abi) {} + hresult_changed_state(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_changed_state, sourceInformation) {} + hresult_changed_state(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_changed_state, message, sourceInformation) {} + hresult_changed_state(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_changed_state, take_ownership_from_abi, sourceInformation) {} }; struct hresult_illegal_method_call : hresult_error { - hresult_illegal_method_call() noexcept : hresult_error(impl::error_illegal_method_call) {} - hresult_illegal_method_call(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_method_call, message) {} - hresult_illegal_method_call(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_method_call, take_ownership_from_abi) {} + hresult_illegal_method_call(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_method_call, sourceInformation) {} + hresult_illegal_method_call(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_method_call, message, sourceInformation) {} + hresult_illegal_method_call(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_method_call, take_ownership_from_abi, sourceInformation) {} }; struct hresult_illegal_state_change : hresult_error { - hresult_illegal_state_change() noexcept : hresult_error(impl::error_illegal_state_change) {} - hresult_illegal_state_change(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_state_change, message) {} - hresult_illegal_state_change(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_state_change, take_ownership_from_abi) {} + hresult_illegal_state_change(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_state_change, sourceInformation) {} + hresult_illegal_state_change(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_state_change, message, sourceInformation) {} + hresult_illegal_state_change(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_state_change, take_ownership_from_abi, sourceInformation) {} }; struct hresult_illegal_delegate_assignment : hresult_error { - hresult_illegal_delegate_assignment() noexcept : hresult_error(impl::error_illegal_delegate_assignment) {} - hresult_illegal_delegate_assignment(param::hstring const& message) noexcept : hresult_error(impl::error_illegal_delegate_assignment, message) {} - hresult_illegal_delegate_assignment(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_illegal_delegate_assignment, take_ownership_from_abi) {} + hresult_illegal_delegate_assignment(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_delegate_assignment, sourceInformation) {} + hresult_illegal_delegate_assignment(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_delegate_assignment, message, sourceInformation) {} + hresult_illegal_delegate_assignment(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_illegal_delegate_assignment, take_ownership_from_abi, sourceInformation) {} }; struct hresult_canceled : hresult_error { - hresult_canceled() noexcept : hresult_error(impl::error_canceled) {} - hresult_canceled(param::hstring const& message) noexcept : hresult_error(impl::error_canceled, message) {} - hresult_canceled(take_ownership_from_abi_t) noexcept : hresult_error(impl::error_canceled, take_ownership_from_abi) {} + hresult_canceled(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, sourceInformation) {} + hresult_canceled(hresult_error::no_originate_t) noexcept : hresult_error(impl::error_canceled, hresult_error::no_originate) {} + hresult_canceled(param::hstring const& message, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, message, sourceInformation) {} + hresult_canceled(take_ownership_from_abi_t, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) noexcept : hresult_error(impl::error_canceled, take_ownership_from_abi, sourceInformation) {} }; - [[noreturn]] inline WINRT_IMPL_NOINLINE void throw_hresult(hresult const result) + [[noreturn]] inline WINRT_IMPL_NOINLINE void throw_hresult(hresult const result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (winrt_throw_hresult_handler) { - winrt_throw_hresult_handler(0, nullptr, nullptr, WINRT_IMPL_RETURNADDRESS(), result); + winrt_throw_hresult_handler(sourceInformation.line(), sourceInformation.file_name(), sourceInformation.function_name(), WINRT_IMPL_RETURNADDRESS(), result); } if (result == impl::error_bad_alloc) @@ -447,70 +351,70 @@ WINRT_EXPORT namespace winrt if (result == impl::error_access_denied) { - throw hresult_access_denied(take_ownership_from_abi); + throw hresult_access_denied(take_ownership_from_abi, sourceInformation); } if (result == impl::error_wrong_thread) { - throw hresult_wrong_thread(take_ownership_from_abi); + throw hresult_wrong_thread(take_ownership_from_abi, sourceInformation); } if (result == impl::error_not_implemented) { - throw hresult_not_implemented(take_ownership_from_abi); + throw hresult_not_implemented(take_ownership_from_abi, sourceInformation); } if (result == impl::error_invalid_argument) { - throw hresult_invalid_argument(take_ownership_from_abi); + throw hresult_invalid_argument(take_ownership_from_abi, sourceInformation); } if (result == impl::error_out_of_bounds) { - throw hresult_out_of_bounds(take_ownership_from_abi); + throw hresult_out_of_bounds(take_ownership_from_abi, sourceInformation); } if (result == impl::error_no_interface) { - throw hresult_no_interface(take_ownership_from_abi); + throw hresult_no_interface(take_ownership_from_abi, sourceInformation); } if (result == impl::error_class_not_available) { - throw hresult_class_not_available(take_ownership_from_abi); + throw hresult_class_not_available(take_ownership_from_abi, sourceInformation); } if (result == impl::error_class_not_registered) { - throw hresult_class_not_registered(take_ownership_from_abi); + throw hresult_class_not_registered(take_ownership_from_abi, sourceInformation); } if (result == impl::error_changed_state) { - throw hresult_changed_state(take_ownership_from_abi); + throw hresult_changed_state(take_ownership_from_abi, sourceInformation); } if (result == impl::error_illegal_method_call) { - throw hresult_illegal_method_call(take_ownership_from_abi); + throw hresult_illegal_method_call(take_ownership_from_abi, sourceInformation); } if (result == impl::error_illegal_state_change) { - throw hresult_illegal_state_change(take_ownership_from_abi); + throw hresult_illegal_state_change(take_ownership_from_abi, sourceInformation); } if (result == impl::error_illegal_delegate_assignment) { - throw hresult_illegal_delegate_assignment(take_ownership_from_abi); + throw hresult_illegal_delegate_assignment(take_ownership_from_abi, sourceInformation); } if (result == impl::error_canceled) { - throw hresult_canceled(take_ownership_from_abi); + throw hresult_canceled(take_ownership_from_abi, sourceInformation); } - throw hresult_error(result, take_ownership_from_abi); + throw hresult_error(result, take_ownership_from_abi, sourceInformation); } inline WINRT_IMPL_NOINLINE hresult to_hresult() noexcept @@ -567,57 +471,59 @@ WINRT_EXPORT namespace winrt } catch (...) { - abort(); + std::abort(); } } - [[noreturn]] inline void throw_last_error() + [[noreturn]] inline void throw_last_error(winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { - throw_hresult(impl::hresult_from_win32(WINRT_IMPL_GetLastError())); + throw_hresult(impl::hresult_from_win32(WINRT_IMPL_GetLastError()), sourceInformation); } - inline hresult check_hresult(hresult const result) + inline hresult check_hresult(hresult const result, winrt::impl::slim_source_location const& sourceInformation) { if (result < 0) { - throw_hresult(result); + throw_hresult(result, sourceInformation); } return result; } template - void check_nt(T result) + void check_nt(T result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (result != 0) { - throw_hresult(impl::hresult_from_nt(result)); + throw_hresult(impl::hresult_from_nt(result), sourceInformation); } } template - void check_win32(T result) + void check_win32(T result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (result != 0) { - throw_hresult(impl::hresult_from_win32(result)); + throw_hresult(impl::hresult_from_win32(result), sourceInformation); } } template - void check_bool(T result) + T check_bool(T result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (!result) { - winrt::throw_last_error(); + winrt::throw_last_error(sourceInformation); } + + return result; } template - T* check_pointer(T* pointer) + T* check_pointer(T* pointer, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (!pointer) { - throw_last_error(); + throw_last_error(sourceInformation); } return pointer; @@ -625,20 +531,18 @@ WINRT_EXPORT namespace winrt [[noreturn]] inline void terminate() noexcept { - static void(__stdcall * handler)(int32_t) noexcept; - impl::load_runtime_function(L"combase.dll", "RoFailFastWithErrorContext", handler, impl::fallback_RoFailFastWithErrorContext); - handler(to_hresult()); - abort(); + WINRT_IMPL_RoFailFastWithErrorContext(to_hresult()); + std::abort(); } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { - inline hresult check_hresult_allow_bounds(hresult const result) + inline hresult check_hresult_allow_bounds(hresult const result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()) { if (result != impl::error_out_of_bounds && result != impl::error_fail && result != impl::error_file_not_found) { - check_hresult(result); + check_hresult(result, sourceInformation); } return result; } diff --git a/strings/base_events.h b/strings/base_events.h index b5783555b..c21124e9c 100644 --- a/strings/base_events.h +++ b/strings/base_events.h @@ -3,7 +3,7 @@ WINRT_EXPORT namespace winrt { struct event_token { - int64_t value{}; + std::int64_t value{}; explicit operator bool() const noexcept { @@ -22,7 +22,7 @@ WINRT_EXPORT namespace winrt template struct event_revoker { - using method_type = int32_t(__stdcall impl::abi_t::*)(winrt::event_token); + using method_type = std::int32_t(__stdcall impl::abi_t::*)(winrt::event_token); event_revoker() noexcept = default; event_revoker(event_revoker const&) = delete; @@ -77,7 +77,7 @@ WINRT_EXPORT namespace winrt template struct factory_event_revoker { - using method_type = int32_t(__stdcall impl::abi_t::*)(winrt::event_token); + using method_type = std::int32_t(__stdcall impl::abi_t::*)(winrt::event_token); factory_event_revoker() noexcept = default; factory_event_revoker(factory_event_revoker const&) = delete; @@ -130,7 +130,7 @@ WINRT_EXPORT namespace winrt }; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct event_revoker @@ -267,7 +267,7 @@ namespace winrt::impl using pointer = value_type*; using iterator = value_type*; - explicit event_array(uint32_t const count) noexcept : m_size(count) + explicit event_array(std::uint32_t const count) noexcept : m_size(count) { std::uninitialized_fill_n(data(), count, value_type()); } @@ -306,7 +306,7 @@ namespace winrt::impl return data() + m_size; } - uint32_t size() const noexcept + std::uint32_t size() const noexcept { return m_size; } @@ -324,20 +324,32 @@ namespace winrt::impl } atomic_ref_count m_references{ 1 }; - uint32_t m_size{ 0 }; + std::uint32_t m_size{ 0 }; }; template - com_ptr> make_event_array(uint32_t const capacity) + com_ptr> make_event_array(std::uint32_t const capacity) { void* raw = ::operator new(sizeof(event_array) + (sizeof(T)* capacity)); +#ifdef _MSC_VER #pragma warning(suppress: 6386) +#endif return { new(raw) event_array(capacity), take_ownership_from_abi }; } - inline int32_t __stdcall fallback_RoTransformError(int32_t, int32_t, void*) noexcept + WINRT_IMPL_NOINLINE inline bool report_failed_invoke() { - return 1; + std::int32_t const code = to_hresult(); + WINRT_IMPL_RoTransformError(code, 0, nullptr); + + if (code == static_cast(0x80010108) || // RPC_E_DISCONNECTED + code == static_cast(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) + code == static_cast(0x89020001)) // JSCRIPT_E_CANTEXECUTE + { + return false; + } + + return true; } template @@ -349,18 +361,7 @@ namespace winrt::impl } catch (...) { - int32_t const code = to_hresult(); - - static int32_t(__stdcall * handler)(int32_t, int32_t, void*) noexcept; - impl::load_runtime_function(L"combase.dll", "RoTransformError", handler, fallback_RoTransformError); - handler(code, 0, nullptr); - - if (code == static_cast(0x80010108) || // RPC_E_DISCONNECTED - code == static_cast(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) - code == static_cast(0x89020001)) // JSCRIPT_E_CANTEXECUTE - { - return false; - } + return report_failed_invoke(); } return true; @@ -385,28 +386,7 @@ WINRT_EXPORT namespace winrt event_token add(delegate_type const& delegate) { - event_token token{}; - - // Extends life of old targets array to release delegates outside of lock. - delegate_array temp_targets; - - { - slim_lock_guard const change_guard(m_change); - delegate_array new_targets = impl::make_event_array((!m_targets) ? 1 : m_targets->size() + 1); - - if (m_targets) - { - std::copy_n(m_targets->begin(), m_targets->size(), new_targets->begin()); - } - - new_targets->back() = impl::make_agile_delegate(delegate); - token = get_token(new_targets->back()); - - slim_lock_guard const swap_guard(m_swap); - temp_targets = std::exchange(m_targets, std::move(new_targets)); - } - - return token; + return add_agile(impl::make_agile_delegate(delegate)); } void remove(event_token const token) @@ -422,7 +402,7 @@ WINRT_EXPORT namespace winrt return; } - uint32_t available_slots = m_targets->size() - 1; + std::uint32_t available_slots = m_targets->size() - 1; delegate_array new_targets; bool removed = false; @@ -508,9 +488,35 @@ WINRT_EXPORT namespace winrt private: + WINRT_IMPL_NOINLINE event_token add_agile(delegate_type delegate) + { + event_token token{}; + + // Extends life of old targets array to release delegates outside of lock. + delegate_array temp_targets; + + { + slim_lock_guard const change_guard(m_change); + delegate_array new_targets = impl::make_event_array((!m_targets) ? 1 : m_targets->size() + 1); + + if (m_targets) + { + std::copy_n(m_targets->begin(), m_targets->size(), new_targets->begin()); + } + + new_targets->back() = std::move(delegate); + token = get_token(new_targets->back()); + + slim_lock_guard const swap_guard(m_swap); + temp_targets = std::exchange(m_targets, std::move(new_targets)); + } + + return token; + } + event_token get_token(delegate_type const& delegate) const noexcept { - return event_token{ reinterpret_cast(WINRT_IMPL_EncodePointer(get_abi(delegate))) }; + return event_token{ reinterpret_cast(WINRT_IMPL_EncodePointer(get_abi(delegate))) }; } using delegate_array = com_ptr>; diff --git a/strings/base_extern.h b/strings/base_extern.h index 7782f3bcb..a17908ac4 100644 --- a/strings/base_extern.h +++ b/strings/base_extern.h @@ -1,88 +1,13 @@ -__declspec(selectany) int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; -__declspec(selectany) winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {}; -__declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {}; -__declspec(selectany) void(__stdcall* winrt_suspend_handler)(void const* token) noexcept {}; -__declspec(selectany) void(__stdcall* winrt_resume_handler)(void const* token) noexcept {}; -__declspec(selectany) int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; - -extern "C" -{ - void* __stdcall WINRT_IMPL_LoadLibraryW(wchar_t const* name) noexcept; - int32_t __stdcall WINRT_IMPL_FreeLibrary(void* library) noexcept; - void* __stdcall WINRT_IMPL_GetProcAddress(void* library, char const* name) noexcept; - - int32_t __stdcall WINRT_IMPL_SetErrorInfo(uint32_t reserved, void* info) noexcept; - int32_t __stdcall WINRT_IMPL_GetErrorInfo(uint32_t reserved, void** info) noexcept; - int32_t __stdcall WINRT_IMPL_CoInitializeEx(void*, uint32_t type) noexcept; - void __stdcall WINRT_IMPL_CoUninitialize() noexcept; - - int32_t __stdcall WINRT_IMPL_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept; - int32_t __stdcall WINRT_IMPL_CoCreateInstance(winrt::guid const& clsid, void* outer, uint32_t context, winrt::guid const& iid, void** object) noexcept; - int32_t __stdcall WINRT_IMPL_CoGetCallContext(winrt::guid const& iid, void** object) noexcept; - int32_t __stdcall WINRT_IMPL_CoGetObjectContext(winrt::guid const& iid, void** object) noexcept; - int32_t __stdcall WINRT_IMPL_CoGetApartmentType(int32_t* type, int32_t* qualifier) noexcept; - void* __stdcall WINRT_IMPL_CoTaskMemAlloc(std::size_t size) noexcept; - void __stdcall WINRT_IMPL_CoTaskMemFree(void* ptr) noexcept; - winrt::impl::bstr __stdcall WINRT_IMPL_SysAllocString(wchar_t const* value) noexcept; - void __stdcall WINRT_IMPL_SysFreeString(winrt::impl::bstr string) noexcept; - uint32_t __stdcall WINRT_IMPL_SysStringLen(winrt::impl::bstr string) noexcept; - int32_t __stdcall WINRT_IMPL_IIDFromString(wchar_t const* string, winrt::guid* iid) noexcept; - int32_t __stdcall WINRT_IMPL_MultiByteToWideChar(uint32_t codepage, uint32_t flags, char const* in_string, int32_t in_size, wchar_t* out_string, int32_t out_size) noexcept; - int32_t __stdcall WINRT_IMPL_WideCharToMultiByte(uint32_t codepage, uint32_t flags, wchar_t const* int_string, int32_t in_size, char* out_string, int32_t out_size, char const* default_char, int32_t* default_used) noexcept; - void* __stdcall WINRT_IMPL_HeapAlloc(void* heap, uint32_t flags, size_t bytes) noexcept; - int32_t __stdcall WINRT_IMPL_HeapFree(void* heap, uint32_t flags, void* value) noexcept; - void* __stdcall WINRT_IMPL_GetProcessHeap() noexcept; - uint32_t __stdcall WINRT_IMPL_FormatMessageW(uint32_t flags, void const* source, uint32_t code, uint32_t language, wchar_t* buffer, uint32_t size, va_list* arguments) noexcept; - uint32_t __stdcall WINRT_IMPL_GetLastError() noexcept; - void __stdcall WINRT_IMPL_GetSystemTimePreciseAsFileTime(void* result) noexcept; - uintptr_t __stdcall WINRT_IMPL_VirtualQuery(void* address, void* buffer, uintptr_t length) noexcept; - void* __stdcall WINRT_IMPL_EncodePointer(void* ptr) noexcept; - - int32_t __stdcall WINRT_IMPL_OpenProcessToken(void* process, uint32_t access, void** token) noexcept; - void* __stdcall WINRT_IMPL_GetCurrentProcess() noexcept; - int32_t __stdcall WINRT_IMPL_DuplicateToken(void* existing, uint32_t level, void** duplicate) noexcept; - int32_t __stdcall WINRT_IMPL_OpenThreadToken(void* thread, uint32_t access, int32_t self, void** token) noexcept; - void* __stdcall WINRT_IMPL_GetCurrentThread() noexcept; - int32_t __stdcall WINRT_IMPL_SetThreadToken(void** thread, void* token) noexcept; - - void __stdcall WINRT_IMPL_AcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept; - void __stdcall WINRT_IMPL_AcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept; - uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept; - uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept; - void __stdcall WINRT_IMPL_ReleaseSRWLockExclusive(winrt::impl::srwlock* lock) noexcept; - void __stdcall WINRT_IMPL_ReleaseSRWLockShared(winrt::impl::srwlock* lock) noexcept; - int32_t __stdcall WINRT_IMPL_SleepConditionVariableSRW(winrt::impl::condition_variable* cv, winrt::impl::srwlock* lock, uint32_t milliseconds, uint32_t flags) noexcept; - void __stdcall WINRT_IMPL_WakeConditionVariable(winrt::impl::condition_variable* cv) noexcept; - void __stdcall WINRT_IMPL_WakeAllConditionVariable(winrt::impl::condition_variable* cv) noexcept; - void* __stdcall WINRT_IMPL_InterlockedPushEntrySList(void* head, void* entry) noexcept; - void* __stdcall WINRT_IMPL_InterlockedFlushSList(void* head) noexcept; - - void* __stdcall WINRT_IMPL_CreateEventW(void*, int32_t, int32_t, void*) noexcept; - int32_t __stdcall WINRT_IMPL_SetEvent(void*) noexcept; - int32_t __stdcall WINRT_IMPL_CloseHandle(void* hObject) noexcept; - uint32_t __stdcall WINRT_IMPL_WaitForSingleObject(void* handle, uint32_t milliseconds) noexcept; - - int32_t __stdcall WINRT_IMPL_TrySubmitThreadpoolCallback(void(__stdcall *callback)(void*, void* context), void* context, void*) noexcept; - winrt::impl::ptp_timer __stdcall WINRT_IMPL_CreateThreadpoolTimer(void(__stdcall *callback)(void*, void* context, void*), void* context, void*) noexcept; - void __stdcall WINRT_IMPL_SetThreadpoolTimer(winrt::impl::ptp_timer timer, void* time, uint32_t period, uint32_t window) noexcept; - void __stdcall WINRT_IMPL_CloseThreadpoolTimer(winrt::impl::ptp_timer timer) noexcept; - winrt::impl::ptp_wait __stdcall WINRT_IMPL_CreateThreadpoolWait(void(__stdcall *callback)(void*, void* context, void*, uint32_t result), void* context, void*) noexcept; - void __stdcall WINRT_IMPL_SetThreadpoolWait(winrt::impl::ptp_wait wait, void* handle, void* timeout) noexcept; - void __stdcall WINRT_IMPL_CloseThreadpoolWait(winrt::impl::ptp_wait wait) noexcept; - winrt::impl::ptp_io __stdcall WINRT_IMPL_CreateThreadpoolIo(void* object, void(__stdcall *callback)(void*, void* context, void* overlapped, uint32_t result, std::size_t bytes, void*) noexcept, void* context, void*) noexcept; - void __stdcall WINRT_IMPL_StartThreadpoolIo(winrt::impl::ptp_io io) noexcept; - void __stdcall WINRT_IMPL_CancelThreadpoolIo(winrt::impl::ptp_io io) noexcept; - void __stdcall WINRT_IMPL_CloseThreadpoolIo(winrt::impl::ptp_io io) noexcept; - winrt::impl::ptp_pool __stdcall WINRT_IMPL_CreateThreadpool(void* reserved) noexcept; - void __stdcall WINRT_IMPL_SetThreadpoolThreadMaximum(winrt::impl::ptp_pool pool, uint32_t value) noexcept; - int32_t __stdcall WINRT_IMPL_SetThreadpoolThreadMinimum(winrt::impl::ptp_pool pool, uint32_t value) noexcept; - void __stdcall WINRT_IMPL_CloseThreadpool(winrt::impl::ptp_pool pool) noexcept; - - int32_t __stdcall WINRT_CanUnloadNow() noexcept; - int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept; -} - +// These global function pointers must use WINRT_EXPORT (which expands to +// 'export extern "C++"' in module builds) so that module and non-module TUs +// in the same binary share the same instances. +WINRT_EXPORT __declspec(selectany) std::int32_t(__stdcall* winrt_to_hresult_handler)(void* address) noexcept {}; +WINRT_EXPORT __declspec(selectany) winrt::hstring(__stdcall* winrt_to_message_handler)(void* address) {}; +WINRT_EXPORT __declspec(selectany) void(__stdcall* winrt_throw_hresult_handler)(std::uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept {}; +WINRT_EXPORT __declspec(selectany) std::int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; + +#if defined(_MSC_VER) #ifdef _M_HYBRID #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:#WINRT_IMPL_" #function "@" #count "=#" #function "@" #count)) #elif _M_ARM64EC @@ -92,75 +17,98 @@ extern "C" #else #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:WINRT_IMPL_" #function "=" #function)) #endif +#elif defined(__GNUC__) +#if defined(__i386__) +#define WINRT_IMPL_LINK(function, count) __asm__("_" #function "@" #count) +#else +#define WINRT_IMPL_LINK(function, count) __asm__(#function) +#endif +#endif -WINRT_IMPL_LINK(LoadLibraryW, 4) -WINRT_IMPL_LINK(FreeLibrary, 4) -WINRT_IMPL_LINK(GetProcAddress, 8) -WINRT_IMPL_LINK(SetErrorInfo, 8) -WINRT_IMPL_LINK(GetErrorInfo, 8) -WINRT_IMPL_LINK(CoInitializeEx, 8) -WINRT_IMPL_LINK(CoUninitialize, 0) - -WINRT_IMPL_LINK(CoCreateFreeThreadedMarshaler, 8) -WINRT_IMPL_LINK(CoCreateInstance, 20) -WINRT_IMPL_LINK(CoGetCallContext, 8) -WINRT_IMPL_LINK(CoGetObjectContext, 8) -WINRT_IMPL_LINK(CoGetApartmentType, 8) -WINRT_IMPL_LINK(CoTaskMemAlloc, 4) -WINRT_IMPL_LINK(CoTaskMemFree, 4) -WINRT_IMPL_LINK(SysAllocString, 4) -WINRT_IMPL_LINK(SysFreeString, 4) -WINRT_IMPL_LINK(SysStringLen, 4) -WINRT_IMPL_LINK(IIDFromString, 8) -WINRT_IMPL_LINK(MultiByteToWideChar, 24) -WINRT_IMPL_LINK(WideCharToMultiByte, 32) -WINRT_IMPL_LINK(HeapAlloc, 12) -WINRT_IMPL_LINK(HeapFree, 12) -WINRT_IMPL_LINK(GetProcessHeap, 0) -WINRT_IMPL_LINK(FormatMessageW, 28) -WINRT_IMPL_LINK(GetLastError, 0) -WINRT_IMPL_LINK(GetSystemTimePreciseAsFileTime, 4) -WINRT_IMPL_LINK(VirtualQuery, 12) -WINRT_IMPL_LINK(EncodePointer, 4) - -WINRT_IMPL_LINK(OpenProcessToken, 12) -WINRT_IMPL_LINK(GetCurrentProcess, 0) -WINRT_IMPL_LINK(DuplicateToken, 12) -WINRT_IMPL_LINK(OpenThreadToken, 16) -WINRT_IMPL_LINK(GetCurrentThread, 0) -WINRT_IMPL_LINK(SetThreadToken, 8) - -WINRT_IMPL_LINK(AcquireSRWLockExclusive, 4) -WINRT_IMPL_LINK(AcquireSRWLockShared, 4) -WINRT_IMPL_LINK(TryAcquireSRWLockExclusive, 4) -WINRT_IMPL_LINK(TryAcquireSRWLockShared, 4) -WINRT_IMPL_LINK(ReleaseSRWLockExclusive, 4) -WINRT_IMPL_LINK(ReleaseSRWLockShared, 4) -WINRT_IMPL_LINK(SleepConditionVariableSRW, 16) -WINRT_IMPL_LINK(WakeConditionVariable, 4) -WINRT_IMPL_LINK(WakeAllConditionVariable, 4) -WINRT_IMPL_LINK(InterlockedPushEntrySList, 8) -WINRT_IMPL_LINK(InterlockedFlushSList, 4) - -WINRT_IMPL_LINK(CreateEventW, 16) -WINRT_IMPL_LINK(SetEvent, 4) -WINRT_IMPL_LINK(CloseHandle, 4) -WINRT_IMPL_LINK(WaitForSingleObject, 8) - -WINRT_IMPL_LINK(TrySubmitThreadpoolCallback, 12) -WINRT_IMPL_LINK(CreateThreadpoolTimer, 12) -WINRT_IMPL_LINK(SetThreadpoolTimer, 16) -WINRT_IMPL_LINK(CloseThreadpoolTimer, 4) -WINRT_IMPL_LINK(CreateThreadpoolWait, 12) -WINRT_IMPL_LINK(SetThreadpoolWait, 12) -WINRT_IMPL_LINK(CloseThreadpoolWait, 4) -WINRT_IMPL_LINK(CreateThreadpoolIo, 16) -WINRT_IMPL_LINK(StartThreadpoolIo, 4) -WINRT_IMPL_LINK(CancelThreadpoolIo, 4) -WINRT_IMPL_LINK(CloseThreadpoolIo, 4) -WINRT_IMPL_LINK(CreateThreadpool, 4) -WINRT_IMPL_LINK(SetThreadpoolThreadMaximum, 8) -WINRT_IMPL_LINK(SetThreadpoolThreadMinimum, 8) -WINRT_IMPL_LINK(CloseThreadpool, 4) +extern "C" +{ + std::int32_t __stdcall WINRT_IMPL_RoGetActivationFactory(void* classId, winrt::guid const& iid, void** factory) noexcept WINRT_IMPL_LINK(RoGetActivationFactory, 12); + std::int32_t __stdcall WINRT_IMPL_RoGetAgileReference(std::uint32_t options, winrt::guid const& iid, void* object, void** reference) noexcept WINRT_IMPL_LINK(RoGetAgileReference, 16); + std::int32_t __stdcall WINRT_IMPL_SetThreadpoolTimerEx(winrt::impl::ptp_timer, void*, std::uint32_t, std::uint32_t) noexcept WINRT_IMPL_LINK(SetThreadpoolTimerEx, 16); + std::int32_t __stdcall WINRT_IMPL_SetThreadpoolWaitEx(winrt::impl::ptp_wait, void*, void*, void*) noexcept WINRT_IMPL_LINK(SetThreadpoolWaitEx, 16); + std::int32_t __stdcall WINRT_IMPL_RoOriginateLanguageException(std::int32_t error, void* message, void* exception) noexcept WINRT_IMPL_LINK(RoOriginateLanguageException, 12); + std::int32_t __stdcall WINRT_IMPL_RoCaptureErrorContext(std::int32_t error) noexcept WINRT_IMPL_LINK(RoCaptureErrorContext, 4); + void __stdcall WINRT_IMPL_RoFailFastWithErrorContext(std::int32_t) noexcept WINRT_IMPL_LINK(RoFailFastWithErrorContext, 4); + std::int32_t __stdcall WINRT_IMPL_RoTransformError(std::int32_t, std::int32_t, void*) noexcept WINRT_IMPL_LINK(RoTransformError, 12); + + void* __stdcall WINRT_IMPL_LoadLibraryExW(wchar_t const* name, void* unused, std::uint32_t flags) noexcept WINRT_IMPL_LINK(LoadLibraryExW, 12); + std::int32_t __stdcall WINRT_IMPL_FreeLibrary(void* library) noexcept WINRT_IMPL_LINK(FreeLibrary, 4); + void* __stdcall WINRT_IMPL_GetProcAddress(void* library, char const* name) noexcept WINRT_IMPL_LINK(GetProcAddress, 8); + + std::int32_t __stdcall WINRT_IMPL_SetErrorInfo(std::uint32_t reserved, void* info) noexcept WINRT_IMPL_LINK(SetErrorInfo, 8); + std::int32_t __stdcall WINRT_IMPL_GetErrorInfo(std::uint32_t reserved, void** info) noexcept WINRT_IMPL_LINK(GetErrorInfo, 8); + std::int32_t __stdcall WINRT_IMPL_CoInitializeEx(void*, std::uint32_t type) noexcept WINRT_IMPL_LINK(CoInitializeEx, 8); + void __stdcall WINRT_IMPL_CoUninitialize() noexcept WINRT_IMPL_LINK(CoUninitialize, 0); + + std::int32_t __stdcall WINRT_IMPL_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept WINRT_IMPL_LINK(CoCreateFreeThreadedMarshaler, 8); + std::int32_t __stdcall WINRT_IMPL_CoCreateInstance(winrt::guid const& clsid, void* outer, std::uint32_t context, winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoCreateInstance, 20); + std::int32_t __stdcall WINRT_IMPL_CoGetCallContext(winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoGetCallContext, 8); + std::int32_t __stdcall WINRT_IMPL_CoGetObjectContext(winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoGetObjectContext, 8); + std::int32_t __stdcall WINRT_IMPL_CoGetApartmentType(std::int32_t* type, std::int32_t* qualifier) noexcept WINRT_IMPL_LINK(CoGetApartmentType, 8); + void* __stdcall WINRT_IMPL_CoTaskMemAlloc(std::size_t size) noexcept WINRT_IMPL_LINK(CoTaskMemAlloc, 4); + void __stdcall WINRT_IMPL_CoTaskMemFree(void* ptr) noexcept WINRT_IMPL_LINK(CoTaskMemFree, 4); + winrt::impl::bstr __stdcall WINRT_IMPL_SysAllocString(wchar_t const* value) noexcept WINRT_IMPL_LINK(SysAllocString, 4); + void __stdcall WINRT_IMPL_SysFreeString(winrt::impl::bstr string) noexcept WINRT_IMPL_LINK(SysFreeString, 4); + std::uint32_t __stdcall WINRT_IMPL_SysStringLen(winrt::impl::bstr string) noexcept WINRT_IMPL_LINK(SysStringLen, 4); + std::int32_t __stdcall WINRT_IMPL_IIDFromString(wchar_t const* string, winrt::guid* iid) noexcept WINRT_IMPL_LINK(IIDFromString, 8); + std::int32_t __stdcall WINRT_IMPL_MultiByteToWideChar(std::uint32_t codepage, std::uint32_t flags, char const* in_string, std::int32_t in_size, wchar_t* out_string, std::int32_t out_size) noexcept WINRT_IMPL_LINK(MultiByteToWideChar, 24); + std::int32_t __stdcall WINRT_IMPL_WideCharToMultiByte(std::uint32_t codepage, std::uint32_t flags, wchar_t const* int_string, std::int32_t in_size, char* out_string, std::int32_t out_size, char const* default_char, std::int32_t* default_used) noexcept WINRT_IMPL_LINK(WideCharToMultiByte, 32); + void* __stdcall WINRT_IMPL_HeapAlloc(void* heap, std::uint32_t flags, std::size_t bytes) noexcept WINRT_IMPL_LINK(HeapAlloc, 12); + std::int32_t __stdcall WINRT_IMPL_HeapFree(void* heap, std::uint32_t flags, void* value) noexcept WINRT_IMPL_LINK(HeapFree, 12); + void* __stdcall WINRT_IMPL_GetProcessHeap() noexcept WINRT_IMPL_LINK(GetProcessHeap, 0); + std::uint32_t __stdcall WINRT_IMPL_FormatMessageW(std::uint32_t flags, void const* source, std::uint32_t code, std::uint32_t language, wchar_t* buffer, std::uint32_t size, va_list* arguments) noexcept WINRT_IMPL_LINK(FormatMessageW, 28); + std::uint32_t __stdcall WINRT_IMPL_GetLastError() noexcept WINRT_IMPL_LINK(GetLastError, 0); + void __stdcall WINRT_IMPL_GetSystemTimePreciseAsFileTime(void* result) noexcept WINRT_IMPL_LINK(GetSystemTimePreciseAsFileTime, 4); + std::uintptr_t __stdcall WINRT_IMPL_VirtualQuery(void* address, void* buffer, std::uintptr_t length) noexcept WINRT_IMPL_LINK(VirtualQuery, 12); + void* __stdcall WINRT_IMPL_EncodePointer(void* ptr) noexcept WINRT_IMPL_LINK(EncodePointer, 4); + + std::int32_t __stdcall WINRT_IMPL_OpenProcessToken(void* process, std::uint32_t access, void** token) noexcept WINRT_IMPL_LINK(OpenProcessToken, 12); + void* __stdcall WINRT_IMPL_GetCurrentProcess() noexcept WINRT_IMPL_LINK(GetCurrentProcess, 0); + std::int32_t __stdcall WINRT_IMPL_DuplicateToken(void* existing, std::uint32_t level, void** duplicate) noexcept WINRT_IMPL_LINK(DuplicateToken, 12); + std::int32_t __stdcall WINRT_IMPL_OpenThreadToken(void* thread, std::uint32_t access, std::int32_t self, void** token) noexcept WINRT_IMPL_LINK(OpenThreadToken, 16); + void* __stdcall WINRT_IMPL_GetCurrentThread() noexcept WINRT_IMPL_LINK(GetCurrentThread, 0); + std::int32_t __stdcall WINRT_IMPL_SetThreadToken(void** thread, void* token) noexcept WINRT_IMPL_LINK(SetThreadToken, 8); + + void __stdcall WINRT_IMPL_AcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(AcquireSRWLockExclusive, 4); + void __stdcall WINRT_IMPL_AcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(AcquireSRWLockShared, 4); + std::uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(TryAcquireSRWLockExclusive, 4); + std::uint8_t __stdcall WINRT_IMPL_TryAcquireSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(TryAcquireSRWLockShared, 4); + void __stdcall WINRT_IMPL_ReleaseSRWLockExclusive(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(ReleaseSRWLockExclusive, 4); + void __stdcall WINRT_IMPL_ReleaseSRWLockShared(winrt::impl::srwlock* lock) noexcept WINRT_IMPL_LINK(ReleaseSRWLockShared, 4); + std::int32_t __stdcall WINRT_IMPL_SleepConditionVariableSRW(winrt::impl::condition_variable* cv, winrt::impl::srwlock* lock, std::uint32_t milliseconds, std::uint32_t flags) noexcept WINRT_IMPL_LINK(SleepConditionVariableSRW, 16); + void __stdcall WINRT_IMPL_WakeConditionVariable(winrt::impl::condition_variable* cv) noexcept WINRT_IMPL_LINK(WakeConditionVariable, 4); + void __stdcall WINRT_IMPL_WakeAllConditionVariable(winrt::impl::condition_variable* cv) noexcept WINRT_IMPL_LINK(WakeAllConditionVariable, 4); + void* __stdcall WINRT_IMPL_InterlockedPushEntrySList(void* head, void* entry) noexcept WINRT_IMPL_LINK(InterlockedPushEntrySList, 8); + void* __stdcall WINRT_IMPL_InterlockedFlushSList(void* head) noexcept WINRT_IMPL_LINK(InterlockedFlushSList, 4); + + void* __stdcall WINRT_IMPL_CreateEventW(void*, std::int32_t, std::int32_t, void*) noexcept WINRT_IMPL_LINK(CreateEventW, 16); + std::int32_t __stdcall WINRT_IMPL_SetEvent(void*) noexcept WINRT_IMPL_LINK(SetEvent, 4); + std::int32_t __stdcall WINRT_IMPL_CloseHandle(void* hObject) noexcept WINRT_IMPL_LINK(CloseHandle, 4); + std::uint32_t __stdcall WINRT_IMPL_WaitForSingleObject(void* handle, std::uint32_t milliseconds) noexcept WINRT_IMPL_LINK(WaitForSingleObject, 8); + + std::int32_t __stdcall WINRT_IMPL_TrySubmitThreadpoolCallback(void(__stdcall *callback)(void*, void* context), void* context, void*) noexcept WINRT_IMPL_LINK(TrySubmitThreadpoolCallback, 12); + winrt::impl::ptp_timer __stdcall WINRT_IMPL_CreateThreadpoolTimer(void(__stdcall *callback)(void*, void* context, void*), void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolTimer, 12); + void __stdcall WINRT_IMPL_SetThreadpoolTimer(winrt::impl::ptp_timer timer, void* time, std::uint32_t period, std::uint32_t window) noexcept WINRT_IMPL_LINK(SetThreadpoolTimer, 16); + void __stdcall WINRT_IMPL_CloseThreadpoolTimer(winrt::impl::ptp_timer timer) noexcept WINRT_IMPL_LINK(CloseThreadpoolTimer, 4); + winrt::impl::ptp_wait __stdcall WINRT_IMPL_CreateThreadpoolWait(void(__stdcall *callback)(void*, void* context, void*, std::uint32_t result), void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolWait, 12); + void __stdcall WINRT_IMPL_SetThreadpoolWait(winrt::impl::ptp_wait wait, void* handle, void* timeout) noexcept WINRT_IMPL_LINK(SetThreadpoolWait, 12); + void __stdcall WINRT_IMPL_CloseThreadpoolWait(winrt::impl::ptp_wait wait) noexcept WINRT_IMPL_LINK(CloseThreadpoolWait, 4); + winrt::impl::ptp_io __stdcall WINRT_IMPL_CreateThreadpoolIo(void* object, void(__stdcall *callback)(void*, void* context, void* overlapped, std::uint32_t result, std::size_t bytes, void*) noexcept, void* context, void*) noexcept WINRT_IMPL_LINK(CreateThreadpoolIo, 16); + void __stdcall WINRT_IMPL_StartThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(StartThreadpoolIo, 4); + void __stdcall WINRT_IMPL_CancelThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(CancelThreadpoolIo, 4); + void __stdcall WINRT_IMPL_CloseThreadpoolIo(winrt::impl::ptp_io io) noexcept WINRT_IMPL_LINK(CloseThreadpoolIo, 4); + winrt::impl::ptp_pool __stdcall WINRT_IMPL_CreateThreadpool(void* reserved) noexcept WINRT_IMPL_LINK(CreateThreadpool, 4); + void __stdcall WINRT_IMPL_SetThreadpoolThreadMaximum(winrt::impl::ptp_pool pool, std::uint32_t value) noexcept WINRT_IMPL_LINK(SetThreadpoolThreadMaximum, 8); + std::int32_t __stdcall WINRT_IMPL_SetThreadpoolThreadMinimum(winrt::impl::ptp_pool pool, std::uint32_t value) noexcept WINRT_IMPL_LINK(SetThreadpoolThreadMinimum, 8); + void __stdcall WINRT_IMPL_CloseThreadpool(winrt::impl::ptp_pool pool) noexcept WINRT_IMPL_LINK(CloseThreadpool, 4); + + std::int32_t __stdcall WINRT_CanUnloadNow() noexcept; + std::int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept; +} #undef WINRT_IMPL_LINK diff --git a/strings/base_fast_forward.h b/strings/base_fast_forward.h index 298403197..a73e70a04 100644 --- a/strings/base_fast_forward.h +++ b/strings/base_fast_forward.h @@ -1,9 +1,27 @@ #include #include +#include +#include #define WINRT_IMPL_STRING_1(expression) #expression #define WINRT_IMPL_STRING(expression) WINRT_IMPL_STRING_1(expression) +#if defined(_MSC_VER) +#define WINRT_IMPL_FF_NOVTABLE __declspec(novtable) +#else +#define WINRT_IMPL_FF_NOVTABLE +#endif + +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(__lto_visibility_public__) +#define WINRT_IMPL_FF_PUBLIC __attribute__((lto_visibility_public)) +#else +#define WINRT_IMPL_FF_PUBLIC +#endif // __has_attribute(__lto_visibility_public__) +#else +#define WINRT_IMPL_FF_PUBLIC +#endif + #if !defined(WINRT_FAST_ABI_SIZE) #define WINRT_FAST_ABI_SIZE % #endif @@ -12,7 +30,11 @@ static_assert(WINRT_FAST_ABI_SIZE >= %); #pragma detect_mismatch("WINRT_FAST_ABI_SIZE", WINRT_IMPL_STRING(WINRT_FAST_ABI_SIZE)) -namespace winrt::impl +#ifndef WINRT_EXPORT +#define WINRT_EXPORT +#endif // WINRT_EXPORT + +WINRT_EXPORT namespace winrt::impl { // Thunk definitions are in arch-specific assembly sources % @@ -20,34 +42,34 @@ namespace winrt::impl { struct guid { - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; + std::uint32_t Data1; + std::uint16_t Data2; + std::uint16_t Data3; + std::uint8_t Data4[8]; inline bool operator!=(guid const& right) const noexcept { - return memcmp(this, &right, sizeof(guid)); + return std::memcmp(this, &right, sizeof(guid)); } }; - struct __declspec(novtable) inspectable + struct WINRT_IMPL_FF_NOVTABLE WINRT_IMPL_FF_PUBLIC inspectable { - virtual int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; - virtual uint32_t __stdcall AddRef() noexcept = 0; - virtual uint32_t __stdcall Release() noexcept = 0; - virtual int32_t __stdcall GetIids(uint32_t* count, guid** ids) noexcept = 0; - virtual int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; - virtual int32_t __stdcall GetTrustLevel(uint32_t* level) noexcept = 0; + virtual std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; + virtual std::uint32_t __stdcall AddRef() noexcept = 0; + virtual std::uint32_t __stdcall Release() noexcept = 0; + virtual std::int32_t __stdcall GetIids(std::uint32_t* count, guid** ids) noexcept = 0; + virtual std::int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; + virtual std::int32_t __stdcall GetTrustLevel(std::uint32_t* level) noexcept = 0; }; void* const* m_vfptr; inspectable* m_owner; std::size_t m_offset; guid m_iid; - std::atomic m_references{ 1 }; + std::atomic m_references{ 1 }; fast_abi_forwarder(void* owner, guid const& iid, std::size_t offset) noexcept : - m_vfptr(s_vtable), m_owner(static_cast(owner)), m_iid(iid), m_offset(offset) + m_vfptr(s_vtable), m_owner(static_cast(owner)), m_offset(offset), m_iid(iid) { m_owner->AddRef(); } @@ -57,7 +79,7 @@ namespace winrt::impl m_owner->Release(); } - static int32_t __stdcall QueryInterface(fast_abi_forwarder* self, guid const& iid, void** object) noexcept + static std::int32_t __stdcall QueryInterface(fast_abi_forwarder* self, guid const& iid, void** object) noexcept { if (iid != self->m_iid) { @@ -69,14 +91,14 @@ namespace winrt::impl } // Note: COM interfaces use stdcall, not thiscall, ('this' gets no special treatment), permitting static implementations - static uint32_t __stdcall AddRef(fast_abi_forwarder* self) noexcept + static std::uint32_t __stdcall AddRef(fast_abi_forwarder* self) noexcept { return 1 + self->m_references.fetch_add(1, std::memory_order_relaxed); } - static uint32_t __stdcall Release(fast_abi_forwarder* self) noexcept + static std::uint32_t __stdcall Release(fast_abi_forwarder* self) noexcept { - uint32_t const remaining = self->m_references.fetch_sub(1, std::memory_order_release) - 1; + std::uint32_t const remaining = self->m_references.fetch_sub(1, std::memory_order_release) - 1; if (remaining == 0) { std::atomic_thread_fence(std::memory_order_acquire); @@ -85,21 +107,26 @@ namespace winrt::impl return remaining; } - static uint32_t __stdcall GetIids(fast_abi_forwarder* self, uint32_t* count, guid** iids) noexcept + static std::uint32_t __stdcall GetIids(fast_abi_forwarder* self, std::uint32_t* count, guid** iids) noexcept { return self->m_owner->GetIids(count, iids); } - static uint32_t __stdcall GetRuntimeClassName(fast_abi_forwarder* self, void** name) noexcept + static std::uint32_t __stdcall GetRuntimeClassName(fast_abi_forwarder* self, void** name) noexcept { return self->m_owner->GetRuntimeClassName(name); } - static uint32_t __stdcall GetTrustLevel(fast_abi_forwarder* self, uint32_t* level) noexcept + static std::uint32_t __stdcall GetTrustLevel(fast_abi_forwarder* self, std::uint32_t* level) noexcept { return self->m_owner->GetTrustLevel(level); } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmicrosoft-cast" +#endif static inline void* const s_vtable[] = { QueryInterface, @@ -109,6 +136,9 @@ namespace winrt::impl GetRuntimeClassName, GetTrustLevel, % }; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif }; // Enforce assumptions made by thunk asm code @@ -120,7 +150,7 @@ namespace winrt::impl namespace winrt { template - auto make_fast_abi_forwarder(void* owner, TGuid const& guid, size_t offset) + auto make_fast_abi_forwarder(void* owner, TGuid const& guid, std::size_t offset) { using ff_guid = impl::fast_abi_forwarder::guid; static_assert(sizeof(ff_guid) == sizeof(TGuid)); @@ -130,3 +160,5 @@ namespace winrt #undef WINRT_IMPL_STRING #undef WINRT_IMPL_STRING_1 +#undef WINRT_IMPL_FF_NOVTABLE +#undef WINRT_IMPL_FF_PUBLIC diff --git a/strings/base_foundation.h b/strings/base_foundation.h index ea8881edc..083252753 100644 --- a/strings/base_foundation.h +++ b/strings/base_foundation.h @@ -100,7 +100,7 @@ WINRT_EXPORT namespace winrt::Windows::Foundation } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template <> inline constexpr auto& name_v = L"Windows.Foundation.Point"; template <> inline constexpr auto& name_v = L"Windows.Foundation.Size"; diff --git a/strings/base_identity.h b/strings/base_identity.h index 5bf7bbaa8..4a5bedbb1 100644 --- a/strings/base_identity.h +++ b/strings/base_identity.h @@ -11,39 +11,39 @@ WINRT_EXPORT namespace winrt } template - bool is_guid_of(guid const& id) noexcept + constexpr bool is_guid_of(guid const& id) noexcept { return ((id == guid_of()) || ...); } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { - template + template constexpr std::array to_array(T const* value, std::index_sequence const) noexcept { return { value[Index]... }; } - template + template constexpr auto to_array(std::array const& value) noexcept { return value; } - template + template constexpr auto to_array(char const(&value)[Size]) noexcept { return to_array(value, std::make_index_sequence()); } - template + template constexpr auto to_array(wchar_t const(&value)[Size]) noexcept { return to_array(value, std::make_index_sequence()); } - template + template constexpr std::array concat( [[maybe_unused]] std::array const& left, [[maybe_unused]] std::array const& right, @@ -53,31 +53,31 @@ namespace winrt::impl return { left[LeftIndex]..., right[RightIndex]... }; } - template + template constexpr auto concat(std::array const& left, std::array const& right) noexcept { return concat(left, right, std::make_index_sequence(), std::make_index_sequence()); } - template + template constexpr auto concat(std::array const& left, T const(&right)[RightSize]) noexcept { return concat(left, to_array(right)); } - template + template constexpr auto concat(T const(&left)[LeftSize], std::array const& right) noexcept { return concat(to_array(left), right); } - template + template constexpr auto concat(std::array const& left, T const right) noexcept { return concat(left, std::array{right}); } - template + template constexpr auto concat(T const left, std::array const& right) noexcept { return concat(std::array{left}, right); @@ -96,31 +96,31 @@ namespace winrt::impl } } - template + template constexpr std::array zconcat_base(std::array const& left, std::array const& right, std::index_sequence const, std::index_sequence const) noexcept { return { left[LI]..., right[RI]..., T{} }; } - template + template constexpr auto zconcat(std::array const& left, std::array const& right) noexcept { return zconcat_base(left, right, std::make_index_sequence(), std::make_index_sequence()); } - template + template constexpr std::array to_zarray_base(T const(&value)[S], std::index_sequence const) noexcept { return { value[I]... }; } - template + template constexpr auto to_zarray(T const(&value)[S]) noexcept { return to_zarray_base(value, std::make_index_sequence()); } - template + template constexpr auto to_zarray(std::array const& value) noexcept { return value; @@ -139,43 +139,43 @@ namespace winrt::impl } } - constexpr std::array to_array(uint32_t value) noexcept + constexpr std::array to_array(std::uint32_t value) noexcept { - return { static_cast(value & 0x000000ff), static_cast((value & 0x0000ff00) >> 8), static_cast((value & 0x00ff0000) >> 16), static_cast((value & 0xff000000) >> 24) }; + return { static_cast(value & 0x000000ff), static_cast((value & 0x0000ff00) >> 8), static_cast((value & 0x00ff0000) >> 16), static_cast((value & 0xff000000) >> 24) }; } - constexpr std::array to_array(uint16_t value) noexcept + constexpr std::array to_array(std::uint16_t value) noexcept { - return { static_cast(value & 0x00ff), static_cast((value & 0xff00) >> 8) }; + return { static_cast(value & 0x00ff), static_cast((value & 0xff00) >> 8) }; } constexpr auto to_array(guid const& value) noexcept { return combine(to_array(value.Data1), to_array(value.Data2), to_array(value.Data3), - std::array{ value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7] }); + std::array{ value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7] }); } template - constexpr T to_hex_digit(uint8_t value) noexcept + constexpr T to_hex_digit(std::uint8_t value) noexcept { value &= 0xF; return value < 10 ? static_cast('0') + value : static_cast('a') + (value - 10); } template - constexpr std::array uint8_to_hex(uint8_t const value) noexcept + constexpr std::array uint8_to_hex(std::uint8_t const value) noexcept { return { to_hex_digit(value >> 4), to_hex_digit(value & 0xF) }; } template - constexpr auto uint16_to_hex(uint16_t value) noexcept + constexpr auto uint16_to_hex(std::uint16_t value) noexcept { - return combine(uint8_to_hex(static_cast(value >> 8)), uint8_to_hex(value & 0xFF)); + return combine(uint8_to_hex(static_cast(value >> 8)), uint8_to_hex(value & 0xFF)); } template - constexpr auto uint32_to_hex(uint32_t const value) noexcept + constexpr auto uint32_to_hex(std::uint32_t const value) noexcept { return combine(uint16_to_hex(value >> 16), uint16_to_hex(value & 0xFFFF)); } @@ -197,18 +197,18 @@ namespace winrt::impl ); } - constexpr uint32_t to_guid(uint8_t a, uint8_t b, uint8_t c, uint8_t d) noexcept + constexpr std::uint32_t to_guid(std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) noexcept { - return (static_cast(d) << 24) | (static_cast(c) << 16) | (static_cast(b) << 8) | static_cast(a); + return (static_cast(d) << 24) | (static_cast(c) << 16) | (static_cast(b) << 8) | static_cast(a); } - constexpr uint16_t to_guid(uint8_t a, uint8_t b) noexcept + constexpr std::uint16_t to_guid(std::uint8_t a, std::uint8_t b) noexcept { - return (static_cast(b) << 8) | static_cast(a); + return (static_cast(b) << 8) | static_cast(a); } - template - constexpr guid to_guid(std::array const& arr) noexcept + template + constexpr guid to_guid(std::array const& arr) noexcept { return { @@ -219,12 +219,12 @@ namespace winrt::impl }; } - constexpr uint32_t endian_swap(uint32_t value) noexcept + constexpr std::uint32_t endian_swap(std::uint32_t value) noexcept { return (value & 0xFF000000) >> 24 | (value & 0x00FF0000) >> 8 | (value & 0x0000FF00) << 8 | (value & 0x000000FF) << 24; } - constexpr uint16_t endian_swap(uint16_t value) noexcept + constexpr std::uint16_t endian_swap(std::uint16_t value) noexcept { return (value & 0xFF00) >> 8 | (value & 0x00FF) << 8; } @@ -239,51 +239,51 @@ namespace winrt::impl constexpr guid set_named_guid_fields(guid value) noexcept { - value.Data3 = static_cast((value.Data3 & 0x0fff) | (5 << 12)); - value.Data4[0] = static_cast((value.Data4[0] & 0x3f) | 0x80); + value.Data3 = static_cast((value.Data3 & 0x0fff) | (5 << 12)); + value.Data4[0] = static_cast((value.Data4[0] & 0x3f) | 0x80); return value; } - template - constexpr std::array char_to_byte_array(std::array const& value, std::index_sequence const) noexcept + template + constexpr std::array char_to_byte_array(std::array const& value, std::index_sequence const) noexcept { - return { static_cast(value[Index])... }; + return { static_cast(value[Index])... }; } - constexpr auto sha1_rotl(uint8_t bits, uint32_t word) noexcept + constexpr auto sha1_rotl(std::uint8_t bits, std::uint32_t word) noexcept { return (word << bits) | (word >> (32 - bits)); } - constexpr auto sha_ch(uint32_t x, uint32_t y, uint32_t z) noexcept + constexpr auto sha_ch(std::uint32_t x, std::uint32_t y, std::uint32_t z) noexcept { return (x & y) ^ ((~x) & z); } - constexpr auto sha_parity(uint32_t x, uint32_t y, uint32_t z) noexcept + constexpr auto sha_parity(std::uint32_t x, std::uint32_t y, std::uint32_t z) noexcept { return x ^ y ^ z; } - constexpr auto sha_maj(uint32_t x, uint32_t y, uint32_t z) noexcept + constexpr auto sha_maj(std::uint32_t x, std::uint32_t y, std::uint32_t z) noexcept { return (x & y) ^ (x & z) ^ (y & z); } - constexpr std::array process_msg_block(uint8_t const* input, size_t start_pos, std::array const& intermediate_hash) noexcept + constexpr std::array process_msg_block(std::uint8_t const* input, std::size_t start_pos, std::array const& intermediate_hash) noexcept { - uint32_t const K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; - std::array W = {}; + std::uint32_t const K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; + std::array W = {}; - size_t t = 0; - uint32_t temp = 0; + std::size_t t = 0; + std::uint32_t temp = 0; for (t = 0; t < 16; t++) { - W[t] = static_cast(input[start_pos + t * 4]) << 24; - W[t] = W[t] | static_cast(input[start_pos + t * 4 + 1]) << 16; - W[t] = W[t] | static_cast(input[start_pos + t * 4 + 2]) << 8; - W[t] = W[t] | static_cast(input[start_pos + t * 4 + 3]); + W[t] = static_cast(input[start_pos + t * 4]) << 24; + W[t] = W[t] | static_cast(input[start_pos + t * 4 + 1]) << 16; + W[t] = W[t] | static_cast(input[start_pos + t * 4 + 2]) << 8; + W[t] = W[t] | static_cast(input[start_pos + t * 4 + 3]); } for (t = 16; t < 80; t++) @@ -291,11 +291,11 @@ namespace winrt::impl W[t] = sha1_rotl(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); } - uint32_t A = intermediate_hash[0]; - uint32_t B = intermediate_hash[1]; - uint32_t C = intermediate_hash[2]; - uint32_t D = intermediate_hash[3]; - uint32_t E = intermediate_hash[4]; + std::uint32_t A = intermediate_hash[0]; + std::uint32_t B = intermediate_hash[1]; + std::uint32_t C = intermediate_hash[2]; + std::uint32_t D = intermediate_hash[3]; + std::uint32_t E = intermediate_hash[4]; for (t = 0; t < 20; t++) { @@ -340,54 +340,54 @@ namespace winrt::impl return { intermediate_hash[0] + A, intermediate_hash[1] + B, intermediate_hash[2] + C, intermediate_hash[3] + D, intermediate_hash[4] + E }; } - template - constexpr std::array process_msg_block(std::array const& input, size_t start_pos, std::array const& intermediate_hash) noexcept + template + constexpr std::array process_msg_block(std::array const& input, std::size_t start_pos, std::array const& intermediate_hash) noexcept { return process_msg_block(input.data(), start_pos, intermediate_hash); } - constexpr std::array size_to_bytes(size_t size) noexcept + constexpr std::array size_to_bytes(std::size_t size) noexcept { return { - static_cast((size & 0xff00000000000000) >> 56), - static_cast((size & 0x00ff000000000000) >> 48), - static_cast((size & 0x0000ff0000000000) >> 40), - static_cast((size & 0x000000ff00000000) >> 32), - static_cast((size & 0x00000000ff000000) >> 24), - static_cast((size & 0x0000000000ff0000) >> 16), - static_cast((size & 0x000000000000ff00) >> 8), - static_cast((size & 0x00000000000000ff) >> 0) + static_cast((size & 0xff00000000000000) >> 56), + static_cast((size & 0x00ff000000000000) >> 48), + static_cast((size & 0x0000ff0000000000) >> 40), + static_cast((size & 0x000000ff00000000) >> 32), + static_cast((size & 0x00000000ff000000) >> 24), + static_cast((size & 0x0000000000ff0000) >> 16), + static_cast((size & 0x000000000000ff00) >> 8), + static_cast((size & 0x00000000000000ff) >> 0) }; } - template - constexpr std::array make_remaining([[maybe_unused]] std::array const& input, [[maybe_unused]] size_t start_pos, std::index_sequence) noexcept + template + constexpr std::array make_remaining([[maybe_unused]] std::array const& input, [[maybe_unused]] std::size_t start_pos, std::index_sequence) noexcept { return { input[Index + start_pos]..., 0x80 }; } - template - constexpr auto make_remaining(std::array const& input, size_t start_pos) noexcept + template + constexpr auto make_remaining(std::array const& input, std::size_t start_pos) noexcept { constexpr auto remaining_size = Size % 64; return make_remaining(input, start_pos, std::make_index_sequence()); } - template - constexpr auto make_buffer(std::array const& remaining_buffer) noexcept + template + constexpr auto make_buffer(std::array const& remaining_buffer) noexcept { constexpr auto message_length = (RemainderSize + 8 <= 64) ? 64 : 64 * 2; constexpr auto padding_length = message_length - RemainderSize - 8; - auto padding_buffer = std::array{}; + auto padding_buffer = std::array{}; auto length_buffer = size_to_bytes(InputSize * 8); return combine(remaining_buffer, padding_buffer, length_buffer); } - template - constexpr std::array finalize_remaining_buffer(std::array const& input, std::array const& intermediate_hash) noexcept + template + constexpr std::array finalize_remaining_buffer(std::array const& input, std::array const& intermediate_hash) noexcept { if constexpr (Size == 64) { @@ -399,22 +399,22 @@ namespace winrt::impl } } - template - constexpr std::array get_result(std::array const& intermediate_hash, std::index_sequence) noexcept + template + constexpr std::array get_result(std::array const& intermediate_hash, std::index_sequence) noexcept { - return { static_cast(intermediate_hash[Index >> 2] >> (8 * (3 - (Index & 0x03))))... }; + return { static_cast(intermediate_hash[Index >> 2] >> (8 * (3 - (Index & 0x03))))... }; } - constexpr auto get_result(std::array const& intermediate_hash) noexcept + constexpr auto get_result(std::array const& intermediate_hash) noexcept { return get_result(intermediate_hash, std::make_index_sequence<20>{}); } - template - constexpr auto calculate_sha1(std::array const& input) noexcept + template + constexpr auto calculate_sha1(std::array const& input) noexcept { - std::array intermediate_hash{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; - size_t i = 0; + std::array intermediate_hash{ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; + std::size_t i = 0; while (i + 64 <= Size) { @@ -426,7 +426,7 @@ namespace winrt::impl return get_result(intermediate_hash); } - template + template constexpr guid generate_guid(std::array const& value) noexcept { guid namespace_guid = { 0xd57af411, 0x737b, 0xc042,{ 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee } }; @@ -453,17 +453,17 @@ namespace winrt::impl template struct pinterface_guid { +#ifdef _MSC_VER #pragma warning(suppress: 4307) +#endif static constexpr guid value{ generate_guid(signature::data) }; }; template -#ifdef __clang__ - inline static const auto name_v -#else +#ifdef _MSC_VER #pragma warning(suppress: 4307) - inline constexpr auto name_v #endif + inline constexpr auto name_v { combine ( @@ -472,7 +472,7 @@ namespace winrt::impl ) }; - constexpr size_t to_utf8_size(wchar_t const value) noexcept + constexpr std::size_t to_utf8_size(wchar_t const value) noexcept { if (value <= 0x7F) { @@ -487,7 +487,7 @@ namespace winrt::impl return 3; } - constexpr size_t to_utf8(wchar_t const value, char* buffer) noexcept + constexpr std::size_t to_utf8(wchar_t const value, char* buffer) noexcept { if (value <= 0x7F) { @@ -509,10 +509,10 @@ namespace winrt::impl } template - constexpr size_t to_utf8_size() noexcept + constexpr std::size_t to_utf8_size() noexcept { auto input = to_array(name_v); - size_t length = 0; + std::size_t length = 0; for (wchar_t const element : input) { @@ -527,7 +527,7 @@ namespace winrt::impl { auto input = to_array(name_v); std::array()> output{}; - size_t offset{}; + std::size_t offset{}; for (wchar_t const element : input) { @@ -544,14 +544,14 @@ namespace winrt::impl constexpr auto& basic_signature_v = ""; template <> inline constexpr auto& basic_signature_v = "b1"; - template <> inline constexpr auto& basic_signature_v = "i1"; - template <> inline constexpr auto& basic_signature_v = "i2"; - template <> inline constexpr auto& basic_signature_v = "i4"; - template <> inline constexpr auto& basic_signature_v = "i8"; - template <> inline constexpr auto& basic_signature_v = "u1"; - template <> inline constexpr auto& basic_signature_v = "u2"; - template <> inline constexpr auto& basic_signature_v = "u4"; - template <> inline constexpr auto& basic_signature_v = "u8"; + template <> inline constexpr auto& basic_signature_v = "i1"; + template <> inline constexpr auto& basic_signature_v = "i2"; + template <> inline constexpr auto& basic_signature_v = "i4"; + template <> inline constexpr auto& basic_signature_v = "i8"; + template <> inline constexpr auto& basic_signature_v = "u1"; + template <> inline constexpr auto& basic_signature_v = "u2"; + template <> inline constexpr auto& basic_signature_v = "u4"; + template <> inline constexpr auto& basic_signature_v = "u8"; template <> inline constexpr auto& basic_signature_v = "f4"; template <> inline constexpr auto& basic_signature_v = "f8"; template <> inline constexpr auto& basic_signature_v = "c2"; @@ -560,14 +560,14 @@ namespace winrt::impl template <> inline constexpr auto& basic_signature_v = "cinterface(IInspectable)"; template <> inline constexpr auto& name_v = L"Boolean"; - template <> inline constexpr auto& name_v = L"Int8"; - template <> inline constexpr auto& name_v = L"Int16"; - template <> inline constexpr auto& name_v = L"Int32"; - template <> inline constexpr auto& name_v = L"Int64"; - template <> inline constexpr auto& name_v = L"UInt8"; - template <> inline constexpr auto& name_v = L"UInt16"; - template <> inline constexpr auto& name_v = L"UInt32"; - template <> inline constexpr auto& name_v = L"UInt64"; + template <> inline constexpr auto& name_v = L"Int8"; + template <> inline constexpr auto& name_v = L"Int16"; + template <> inline constexpr auto& name_v = L"Int32"; + template <> inline constexpr auto& name_v = L"Int64"; + template <> inline constexpr auto& name_v = L"UInt8"; + template <> inline constexpr auto& name_v = L"UInt16"; + template <> inline constexpr auto& name_v = L"UInt32"; + template <> inline constexpr auto& name_v = L"UInt64"; template <> inline constexpr auto& name_v = L"Single"; template <> inline constexpr auto& name_v = L"Double"; template <> inline constexpr auto& name_v = L"Char16"; @@ -581,23 +581,23 @@ namespace winrt::impl template <> inline constexpr auto& name_v = L"IAgileObject"; template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; - template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; + template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; template <> struct category { using type = basic_category; }; - template <> struct category { using type = struct_category; }; - template <> struct category { using type = struct_category; }; + template <> struct category { using type = struct_category; }; + template <> struct category { using type = struct_category; }; template <> struct category { using type = basic_category; }; - template <> struct category { using type = struct_category; }; - template <> struct category { using type = struct_category; }; + template <> struct category { using type = struct_category; }; + template <> struct category { using type = struct_category; }; template struct category_signature @@ -642,13 +642,13 @@ namespace winrt::impl constexpr static auto data{ combine("delegate(", to_array(guid_of()), ")") }; }; - template + template constexpr std::wstring_view to_wstring_view(std::array const& value) noexcept { return { value.data(), Size - 1 }; } - template + template constexpr std::wstring_view to_wstring_view(wchar_t const (&value)[Size]) noexcept { return { value, Size - 1 }; diff --git a/strings/base_implements.h b/strings/base_implements.h index b2300edc5..0eb8db0bd 100644 --- a/strings/base_implements.h +++ b/strings/base_implements.h @@ -6,7 +6,7 @@ #endif #endif -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct marker { @@ -30,7 +30,7 @@ WINRT_EXPORT namespace winrt struct implements; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template using tuple_cat_t = decltype(std::tuple_cat(std::declval()...)); @@ -110,10 +110,25 @@ namespace winrt::impl template struct producer_convert : producer::type> { +#ifdef __clang__ + // This is sub-optimal in that it requires an AddRef and Release of the + // implementation type for every conversion, but it works around an + // issue where Clang ignores the conversion of producer_ref const + // to I&& (an rvalue ref that cannot bind a const rvalue). + // See CWG rev. 110 active issue 2077, "Overload resolution and invalid + // rvalue-reference initialization" + operator I() const noexcept + { + I result{ nullptr }; + copy_from_abi(result, (produce::type>*)this); + return result; + } +#else operator producer_ref const() const noexcept { return { (produce::type>*)this }; } +#endif operator producer_vtable const() const noexcept { @@ -201,11 +216,11 @@ namespace winrt::impl } template - void zero_abi([[maybe_unused]] void* ptr, [[maybe_unused]] uint32_t const capacity) noexcept + void zero_abi([[maybe_unused]] void* ptr, [[maybe_unused]] std::uint32_t const capacity) noexcept { if constexpr (!std::is_trivially_destructible_v) { - memset(ptr, 0, sizeof(T) * capacity); + std::memset(ptr, 0, sizeof(T) * capacity); } } @@ -214,7 +229,7 @@ namespace winrt::impl { if constexpr (!std::is_trivially_destructible_v) { - memset(ptr, 0, sizeof(T)); + std::memset(ptr, 0, sizeof(T)); } } } @@ -227,6 +242,12 @@ WINRT_EXPORT namespace winrt return &static_cast>*>(get_abi(from))->shim(); } + template + D* get_self(com_ptr const& from) noexcept + { + return static_cast(static_cast*>(from.get())); + } + template [[deprecated]] D* from_abi(I const& from) noexcept { @@ -246,31 +267,31 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct interface_list; template <> struct interface_list<> { - template - static constexpr void* find(const T*, const Predicate&) noexcept + template + static constexpr auto find(Traits const& traits) noexcept { - return nullptr; + return traits.not_found(); } }; template struct interface_list { - template - static constexpr void* find(const T* obj, const Predicate& pred) noexcept + template + static constexpr auto find(Traits const& traits) noexcept { - if (pred.template test()) + if (traits.template test()) { - return to_abi(obj); + return traits.template found(); } - return interface_list::find(obj, pred); + return interface_list::find(traits); } using first_interface = First; }; @@ -340,7 +361,9 @@ namespace winrt::impl template struct uncloaked_iids> { +#ifdef _MSC_VER #pragma warning(suppress: 4307) +#endif static constexpr std::array value{ winrt::guid_of() ... }; }; @@ -362,34 +385,88 @@ namespace winrt::impl using type = typename implements_default_interface::type; }; - struct iid_finder + template + struct find_iid_traits { - const guid& m_guid; + T const* m_object; + guid const& m_guid; template constexpr bool test() const noexcept { return is_guid_of::type>(m_guid); } + + template + constexpr void* found() const noexcept + { + return to_abi(m_object); + } + + static constexpr void* not_found() noexcept + { + return nullptr; + } }; template - auto find_iid(const T* obj, const guid& iid) noexcept + auto find_iid(T const* obj, guid const& iid) noexcept { - return static_cast(implemented_interfaces::find(obj, iid_finder{ iid })); + return static_cast(implemented_interfaces::find(find_iid_traits{ obj, iid })); } - struct inspectable_finder + template + struct has_interface_traits { + template + constexpr bool test() const noexcept + { + return std::is_same_v; + } + + template + static constexpr bool found() noexcept + { + return true; + } + + static constexpr bool not_found() noexcept + { + return false; + } + }; + + template + constexpr bool has_interface() noexcept + { + return impl::implemented_interfaces::find(has_interface_traits{}); + } + + template + struct find_inspectable_traits + { + T const* m_object; + template static constexpr bool test() noexcept { return std::is_base_of_v>; } + + template + constexpr void* found() const noexcept + { + return to_abi(m_object); + } + + static constexpr void* not_found() noexcept + { + return nullptr; + } }; template - inspectable_abi* find_inspectable(const T* obj) noexcept + inspectable_abi* find_inspectable(T const* obj) noexcept { using default_interface = typename implements_default_interface::type; @@ -399,7 +476,7 @@ namespace winrt::impl } else { - return static_cast(implemented_interfaces::find(obj, inspectable_finder{})); + return static_cast(implemented_interfaces::find(find_inspectable_traits{ obj })); } } @@ -445,32 +522,32 @@ namespace winrt::impl return*static_cast(reinterpret_cast*>(this)); } - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept override + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept override { return shim().QueryInterface(id, object); } - uint32_t __stdcall AddRef() noexcept override + std::uint32_t __stdcall AddRef() noexcept override { return shim().AddRef(); } - uint32_t __stdcall Release() noexcept override + std::uint32_t __stdcall Release() noexcept override { return shim().Release(); } - int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept override + std::int32_t __stdcall GetIids(std::uint32_t* count, guid** array) noexcept override { return shim().GetIids(reinterpret_cast(count), reinterpret_cast(array)); } - int32_t __stdcall GetRuntimeClassName(void** name) noexcept override + std::int32_t __stdcall GetRuntimeClassName(void** name) noexcept override { return shim().abi_GetRuntimeClassName(name); } - int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept final + std::int32_t __stdcall GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept final { return shim().abi_GetTrustLevel(trustLevel); } @@ -502,27 +579,27 @@ namespace winrt::impl template struct produce : produce_base { - int32_t __stdcall QueryInterface(const guid& id, void** object) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { return this->shim().NonDelegatingQueryInterface(id, object); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return this->shim().NonDelegatingAddRef(); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { return this->shim().NonDelegatingRelease(); } - int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept final + std::int32_t __stdcall GetIids(std::uint32_t* count, guid** array) noexcept final { return this->shim().NonDelegatingGetIids(count, array); } - int32_t __stdcall GetRuntimeClassName(void** name) noexcept final + std::int32_t __stdcall GetRuntimeClassName(void** name) noexcept final { return this->shim().NonDelegatingGetRuntimeClassName(name); } @@ -542,7 +619,7 @@ namespace winrt::impl return static_cast*>(reinterpret_cast*>(this)); } - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { if (is_guid_of(id)) { @@ -554,17 +631,17 @@ namespace winrt::impl return that()->m_object->QueryInterface(id, object); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return that()->increment_strong(); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { return that()->m_object->Release(); } - int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept final + std::int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept final { *weakReference = that(); that()->AddRef(); @@ -582,14 +659,14 @@ namespace winrt::impl template struct weak_ref final : IWeakReference, weak_source_producer { - weak_ref(unknown_abi* object, uint32_t const strong) noexcept : + weak_ref(unknown_abi* object, std::uint32_t const strong) noexcept : m_object(object), m_strong(strong) { WINRT_ASSERT(object); } - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { if (is_guid_of(id) || is_guid_of(id)) { @@ -617,14 +694,14 @@ namespace winrt::impl return error_no_interface; } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return 1 + m_weak.fetch_add(1, std::memory_order_relaxed); } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { - uint32_t const target = m_weak.fetch_sub(1, std::memory_order_relaxed) - 1; + std::uint32_t const target = m_weak.fetch_sub(1, std::memory_order_relaxed) - 1; if (target == 0) { @@ -634,9 +711,9 @@ namespace winrt::impl return target; } - int32_t __stdcall Resolve(guid const& id, void** objectReference) noexcept final + std::int32_t __stdcall Resolve(guid const& id, void** objectReference) noexcept final { - uint32_t target = m_strong.load(std::memory_order_relaxed); + std::uint32_t target = m_strong.load(std::memory_order_relaxed); while (true) { @@ -648,26 +725,26 @@ namespace winrt::impl if (m_strong.compare_exchange_weak(target, target + 1, std::memory_order_acquire, std::memory_order_relaxed)) { - int32_t hr = m_object->QueryInterface(id, objectReference); + std::int32_t hr = m_object->QueryInterface(id, objectReference); m_strong.fetch_sub(1, std::memory_order_relaxed); return hr; } } } - void set_strong(uint32_t const count) noexcept + void set_strong(std::uint32_t const count) noexcept { m_strong = count; } - uint32_t increment_strong() noexcept + std::uint32_t increment_strong() noexcept { return 1 + m_strong.fetch_add(1, std::memory_order_relaxed); } - uint32_t decrement_strong() noexcept + std::uint32_t decrement_strong() noexcept { - uint32_t const target = m_strong.fetch_sub(1, std::memory_order_release) - 1; + std::uint32_t const target = m_strong.fetch_sub(1, std::memory_order_release) - 1; if (target == 0) { @@ -690,12 +767,12 @@ namespace winrt::impl static_assert(sizeof(weak_source_producer) == sizeof(weak_source)); unknown_abi* m_object{}; - std::atomic m_strong{ 1 }; - std::atomic m_weak{ 1 }; + std::atomic m_strong{ 1 }; + std::atomic m_weak{ 1 }; }; template - struct __declspec(empty_bases) root_implements_composing_outer + struct WINRT_IMPL_EMPTY_BASES root_implements_composing_outer { protected: static constexpr bool is_composing = false; @@ -703,7 +780,7 @@ namespace winrt::impl }; template <> - struct __declspec(empty_bases) root_implements_composing_outer + struct WINRT_IMPL_EMPTY_BASES root_implements_composing_outer { template auto try_as() const noexcept @@ -715,23 +792,34 @@ namespace winrt::impl { return m_inner.operator bool(); } + + template + friend auto winrt::impl::try_as_with_reason(From ptr, hresult& code) noexcept; + protected: static constexpr bool is_composing = true; Windows::Foundation::IInspectable m_inner; + + private: + template + auto try_as_with_reason(hresult& code) const noexcept + { + return m_inner.try_as_with_reason(code); + } }; template - struct __declspec(empty_bases) root_implements_composable_inner + struct WINRT_IMPL_EMPTY_BASES root_implements_composable_inner { protected: - static constexpr inspectable_abi* outer() noexcept { return nullptr; } + static inspectable_abi* outer() noexcept { return nullptr; } template friend class produce_dispatch_to_overridable_base; }; template - struct __declspec(empty_bases) root_implements_composable_inner : producer + struct WINRT_IMPL_EMPTY_BASES root_implements_composable_inner : producer { protected: inspectable_abi* outer() noexcept { return m_outer; } @@ -746,7 +834,7 @@ namespace winrt::impl }; template - struct __declspec(novtable) root_implements + struct WINRT_IMPL_NOVTABLE root_implements : root_implements_composing_outer...>> , root_implements_composable_inner...>> , module_lock_updater...>> @@ -754,14 +842,14 @@ namespace winrt::impl using IInspectable = Windows::Foundation::IInspectable; using root_implements_type = root_implements; - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept { if (this->outer()) { return this->outer()->QueryInterface(id, object); } - int32_t result = query_interface(id, object); + std::int32_t result = query_interface(id, object); if (result == error_no_interface && this->m_inner) { @@ -771,7 +859,7 @@ namespace winrt::impl return result; } - uint32_t __stdcall AddRef() noexcept + std::uint32_t __stdcall AddRef() noexcept { if (this->outer()) { @@ -781,7 +869,7 @@ namespace winrt::impl return NonDelegatingAddRef(); } - uint32_t __stdcall Release() noexcept + std::uint32_t __stdcall Release() noexcept { if (this->outer()) { @@ -819,7 +907,7 @@ namespace winrt::impl protected: - virtual int32_t query_interface_tearoff(guid const&, void**) const noexcept + virtual std::int32_t query_interface_tearoff(guid const&, void**) const noexcept { return error_no_interface; } @@ -831,10 +919,10 @@ namespace winrt::impl virtual ~root_implements() noexcept { // If a weak reference is created during destruction, this ensures that it is also destroyed. - subtract_reference(); + subtract_final_reference(); } - int32_t __stdcall GetIids(uint32_t* count, guid** array) noexcept + std::int32_t __stdcall GetIids(std::uint32_t* count, guid** array) noexcept { if (this->outer()) { @@ -844,7 +932,7 @@ namespace winrt::impl return NonDelegatingGetIids(count, array); } - int32_t __stdcall abi_GetRuntimeClassName(void** name) noexcept + std::int32_t __stdcall abi_GetRuntimeClassName(void** name) noexcept { if (this->outer()) { @@ -854,7 +942,7 @@ namespace winrt::impl return NonDelegatingGetRuntimeClassName(name); } - int32_t __stdcall abi_GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept + std::int32_t __stdcall abi_GetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept { if (this->outer()) { @@ -864,11 +952,11 @@ namespace winrt::impl return NonDelegatingGetTrustLevel(trustLevel); } - uint32_t __stdcall NonDelegatingAddRef() noexcept + std::uint32_t __stdcall NonDelegatingAddRef() noexcept { if constexpr (is_weak_ref_source::value) { - uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); + std::uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); while (true) { @@ -877,11 +965,11 @@ namespace winrt::impl return decode_weak_ref(count_or_pointer)->increment_strong(); } - uintptr_t const target = count_or_pointer + 1; + std::uintptr_t const target = count_or_pointer + 1; if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_relaxed)) { - return static_cast(target); + return static_cast(target); } } } @@ -891,16 +979,12 @@ namespace winrt::impl } } - uint32_t __stdcall NonDelegatingRelease() noexcept + std::uint32_t __stdcall NonDelegatingRelease() noexcept { - uint32_t const target = subtract_reference(); + std::uint32_t const target = subtract_reference(); if (target == 0) { - // If a weak reference was previously created, the m_references value will not be stable value (won't be zero). - // This ensures destruction has a stable value during destruction. - m_references = 1; - if constexpr (has_final_release::value) { D::final_release(std::unique_ptr(static_cast(this))); @@ -914,7 +998,7 @@ namespace winrt::impl return target; } - int32_t __stdcall NonDelegatingQueryInterface(const guid& id, void** object) noexcept + std::int32_t __stdcall NonDelegatingQueryInterface(guid const& id, void** object) noexcept { if (is_guid_of(id) || is_guid_of(id)) { @@ -924,7 +1008,7 @@ namespace winrt::impl return 0; } - int32_t result = query_interface(id, object); + std::int32_t result = query_interface(id, object); if (result == error_no_interface && this->m_inner) { @@ -934,23 +1018,23 @@ namespace winrt::impl return result; } - int32_t __stdcall NonDelegatingGetIids(uint32_t* count, guid** array) noexcept + std::int32_t __stdcall NonDelegatingGetIids(std::uint32_t* count, guid** array) noexcept { - const auto& local_iids = static_cast(this)->get_local_iids(); - const uint32_t& local_count = local_iids.first; + auto const& local_iids = static_cast(this)->get_local_iids(); + std::uint32_t const& local_count = local_iids.first; if constexpr (root_implements_type::is_composing) { if (local_count > 0) { - const com_array& inner_iids = get_interfaces(root_implements_type::m_inner); + com_array const& inner_iids = get_interfaces(root_implements_type::m_inner); *count = local_count + inner_iids.size(); *array = static_cast(WINRT_IMPL_CoTaskMemAlloc(sizeof(guid)*(*count))); if (*array == nullptr) { return error_bad_alloc; } - *array = std::copy(local_iids.second, local_iids.second + local_count, *array); - std::copy(inner_iids.cbegin(), inner_iids.cend(), *array); + auto next = std::copy(local_iids.second, local_iids.second + local_count, *array); + std::copy(inner_iids.cbegin(), inner_iids.cend(), next); } else { @@ -978,25 +1062,25 @@ namespace winrt::impl return 0; } - int32_t __stdcall NonDelegatingGetRuntimeClassName(void** name) noexcept try + std::int32_t __stdcall NonDelegatingGetRuntimeClassName(void** name) noexcept try { *name = detach_abi(static_cast(this)->GetRuntimeClassName()); return 0; } catch (...) { return to_hresult(); } - int32_t __stdcall NonDelegatingGetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept try + std::int32_t __stdcall NonDelegatingGetTrustLevel(Windows::Foundation::TrustLevel* trustLevel) noexcept try { *trustLevel = static_cast(this)->GetTrustLevel(); return 0; } catch (...) { return to_hresult(); } - uint32_t subtract_reference() noexcept + std::uint32_t subtract_final_reference() noexcept { if constexpr (is_weak_ref_source::value) { - uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); + std::uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); while (true) { @@ -1005,11 +1089,11 @@ namespace winrt::impl return decode_weak_ref(count_or_pointer)->decrement_strong(); } - uintptr_t const target = count_or_pointer - 1; + std::uintptr_t const target = count_or_pointer - 1; if (m_references.compare_exchange_weak(count_or_pointer, target, std::memory_order_release, std::memory_order_relaxed)) { - return static_cast(target); + return static_cast(target); } } } @@ -1019,6 +1103,19 @@ namespace winrt::impl } } + std::uint32_t subtract_reference() noexcept + { + std::uint32_t result = subtract_final_reference(); + + if (result == 0) + { + // Ensure destruction happens with a stable reference count that isn't a weak reference. + m_references.store(1, std::memory_order_relaxed); + } + + return result; + } + template winrt::weak_ref get_weak() { @@ -1054,13 +1151,13 @@ namespace winrt::impl using is_agile = std::negation...>>; using is_inspectable = std::disjunction...>; - using is_weak_ref_source = std::conjunction...>>>; + using is_weak_ref_source = std::negation...>>; using use_module_lock = std::negation...>>; using weak_ref_t = impl::weak_ref; - std::atomic> m_references{ 1 }; + std::atomic> m_references{ 1 }; - int32_t query_interface(guid const& id, void** object) noexcept + std::int32_t query_interface(guid const& id, void** object) noexcept { *object = static_cast(this)->find_interface(id); @@ -1070,19 +1167,16 @@ namespace winrt::impl return 0; } - if constexpr (is_agile::value) - { - if (is_guid_of(id)) - { - *object = get_unknown(); - AddRef(); - return 0; - } + return query_interface_common(id, object); + } - if (is_guid_of(id)) - { - return make_marshaler(get_unknown(), object); - } + WINRT_IMPL_NOINLINE std::int32_t query_interface_common(guid const& id, void** object) noexcept + { + if (is_guid_of(id)) + { + *object = get_unknown(); + AddRef(); + return 0; } if constexpr (is_inspectable::value) @@ -1095,13 +1189,6 @@ namespace winrt::impl } } - if (is_guid_of(id)) - { - *object = get_unknown(); - AddRef(); - return 0; - } - if constexpr (is_weak_ref_source::value) { if (is_guid_of(id)) @@ -1110,70 +1197,91 @@ namespace winrt::impl return *object ? error_ok : error_bad_alloc; } } + + if constexpr (is_agile::value) + { + if (is_guid_of(id)) + { + *object = get_unknown(); + AddRef(); + return 0; + } + + if (is_guid_of(id)) + { + return make_marshaler(get_unknown(), object); + } + } return query_interface_tearoff(id, object); } impl::IWeakReferenceSource* make_weak_ref() noexcept { - static_assert(is_weak_ref_source::value, "This is only for weak ref support."); - uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); - - if (is_weak_ref(count_or_pointer)) + if constexpr (is_weak_ref_source::value) { - return decode_weak_ref(count_or_pointer)->get_source(); - } + std::uintptr_t count_or_pointer = m_references.load(std::memory_order_relaxed); - com_ptr weak_ref; - *weak_ref.put() = new (std::nothrow) weak_ref_t(get_unknown(), static_cast(count_or_pointer)); - - if (!weak_ref) - { - return nullptr; - } + if (is_weak_ref(count_or_pointer)) + { + return decode_weak_ref(count_or_pointer)->get_source(); + } - uintptr_t const encoding = encode_weak_ref(weak_ref.get()); + com_ptr weak_ref(new (std::nothrow) weak_ref_t(get_unknown(), static_cast(count_or_pointer)), take_ownership_from_abi); - for (;;) - { - if (m_references.compare_exchange_weak(count_or_pointer, encoding, std::memory_order_acq_rel, std::memory_order_relaxed)) + if (!weak_ref) { - impl::IWeakReferenceSource* result = weak_ref->get_source(); - detach_abi(weak_ref); - return result; + return nullptr; } - if (is_weak_ref(count_or_pointer)) + std::uintptr_t const encoding = encode_weak_ref(weak_ref.get()); + + while (true) { - return decode_weak_ref(count_or_pointer)->get_source(); - } + if (m_references.compare_exchange_weak(count_or_pointer, encoding, std::memory_order_acq_rel, std::memory_order_relaxed)) + { + impl::IWeakReferenceSource* result = weak_ref->get_source(); + detach_abi(weak_ref); + return result; + } - weak_ref->set_strong(static_cast(count_or_pointer)); + if (is_weak_ref(count_or_pointer)) + { + return decode_weak_ref(count_or_pointer)->get_source(); + } + + weak_ref->set_strong(static_cast(count_or_pointer)); + } + } + else + { + static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified."); + return nullptr; } } - static bool is_weak_ref(intptr_t const value) noexcept + static bool is_weak_ref(std::intptr_t const value) noexcept { - static_assert(is_weak_ref_source::value, "This is only for weak ref support."); + static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified."); return value < 0; } - static weak_ref_t* decode_weak_ref(uintptr_t const value) noexcept + static weak_ref_t* decode_weak_ref(std::uintptr_t const value) noexcept { - static_assert(is_weak_ref_source::value, "This is only for weak ref support."); + static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified."); return reinterpret_cast(value << 1); } - static uintptr_t encode_weak_ref(weak_ref_t* value) noexcept + static std::uintptr_t encode_weak_ref(weak_ref_t* value) noexcept { - static_assert(is_weak_ref_source::value, "This is only for weak ref support."); - constexpr uintptr_t pointer_flag = static_cast(1) << ((sizeof(uintptr_t) * 8) - 1); - WINRT_ASSERT((reinterpret_cast(value) & 1) == 0); - return (reinterpret_cast(value) >> 1) | pointer_flag; + static_assert(is_weak_ref_source::value, "Weak references are not supported because no_weak_ref was specified."); + constexpr std::uintptr_t pointer_flag = static_cast(1) << ((sizeof(std::uintptr_t) * 8) - 1); + WINRT_ASSERT((reinterpret_cast(value) & 1) == 0); + return (reinterpret_cast(value) >> 1) | pointer_flag; } virtual unknown_abi* get_unknown() const noexcept = 0; - virtual std::pair get_local_iids() const noexcept = 0; + virtual std::pair get_local_iids() const noexcept = 0; virtual hstring GetRuntimeClassName() const = 0; virtual void* find_interface(guid const&) const noexcept = 0; virtual inspectable_abi* find_inspectable() const noexcept = 0; @@ -1202,6 +1310,29 @@ namespace winrt::impl }; #endif + template + class has_initializer + { + template ().InitializeComponent())> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + + public: + static constexpr bool value = get_value(0); + }; + + template + T* create_and_initialize(Args&&... args) + { + com_ptr instance{ new heap_implements(std::forward(args)...), take_ownership_from_abi }; + + if constexpr (has_initializer::value) + { + instance->InitializeComponent(); + } + + return instance.detach(); + } + inline com_ptr get_static_lifetime_map() { auto const lifetime_factory = get_activation_factory(L"Windows.ApplicationModel.Core.CoreApplication"); @@ -1217,7 +1348,7 @@ namespace winrt::impl if constexpr (!has_static_lifetime_v) { - return { to_abi(new heap_implements), take_ownership_from_abi }; + return { to_abi(create_and_initialize()), take_ownership_from_abi }; } else { @@ -1231,7 +1362,7 @@ namespace winrt::impl return { result, take_ownership_from_abi }; } - result_type object{ to_abi(new heap_implements), take_ownership_from_abi }; + result_type object{ to_abi(create_and_initialize()), take_ownership_from_abi }; static slim_mutex lock; slim_lock_guard const guard{ lock }; @@ -1259,6 +1390,10 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4702) // Compiler bug causing spurious "unreachable code" warnings +#endif template auto make(Args&&... args) { @@ -1277,17 +1412,17 @@ WINRT_EXPORT namespace winrt } else if constexpr (impl::has_composable::value) { - impl::com_ref result{ to_abi(new impl::heap_implements(std::forward(args)...)), take_ownership_from_abi }; + impl::com_ref result{ to_abi(impl::create_and_initialize(std::forward(args)...)), take_ownership_from_abi }; return result.template as(); } else if constexpr (impl::has_class_type::value) { static_assert(std::is_same_v>); - return typename D::class_type{ to_abi(new impl::heap_implements(std::forward(args)...)), take_ownership_from_abi }; + return typename D::class_type{ to_abi(impl::create_and_initialize(std::forward(args)...)), take_ownership_from_abi }; } else { - return impl::com_ref{ to_abi(new impl::heap_implements(std::forward(args)...)), take_ownership_from_abi }; + return impl::com_ref{ to_abi(impl::create_and_initialize(std::forward(args)...)), take_ownership_from_abi }; } } @@ -1309,9 +1444,12 @@ WINRT_EXPORT namespace winrt } else { - return { new impl::heap_implements(std::forward(args)...), take_ownership_from_abi }; + return { impl::create_and_initialize(std::forward(args)...), take_ownership_from_abi }; } } +#ifdef _MSC_VER +#pragma warning(pop) +#endif template inline void clear_factory_static_lifetime() @@ -1369,6 +1507,10 @@ WINRT_EXPORT namespace winrt return result; } +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif impl::hresult_type __stdcall QueryInterface(impl::guid_type const& id, void** object) noexcept { return root_implements_type::QueryInterface(reinterpret_cast(id), object); @@ -1386,7 +1528,7 @@ WINRT_EXPORT namespace winrt impl::hresult_type __stdcall GetIids(impl::count_type* count, impl::guid_type** iids) noexcept { - return root_implements_type::GetIids(reinterpret_cast(count), reinterpret_cast(iids)); + return root_implements_type::GetIids(reinterpret_cast(count), reinterpret_cast(iids)); } impl::hresult_type __stdcall GetRuntimeClassName(impl::hstring_type* value) noexcept @@ -1400,6 +1542,9 @@ WINRT_EXPORT namespace winrt { return root_implements_type::abi_GetTrustLevel(reinterpret_cast(value)); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif void* find_interface(guid const& id) const noexcept override { @@ -1411,11 +1556,11 @@ WINRT_EXPORT namespace winrt return impl::find_inspectable(static_cast(this)); } - std::pair get_local_iids() const noexcept override + std::pair get_local_iids() const noexcept override { using interfaces = impl::uncloaked_interfaces; using local_iids = impl::uncloaked_iids; - return { static_cast(local_iids::value.size()), local_iids::value.data() }; + return { static_cast(local_iids::value.size()), local_iids::value.data() }; } private: diff --git a/strings/base_include_numerics.h b/strings/base_include_numerics.h new file mode 100644 index 000000000..4b7658fff --- /dev/null +++ b/strings/base_include_numerics.h @@ -0,0 +1,19 @@ + +// Includes when WINRT_IMPL_NUMERICS is defined. +// Requires to already be included (via base_detect_numerics). +// The types are redirected into winrt::Windows::Foundation::Numerics via macro wrapping. +// Uses WINRT_EXPORT for the namespace declaration, which resolves to 'export extern "C++"' +// in module builds and nothing in header builds. +#ifdef WINRT_IMPL_NUMERICS +#ifndef WINRT_EXPORT +#define WINRT_EXPORT +#endif +#include +#define _WINDOWS_NUMERICS_NAMESPACE_ winrt::Windows::Foundation::Numerics +#define _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ WINRT_EXPORT namespace winrt::Windows::Foundation::Numerics +#define _WINDOWS_NUMERICS_END_NAMESPACE_ +#include +#undef _WINDOWS_NUMERICS_NAMESPACE_ +#undef _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ +#undef _WINDOWS_NUMERICS_END_NAMESPACE_ +#endif // WINRT_IMPL_NUMERICS diff --git a/strings/base_includes.h b/strings/base_includes.h index 14d992fc9..bac7358bd 100644 --- a/strings/base_includes.h +++ b/strings/base_includes.h @@ -1,14 +1,23 @@ +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include +#include #include +#include #include #include #include +#include #include #include #include @@ -19,39 +28,28 @@ #include #include -#if __has_include() -#define WINRT_IMPL_NUMERICS -#include +#if __has_include() +#include +#endif + +#ifndef WINRT_LEAN_AND_MEAN +#include +#endif + +#ifdef __cpp_lib_span +#include #endif #ifdef __cpp_lib_format #include #endif -#ifdef __cpp_lib_coroutine +#ifdef __cpp_lib_source_location +#include +#endif +#ifdef __cpp_lib_coroutine #include - -namespace winrt::impl -{ - template - using coroutine_handle = std::coroutine_handle; - - using suspend_always = std::suspend_always; - using suspend_never = std::suspend_never; -} - -#else - -#include - -namespace winrt::impl -{ - template - using coroutine_handle = std::experimental::coroutine_handle; - - using suspend_always = std::experimental::suspend_always; - using suspend_never = std::experimental::suspend_never; -} - +#elif defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +#error "C++/WinRT no longer supports pre-standardization coroutines. If you use co_await, switch to /await:strict or upgrade to C++20. If you do not, remove /await from the compiler flags." #endif diff --git a/strings/base_iterator.h b/strings/base_iterator.h index b0ad7836d..46c0c6b63 100644 --- a/strings/base_iterator.h +++ b/strings/base_iterator.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct fast_iterator @@ -7,13 +7,13 @@ namespace winrt::impl using iterator_concept = std::random_access_iterator_tag; using iterator_category = std::input_iterator_tag; using value_type = decltype(std::declval().GetAt(0)); - using difference_type = ptrdiff_t; + using difference_type = std::ptrdiff_t; using pointer = void; using reference = value_type; fast_iterator() noexcept = default; - fast_iterator(T const& collection, uint32_t const index) noexcept : + fast_iterator(T const& collection, std::uint32_t const index) noexcept : m_collection(&collection), m_index(index) {} @@ -46,7 +46,7 @@ namespace winrt::impl fast_iterator& operator+=(difference_type n) noexcept { - m_index += static_cast(n); + m_index += static_cast(n); return *this; } @@ -78,7 +78,7 @@ namespace winrt::impl reference operator[](difference_type n) const { - return m_collection->GetAt(m_index + static_cast(n)); + return m_collection->GetAt(m_index + static_cast(n)); } bool operator==(fast_iterator const& other) const noexcept @@ -127,7 +127,7 @@ namespace winrt::impl private: T const* m_collection = nullptr; - uint32_t m_index = 0; + std::uint32_t m_index = 0; }; template diff --git a/strings/base_lock.h b/strings/base_lock.h index cf70a001a..a0d6261e4 100644 --- a/strings/base_lock.h +++ b/strings/base_lock.h @@ -117,7 +117,7 @@ WINRT_EXPORT namespace winrt return false; } - if (!WINRT_IMPL_SleepConditionVariableSRW(&m_cv, x.get(), static_cast(milliseconds), 0)) + if (!WINRT_IMPL_SleepConditionVariableSRW(&m_cv, x.get(), static_cast(milliseconds), 0)) { return predicate(); } diff --git a/strings/base_macros.h b/strings/base_macros.h index 1b96e240c..850d0c627 100644 --- a/strings/base_macros.h +++ b/strings/base_macros.h @@ -1,3 +1,6 @@ +#pragma once +#ifndef WINRT_BASE_MACROS_H +#define WINRT_BASE_MACROS_H #ifdef _DEBUG @@ -11,39 +14,44 @@ #define WINRT_VERIFY(expression) (void)(expression) #define WINRT_VERIFY_(result, expression) (void)(expression) -#endif +#endif // _DEBUG -#define WINRT_IMPL_SHIM(...) (*(abi_t<__VA_ARGS__>**)&static_cast<__VA_ARGS__ const&>(static_cast(*this))) +#if defined(__cpp_lib_coroutine) +#define WINRT_IMPL_COROUTINES +#endif // __cpp_lib_coroutine -#ifdef __INTELLISENSE__ -#define WINRT_IMPL_AUTO(...) __VA_ARGS__ -#else -#define WINRT_IMPL_AUTO(...) auto -#endif +#define WINRT_IMPL_SHIM(...) (*(abi_t<__VA_ARGS__>**)&static_cast<__VA_ARGS__ const&>(static_cast(*this))) +#ifdef _MSC_VER // Note: this is a workaround for a false-positive warning produced by the Visual C++ 15.9 compiler. #pragma warning(disable : 5046) // Note: this is a workaround for a false-positive warning produced by the Visual C++ 16.3 compiler. #pragma warning(disable : 4268) -#if defined(__cpp_lib_coroutine) || defined(__cpp_coroutines) || defined(_RESUMABLE_FUNCTIONS_SUPPORTED) -#define WINRT_IMPL_COROUTINES -#endif +// C++ module warnings by /W4 +#pragma warning(disable : 4499) +#pragma warning(disable : 4630) +#endif // _MSC_VER #ifndef WINRT_EXPORT +#ifdef WINRT_IMPL_BUILD_MODULE +#define WINRT_EXPORT export extern "C++" +#else #define WINRT_EXPORT -#endif +#endif // WINRT_IMPL_BUILD_MODULE +#endif // WINRT_EXPORT -#ifdef WINRT_IMPL_NUMERICS -#define _WINDOWS_NUMERICS_NAMESPACE_ winrt::Windows::Foundation::Numerics -#define _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ WINRT_EXPORT namespace winrt::Windows::Foundation::Numerics -#define _WINDOWS_NUMERICS_END_NAMESPACE_ -#include -#undef _WINDOWS_NUMERICS_NAMESPACE_ -#undef _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ -#undef _WINDOWS_NUMERICS_END_NAMESPACE_ -#endif +// Template specializations in namespace std (hash, coroutine_traits) need extern "C++" +// linkage in module builds for proper merging with the std module, but must NOT be +// exported - exporting namespace std would make all of std transitively visible. +#ifndef WINRT_IMPL_STD_EXPORT +#ifdef WINRT_IMPL_BUILD_MODULE +#define WINRT_IMPL_STD_EXPORT extern "C++" +#else +#define WINRT_IMPL_STD_EXPORT +#endif // WINRT_IMPL_BUILD_MODULE +#endif // WINRT_IMPL_STD_EXPORT #if defined(_MSC_VER) #define WINRT_IMPL_NOINLINE __declspec(noinline) @@ -53,10 +61,57 @@ #define WINRT_IMPL_NOINLINE #endif -#ifdef __IUnknown_INTERFACE_DEFINED__ +#if defined(_MSC_VER) +#define WINRT_IMPL_EMPTY_BASES __declspec(empty_bases) +#else +#define WINRT_IMPL_EMPTY_BASES +#endif + +#if defined(_MSC_VER) +#define WINRT_IMPL_NOVTABLE __declspec(novtable) +#else +#define WINRT_IMPL_NOVTABLE +#endif + +#if defined(__clang__) && defined(__has_attribute) +#if __has_attribute(__lto_visibility_public__) +#define WINRT_IMPL_PUBLIC __attribute__((lto_visibility_public)) +#else +#define WINRT_IMPL_PUBLIC +#endif // __has_attribute(__lto_visibility_public__) +#else +#define WINRT_IMPL_PUBLIC +#endif + +#define WINRT_IMPL_ABI_DECL WINRT_IMPL_NOVTABLE WINRT_IMPL_PUBLIC + +#if defined(__clang__) +#define WINRT_IMPL_HAS_DECLSPEC_UUID __has_declspec_attribute(uuid) +#elif defined(_MSC_VER) +#define WINRT_IMPL_HAS_DECLSPEC_UUID 1 +#else +#define WINRT_IMPL_HAS_DECLSPEC_UUID 0 +#endif + +#if defined(__IUnknown_INTERFACE_DEFINED__) || defined(WINRT_ENABLE_LEGACY_COM) #define WINRT_IMPL_IUNKNOWN_DEFINED #else // Forward declare so we can talk about it. struct IUnknown; typedef struct _GUID GUID; #endif + +#if defined(__cpp_consteval) +#define WINRT_IMPL_CONSTEVAL consteval +#else +#define WINRT_IMPL_CONSTEVAL constexpr +#endif + +// CPPWINRT_VERSION is defined here so it is available in module global fragments. +// In header builds, base_version_odr.h defines it first (before base_macros.h is included), +// so the #ifndef guard prevents redefinition. +#ifndef CPPWINRT_VERSION +#define CPPWINRT_VERSION "%" +#endif + +#endif // WINRT_BASE_MACROS_H diff --git a/strings/base_marshaler.h b/strings/base_marshaler.h index 359cf3b47..526f4d4c3 100644 --- a/strings/base_marshaler.h +++ b/strings/base_marshaler.h @@ -1,7 +1,7 @@ namespace winrt::impl { - inline int32_t make_marshaler(unknown_abi* outer, void** result) noexcept + inline std::int32_t make_marshaler(unknown_abi* outer, void** result) noexcept { struct marshaler final : IMarshal { @@ -10,7 +10,7 @@ namespace winrt::impl m_object.copy_from(object); } - int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final + std::int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final { if (is_guid_of(id)) { @@ -22,12 +22,12 @@ namespace winrt::impl return m_object->QueryInterface(id, object); } - uint32_t __stdcall AddRef() noexcept final + std::uint32_t __stdcall AddRef() noexcept final { return ++m_references; } - uint32_t __stdcall Release() noexcept final + std::uint32_t __stdcall Release() noexcept final { auto const remaining = --m_references; @@ -39,7 +39,7 @@ namespace winrt::impl return remaining; } - int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, guid* pCid) noexcept final + std::int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags, guid* pCid) noexcept final { if (m_marshaler) { @@ -49,7 +49,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, uint32_t* pSize) noexcept final + std::int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags, std::uint32_t* pSize) noexcept final { if (m_marshaler) { @@ -59,7 +59,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags) noexcept final + std::int32_t __stdcall MarshalInterface(void* pStm, guid const& riid, void* pv, std::uint32_t dwDestContext, void* pvDestContext, std::uint32_t mshlflags) noexcept final { if (m_marshaler) { @@ -69,7 +69,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept final + std::int32_t __stdcall UnmarshalInterface(void* pStm, guid const& riid, void** ppv) noexcept final { if (m_marshaler) { @@ -80,7 +80,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept final + std::int32_t __stdcall ReleaseMarshalData(void* pStm) noexcept final { if (m_marshaler) { @@ -90,7 +90,7 @@ namespace winrt::impl return error_bad_alloc; } - int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept final + std::int32_t __stdcall DisconnectObject(std::uint32_t dwReserved) noexcept final { if (m_marshaler) { diff --git a/strings/base_meta.h b/strings/base_meta.h index f951c4db0..6b28640ef 100644 --- a/strings/base_meta.h +++ b/strings/base_meta.h @@ -1,7 +1,7 @@ WINRT_EXPORT namespace winrt { - hresult check_hresult(hresult const result); + hresult check_hresult(hresult const result, winrt::impl::slim_source_location const& sourceInformation = winrt::impl::slim_source_location::current()); hresult to_hresult() noexcept; template @@ -10,9 +10,16 @@ WINRT_EXPORT namespace winrt struct take_ownership_from_abi_t {}; inline constexpr take_ownership_from_abi_t take_ownership_from_abi{}; + // Map implementations can implement TryLookup with trylookup_from_abi_t as an optimization + struct trylookup_from_abi_t {}; + inline constexpr trylookup_from_abi_t trylookup_from_abi{}; + template struct com_ptr; + template + D* get_self(com_ptr const& from) noexcept; + namespace param { template @@ -41,7 +48,7 @@ WINRT_EXPORT namespace winrt } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { using namespace std::literals; @@ -118,16 +125,22 @@ namespace winrt::impl }; template -#if defined(__clang__) -#if __has_declspec_attribute(uuid) - inline const guid guid_v{ __uuidof(T) }; -#else - inline constexpr guid guid_v{}; + struct classic_com_guid_error + { +#if !defined(__MINGW32__) && defined(__clang__) && !WINRT_IMPL_HAS_DECLSPEC_UUID + static_assert(std::is_void_v /* dependent_false */, "To use classic COM interfaces, you must compile with -fms-extensions."); +#elif !defined(WINRT_IMPL_IUNKNOWN_DEFINED) + static_assert(std::is_void_v /* dependent_false */, "To use classic COM interfaces, you must include before including C++/WinRT headers."); +#else // MSVC won't hit this struct, so we can safely assume everything that isn't Clang isn't supported + static_assert(std::is_void_v /* dependent_false */, "Classic COM interfaces are not supported with this compiler."); #endif -#elif defined(_MSC_VER) + }; + + template +#if (defined(_MSC_VER) && !defined(__clang__)) || ((WINRT_IMPL_HAS_DECLSPEC_UUID || defined(__MINGW32__)) && defined(WINRT_IMPL_IUNKNOWN_DEFINED)) inline constexpr guid guid_v{ __uuidof(T) }; #else - inline constexpr guid guid_v{}; + inline constexpr guid guid_v = classic_com_guid_error::value; #endif template @@ -155,7 +168,7 @@ namespace winrt::impl }; template - struct __declspec(empty_bases) require : require_one... + struct WINRT_IMPL_EMPTY_BASES require : require_one... {}; template @@ -168,7 +181,7 @@ namespace winrt::impl }; template - struct __declspec(empty_bases) base : base_one... + struct WINRT_IMPL_EMPTY_BASES base : base_one... {}; template @@ -184,6 +197,25 @@ namespace winrt::impl } } + template + struct movable_primitive + { + T value = empty_value; + movable_primitive() = default; + movable_primitive(T const& init) : value(init) {} + movable_primitive(movable_primitive const&) = default; + movable_primitive(movable_primitive&& other) : + value(other.detach()) {} + movable_primitive& operator=(movable_primitive const&) = default; + movable_primitive& operator=(movable_primitive&& other) + { + value = other.detach(); + return *this; + } + + T detach() { return std::exchange(value, empty_value); } + }; + template struct arg { @@ -270,4 +302,16 @@ namespace winrt::impl return (func(Types{}) || ...); } }; + + template + struct has_TryLookup + { + template ().TryLookup(std::declval(), trylookup_from_abi))> static constexpr bool get_value(int) { return true; } + template static constexpr bool get_value(...) { return false; } + public: + static constexpr bool value = get_value(0); + }; + + template + inline constexpr bool has_TryLookup_v = has_TryLookup::value; } diff --git a/strings/base_module_base_ixx.h b/strings/base_module_base_ixx.h new file mode 100644 index 000000000..5930f54ea --- /dev/null +++ b/strings/base_module_base_ixx.h @@ -0,0 +1,13 @@ + +#include +#include + +#ifdef WINRT_ENABLE_LEGACY_COM +#include +#include +#endif + +export module winrt_base; + +import std; +export import winrt_numerics; diff --git a/strings/base_module_ixx_preamble.h b/strings/base_module_ixx_preamble.h new file mode 100644 index 000000000..114873dc7 --- /dev/null +++ b/strings/base_module_ixx_preamble.h @@ -0,0 +1,11 @@ +module; +#define WINRT_IMPL_BUILD_MODULE + +#if defined(_MSC_VER) && _MSC_VER < 1950 +#pragma message("warning: C++/WinRT modules require MSVC toolset v14.50 (v145) or later. Building with an older toolset is not supported and may produce unexpected errors.") +#endif + +#include +#ifdef _DEBUG +#include +#endif // _DEBUG diff --git a/strings/base_module_numerics_ixx.h b/strings/base_module_numerics_ixx.h new file mode 100644 index 000000000..f1ade01ff --- /dev/null +++ b/strings/base_module_numerics_ixx.h @@ -0,0 +1,6 @@ + +#include + +#if defined(_MSC_VER) +#pragma detect_mismatch("C++/WinRT version", CPPWINRT_VERSION) +#endif diff --git a/strings/base_natvis.h b/strings/base_natvis.h index 8ff4bd145..9e78563cb 100644 --- a/strings/base_natvis.h +++ b/strings/base_natvis.h @@ -5,7 +5,7 @@ #ifdef WINRT_NATVIS -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct natvis { @@ -15,19 +15,19 @@ namespace winrt::impl { bool b; wchar_t c; - int8_t i1; - int16_t i2; - int32_t i4; - int64_t i8; - uint8_t u1; - uint16_t u2; - uint32_t u4; - uint64_t u8; + std::int8_t i1; + std::int16_t i2; + std::int32_t i4; + std::int64_t i8; + std::uint8_t u1; + std::uint16_t u2; + std::uint32_t u4; + std::uint64_t u8; float r4; double r8; guid g; void* s; - uint8_t v[1024]; + std::uint8_t v[1024]; } value; value.s = 0; @@ -38,16 +38,16 @@ namespace winrt::impl { void* base_address; void* allocation_base; - uint32_t allocation_protect; + std::uint32_t allocation_protect; #ifdef _WIN64 - uint32_t __alignment1; + std::uint32_t __alignment1; #endif - uintptr_t region_size; - uint32_t state; - uint32_t protect; - uint32_t type; + std::uintptr_t region_size; + std::uint32_t state; + std::uint32_t protect; + std::uint32_t type; #ifdef _WIN64 - uint32_t __alignment2; + std::uint32_t __alignment2; #endif }; memory_basic_information info; @@ -66,7 +66,7 @@ namespace winrt::impl // validate method pointer is executable if ((WINRT_IMPL_VirtualQuery(vfunc, &info, sizeof(info)) != 0) && ((info.protect & 0xF0) != 0)) { - typedef int32_t(__stdcall inspectable_abi:: * PropertyAccessor)(void*); + typedef std::int32_t(__stdcall inspectable_abi:: * PropertyAccessor)(void*); (pinsp->**(PropertyAccessor*)&vfunc)(&value); pinsp->Release(); } diff --git a/strings/base_reference_produce.h b/strings/base_reference_produce.h index 8ea2de5b9..db9639cc3 100644 --- a/strings/base_reference_produce.h +++ b/strings/base_reference_produce.h @@ -1,100 +1,198 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template - struct reference : implements, Windows::Foundation::IReference, Windows::Foundation::IPropertyValue> + struct reference; + + template + struct reference_array; + + template + inline constexpr bool is_stock_reference_v = + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v; + + template + constexpr Windows::Foundation::PropertyType scalar_property_type() noexcept + { + using pt = Windows::Foundation::PropertyType; + + if constexpr (std::is_same_v) { return pt::UInt8; } + else if constexpr (std::is_same_v) { return pt::Int16; } + else if constexpr (std::is_same_v) { return pt::UInt16; } + else if constexpr (std::is_same_v) { return pt::Int32; } + else if constexpr (std::is_same_v) { return pt::UInt32; } + else if constexpr (std::is_same_v) { return pt::Int64; } + else if constexpr (std::is_same_v) { return pt::UInt64; } + else if constexpr (std::is_same_v) { return pt::Single; } + else if constexpr (std::is_same_v) { return pt::Double; } + else if constexpr (std::is_same_v) { return pt::Char16; } + else if constexpr (std::is_same_v) { return pt::Boolean; } + else if constexpr (std::is_same_v) { return pt::String; } + else if constexpr (std::is_same_v) { return pt::Inspectable; } + else if constexpr (std::is_same_v) { return pt::Guid; } + else if constexpr (std::is_same_v) { return pt::DateTime; } + else if constexpr (std::is_same_v) { return pt::TimeSpan; } + else if constexpr (std::is_same_v) { return pt::Point; } + else if constexpr (std::is_same_v) { return pt::Size; } + else if constexpr (std::is_same_v) { return pt::Rect; } + else { return pt::OtherType; } + } + + template + constexpr Windows::Foundation::PropertyType array_property_type() noexcept { - reference(T const& value) : m_value(value) - { - } + return static_cast( + static_cast(scalar_property_type()) + 1024); + } - T Value() const - { - return m_value; - } + template + inline constexpr bool is_numeric_scalar_v = + (std::is_arithmetic_v && !std::is_same_v && !std::is_same_v) || std::is_enum_v; + template + struct reference_producer : implements, non_agile, marker>> + { Windows::Foundation::PropertyType Type() const noexcept { - return Windows::Foundation::PropertyType::OtherType; + if constexpr (IsArray) { return array_property_type(); } + else { return scalar_property_type(); } } static constexpr bool IsNumericScalar() noexcept { - return std::is_arithmetic_v || std::is_enum_v; + return !IsArray && is_numeric_scalar_v; } - uint8_t GetUInt8() const - { - return to_scalar(); - } + std::uint8_t GetUInt8() const { return derived()->template get_as(); } + std::int16_t GetInt16() const { return derived()->template get_as(); } + std::uint16_t GetUInt16() const { return derived()->template get_as(); } + std::int32_t GetInt32() const { return derived()->template get_as(); } + std::uint32_t GetUInt32() const { return derived()->template get_as(); } + std::int64_t GetInt64() const { return derived()->template get_as(); } + std::uint64_t GetUInt64() const { return derived()->template get_as(); } + float GetSingle() const { return derived()->template get_as(); } + double GetDouble() const { return derived()->template get_as(); } + char16_t GetChar16() const { return derived()->template get_as(); } + bool GetBoolean() const { return derived()->template get_as(); } + hstring GetString() const { return derived()->template get_as(); } + guid GetGuid() const { return derived()->template get_as(); } + Windows::Foundation::DateTime GetDateTime() const { return derived()->template get_as(); } + Windows::Foundation::TimeSpan GetTimeSpan() const { return derived()->template get_as(); } + Windows::Foundation::Point GetPoint() const { return derived()->template get_as(); } + Windows::Foundation::Size GetSize() const { return derived()->template get_as(); } + Windows::Foundation::Rect GetRect() const { return derived()->template get_as(); } + void GetUInt8Array(com_array& value) const { derived()->get_as(value); } + void GetInt16Array(com_array& value) const { derived()->get_as(value); } + void GetUInt16Array(com_array& value) const { derived()->get_as(value); } + void GetInt32Array(com_array& value) const { derived()->get_as(value); } + void GetUInt32Array(com_array& value) const { derived()->get_as(value); } + void GetInt64Array(com_array& value) const { derived()->get_as(value); } + void GetUInt64Array(com_array& value) const { derived()->get_as(value); } + void GetSingleArray(com_array& value) const { derived()->get_as(value); } + void GetDoubleArray(com_array& value) const { derived()->get_as(value); } + void GetChar16Array(com_array& value) const { derived()->get_as(value); } + void GetBooleanArray(com_array& value) const { derived()->get_as(value); } + void GetStringArray(com_array& value) const { derived()->get_as(value); } + void GetInspectableArray(com_array& value) const { derived()->get_as(value); } + void GetGuidArray(com_array& value) const { derived()->get_as(value); } + void GetDateTimeArray(com_array& value) const { derived()->get_as(value); } + void GetTimeSpanArray(com_array& value) const { derived()->get_as(value); } + void GetPointArray(com_array& value) const { derived()->get_as(value); } + void GetSizeArray(com_array& value) const { derived()->get_as(value); } + void GetRectArray(com_array& value) const { derived()->get_as(value); } - int16_t GetInt16() const - { - return to_scalar(); - } + private: - uint16_t GetUInt16() const - { - return to_scalar(); - } + Derived const* derived() const noexcept { return static_cast(this); } - int32_t GetInt32() const + std::int32_t query_interface_tearoff(guid const& id, void** object) const noexcept override { - return to_scalar(); - } + if constexpr (is_stock_reference_v) + { + if (is_guid_of(id)) + { + try + { + auto marshal = derived()->create_property_value().template as(); + *object = detach_abi(marshal); + return error_ok; + } + catch (...) + { + *object = nullptr; + return to_hresult(); + } + } - uint32_t GetUInt32() const - { - return to_scalar(); + if (is_guid_of(id)) + { + auto unknown = reinterpret_cast(to_abi(derived())); + unknown->AddRef(); + *object = unknown; + return error_ok; + } + } + + *object = nullptr; + return error_no_interface; } + }; - int64_t GetInt64() const + template + struct reference : reference_producer, T, Windows::Foundation::IReference, false> + { + reference(T const& value) : m_value(value) { - return to_scalar(); } - uint64_t GetUInt64() const + T Value() const { - return to_scalar(); + return m_value; } - float GetSingle() { throw hresult_not_implemented(); } - double GetDouble() { throw hresult_not_implemented(); } - char16_t GetChar16() { throw hresult_not_implemented(); } - bool GetBoolean() { throw hresult_not_implemented(); } - hstring GetString() { throw hresult_not_implemented(); } - guid GetGuid() { throw hresult_not_implemented(); } - Windows::Foundation::DateTime GetDateTime() { throw hresult_not_implemented(); } - Windows::Foundation::TimeSpan GetTimeSpan() { throw hresult_not_implemented(); } - Windows::Foundation::Point GetPoint() { throw hresult_not_implemented(); } - Windows::Foundation::Size GetSize() { throw hresult_not_implemented(); } - Windows::Foundation::Rect GetRect() { throw hresult_not_implemented(); } - void GetUInt8Array(com_array &) { throw hresult_not_implemented(); } - void GetInt16Array(com_array &) { throw hresult_not_implemented(); } - void GetUInt16Array(com_array &) { throw hresult_not_implemented(); } - void GetInt32Array(com_array &) { throw hresult_not_implemented(); } - void GetUInt32Array(com_array &) { throw hresult_not_implemented(); } - void GetInt64Array(com_array &) { throw hresult_not_implemented(); } - void GetUInt64Array(com_array &) { throw hresult_not_implemented(); } - void GetSingleArray(com_array &) { throw hresult_not_implemented(); } - void GetDoubleArray(com_array &) { throw hresult_not_implemented(); } - void GetChar16Array(com_array &) { throw hresult_not_implemented(); } - void GetBooleanArray(com_array &) { throw hresult_not_implemented(); } - void GetStringArray(com_array &) { throw hresult_not_implemented(); } - void GetInspectableArray(com_array &) { throw hresult_not_implemented(); } - void GetGuidArray(com_array &) { throw hresult_not_implemented(); } - void GetDateTimeArray(com_array &) { throw hresult_not_implemented(); } - void GetTimeSpanArray(com_array &) { throw hresult_not_implemented(); } - void GetPointArray(com_array &) { throw hresult_not_implemented(); } - void GetSizeArray(com_array &) { throw hresult_not_implemented(); } - void GetRectArray(com_array &) { throw hresult_not_implemented(); } - private: + template friend struct reference_producer; + + Windows::Foundation::IInspectable create_property_value() const + { + using pv = Windows::Foundation::PropertyValue; + + if constexpr (std::is_same_v) { return pv::CreateUInt8(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateInt16(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateUInt16(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateInt32(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateUInt32(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateInt64(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateUInt64(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateSingle(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateDouble(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateChar16(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateBoolean(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateString(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateGuid(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateDateTime(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateTimeSpan(m_value); } + else if constexpr (std::is_same_v) { return pv::CreatePoint(m_value); } + else { return nullptr; } + } + template - To to_scalar() const + To get_as() const { - if constexpr (IsNumericScalar()) + if constexpr (std::is_same_v) + { + return m_value; + } + else if constexpr (is_numeric_scalar_v && is_numeric_scalar_v) { return static_cast(m_value); } @@ -104,98 +202,81 @@ namespace winrt::impl } } + template + void get_as(com_array const&) const + { + throw hresult_not_implemented(); + } + T m_value; }; template - struct reference_traits - { - static auto make(T const& value) { return winrt::make>(value); } - using itf = Windows::Foundation::IReference; - }; - - template <> - struct reference_traits - { - static auto make(uint8_t value) { return Windows::Foundation::PropertyValue::CreateUInt8(value); } - using itf = Windows::Foundation::IReference; - }; - - template <> - struct reference_traits - { - static auto make(uint16_t value) { return Windows::Foundation::PropertyValue::CreateUInt16(value); } - using itf = Windows::Foundation::IReference; - }; - - template <> - struct reference_traits + struct reference_array : reference_producer, T, Windows::Foundation::IReferenceArray, true> { - static auto make(int16_t value) { return Windows::Foundation::PropertyValue::CreateInt16(value); } - using itf = Windows::Foundation::IReference; - }; + reference_array(array_view const& value) : m_value(value.begin(), value.end()) + { + } - template <> - struct reference_traits - { - static auto make(uint32_t value) { return Windows::Foundation::PropertyValue::CreateUInt32(value); } - using itf = Windows::Foundation::IReference; - }; + com_array Value() const + { + return com_array(m_value.begin(), m_value.end()); + } - template <> - struct reference_traits - { - static auto make(int32_t value) { return Windows::Foundation::PropertyValue::CreateInt32(value); } - using itf = Windows::Foundation::IReference; - }; + private: - template <> - struct reference_traits - { - static auto make(uint64_t value) { return Windows::Foundation::PropertyValue::CreateUInt64(value); } - using itf = Windows::Foundation::IReference; - }; + template friend struct reference_producer; - template <> - struct reference_traits - { - static auto make(int64_t value) { return Windows::Foundation::PropertyValue::CreateInt64(value); } - using itf = Windows::Foundation::IReference; - }; - - template <> - struct reference_traits - { - static auto make(float value) { return Windows::Foundation::PropertyValue::CreateSingle(value); } - using itf = Windows::Foundation::IReference; - }; + Windows::Foundation::IInspectable create_property_value() const + { + using pv = Windows::Foundation::PropertyValue; + + if constexpr (std::is_same_v) { return pv::CreateUInt8Array(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateInt16Array(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateUInt16Array(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateInt32Array(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateUInt32Array(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateInt64Array(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateUInt64Array(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateSingleArray(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateDoubleArray(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateChar16Array(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateBooleanArray(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateStringArray(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateGuidArray(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateDateTimeArray(m_value); } + else if constexpr (std::is_same_v) { return pv::CreateTimeSpanArray(m_value); } + else if constexpr (std::is_same_v) { return pv::CreatePointArray(m_value); } + else { return nullptr; } + } - template <> - struct reference_traits - { - static auto make(double value) { return Windows::Foundation::PropertyValue::CreateDouble(value); } - using itf = Windows::Foundation::IReference; - }; + template + To get_as() const + { + throw hresult_not_implemented(); + } - template <> - struct reference_traits - { - static auto make(char16_t value) { return Windows::Foundation::PropertyValue::CreateChar16(value); } - using itf = Windows::Foundation::IReference; - }; + template + void get_as(com_array& value) const + { + if constexpr (std::is_same_v) + { + value = com_array(m_value.begin(), m_value.end()); + } + else + { + throw hresult_not_implemented(); + } + } - template <> - struct reference_traits - { - static auto make(bool value) { return Windows::Foundation::PropertyValue::CreateBoolean(value); } - using itf = Windows::Foundation::IReference; + com_array m_value; }; - template <> - struct reference_traits + template + struct reference_traits { - static auto make(hstring const& value) { return Windows::Foundation::PropertyValue::CreateString(value); } - using itf = Windows::Foundation::IReference; + static auto make(T const& value) { return winrt::make>(value); } + using itf = Windows::Foundation::IReference; }; template <> @@ -205,41 +286,13 @@ namespace winrt::impl using itf = Windows::Foundation::IInspectable; }; - template <> - struct reference_traits - { - static auto make(guid const& value) { return Windows::Foundation::PropertyValue::CreateGuid(value); } - using itf = Windows::Foundation::IReference; - }; - template <> struct reference_traits { - static auto make(GUID const& value) { return Windows::Foundation::PropertyValue::CreateGuid(reinterpret_cast(value)); } + static auto make(GUID const& value) { return reference_traits::make(reinterpret_cast(value)); } using itf = Windows::Foundation::IReference; }; - template <> - struct reference_traits - { - static auto make(Windows::Foundation::DateTime value) { return Windows::Foundation::PropertyValue::CreateDateTime(value); } - using itf = Windows::Foundation::IReference; - }; - - template <> - struct reference_traits - { - static auto make(Windows::Foundation::TimeSpan value) { return Windows::Foundation::PropertyValue::CreateTimeSpan(value); } - using itf = Windows::Foundation::IReference; - }; - - template <> - struct reference_traits - { - static auto make(Windows::Foundation::Point const& value) { return Windows::Foundation::PropertyValue::CreatePoint(value); } - using itf = Windows::Foundation::IReference; - }; - template <> struct reference_traits { @@ -255,79 +308,79 @@ namespace winrt::impl }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt8Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return winrt::make>(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt16Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return winrt::make>(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt16Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return winrt::make>(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt32Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return winrt::make>(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(com_array const& value) { return Windows::Foundation::PropertyValue::CreateUInt32Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(com_array const& value) { return winrt::make>(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateInt64Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return winrt::make>(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> - struct reference_traits> + struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateUInt64Array(value); } - using itf = Windows::Foundation::IReferenceArray; + static auto make(array_view const& value) { return winrt::make>(value); } + using itf = Windows::Foundation::IReferenceArray; }; template <> struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateSingleArray(value); } + static auto make(array_view const& value) { return winrt::make>(value); } using itf = Windows::Foundation::IReferenceArray; }; template <> struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateDoubleArray(value); } + static auto make(array_view const& value) { return winrt::make>(value); } using itf = Windows::Foundation::IReferenceArray; }; template <> struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateChar16Array(value); } + static auto make(array_view const& value) { return winrt::make>(value); } using itf = Windows::Foundation::IReferenceArray; }; template <> struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateBooleanArray(value); } + static auto make(array_view const& value) { return winrt::make>(value); } using itf = Windows::Foundation::IReferenceArray; }; @@ -348,14 +401,14 @@ namespace winrt::impl template <> struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateGuidArray(value); } + static auto make(array_view const& value) { return winrt::make>(value); } using itf = Windows::Foundation::IReferenceArray; }; template <> struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreateGuidArray(reinterpret_cast const&>(value)); } + static auto make(array_view const& value) { return winrt::make>(reinterpret_cast const&>(value)); } using itf = Windows::Foundation::IReferenceArray; }; @@ -376,7 +429,7 @@ namespace winrt::impl template <> struct reference_traits> { - static auto make(array_view const& value) { return Windows::Foundation::PropertyValue::CreatePointArray(value); } + static auto make(array_view const& value) { return winrt::make>(value); } using itf = Windows::Foundation::IReferenceArray; }; @@ -420,7 +473,7 @@ WINRT_EXPORT namespace winrt::Windows::Foundation } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template T unbox_value_type(From&& value) @@ -509,12 +562,13 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { - inline Windows::Foundation::IInspectable box_value(param::hstring const& value) + template , int> = 0> + Windows::Foundation::IInspectable box_value(T&& value) { - return Windows::Foundation::IReference(*(hstring*)(&value)); + return Windows::Foundation::IReference(hstring(std::forward(value))); } - template , int> = 0> + template , int> = 0> Windows::Foundation::IInspectable box_value(T const& value) { if constexpr (std::is_base_of_v) diff --git a/strings/base_security.h b/strings/base_security.h index 8160f11ad..a912487e4 100644 --- a/strings/base_security.h +++ b/strings/base_security.h @@ -18,7 +18,7 @@ WINRT_EXPORT namespace winrt if (!WINRT_IMPL_OpenThreadToken(WINRT_IMPL_GetCurrentThread(), 0x0004 /*TOKEN_IMPERSONATE*/, 1, token.put())) { - uint32_t const error = WINRT_IMPL_GetLastError(); + std::uint32_t const error = WINRT_IMPL_GetLastError(); if (error != 1008 /*ERROR_NO_TOKEN*/) { diff --git a/strings/base_source_location.h b/strings/base_source_location.h new file mode 100644 index 000000000..c0fd81f9f --- /dev/null +++ b/strings/base_source_location.h @@ -0,0 +1,97 @@ + +// The intrinsics (such as __builtin_FILE()) that power std::source_location are also used to power winrt:impl::slim_source_location. +// The source location needs to be for the calling code, not cppwinrt itself, so that it is useful to developers building on top of +// this library. As a result any public-facing method that can result in an error needs a default-constructed slim_source_location +// argument so that it will collect source information from the application code that is calling into cppwinrt. +// +// We do not directly use std::source_location for two reasons: +// 1) std::source_location::function_name() is unavoidable. These strings end up in the final binary, bloating their size. This +// is particularly impactful for code bases that use templates heavily. Cases of 50% binary size growth have been observed. +// 2) std::source_location is a cpp20 feature, which is above the cpp17 feature floor for cppwinrt. By defining our own version +// we can avoid ODR violations in mixed cpp17/cpp20 builds. cpp17 callers will have an ABI that matches cpp20 callers (they +// will just not have useful file/line/function information). +// +// Some projects may decide that the source information binary size impact is not worth the benefit. Defining WINRT_NO_SOURCE_LOCATION +// will prevent this feature from activating. The slim_source_location type will be forwarded around but it will not include any +// nonzero data. That eliminates the biggest source of binary size overhead. +// +// To help with debugging the __builtin_FUNCTION() intrinsic will be used in _DEBUG builds. This will provide a bit more diagnostic +// value at the cost of binary size. The assumption is that binary size is considered less important in debug builds so this tradeoff +// is acceptable. +// +// The different behavior of the default parameters to winrt::impl::slim_source_location::current() is technically an ODR violation, +// albeit a minor one. There should be no serious consequence to this violation. In practice it means that mixing cpp17/cpp20, +// or mixing WINRT_NO_SOURCE_LOCATION with undefining it, will lead to inconsistent source location information. It may be missing +// when it is expected to be included, or it may be present when it is not expected. The behavior will depend on the linker's choice +// when there are multiple translation units with different options. This violation is tracked by https://github.com/microsoft/cppwinrt/issues/1445. + +#if !defined(__cpp_lib_source_location) || defined(WINRT_NO_SOURCE_LOCATION) +// Case1: cpp17 mode. The source_location intrinsics are not available. +// Case2: The caller has disabled source_location support. Ensure that there is no binary size overhead for line/file/function. +#define WINRT_IMPL_BUILTIN_LINE 0 +#define WINRT_IMPL_BUILTIN_FILE nullptr +#define WINRT_IMPL_BUILTIN_FUNCTION nullptr +#elif _DEBUG +// cpp20 _DEBUG builds include function information, which has a heavy binary size impact, in addition to file/line. +#define WINRT_IMPL_BUILTIN_LINE __builtin_LINE() +#define WINRT_IMPL_BUILTIN_FILE __builtin_FILE() +#define WINRT_IMPL_BUILTIN_FUNCTION __builtin_FUNCTION() +#else +// Release builds in cpp20 mode get file and line information but NOT function information. Function strings +// quickly add up to a substantial binary size impact, especially when templates are heavily used. +#define WINRT_IMPL_BUILTIN_LINE __builtin_LINE() +#define WINRT_IMPL_BUILTIN_FILE __builtin_FILE() +#define WINRT_IMPL_BUILTIN_FUNCTION nullptr +#endif + +WINRT_EXPORT namespace winrt::impl +{ + // This struct is intended to be highly similar to std::source_location. The key difference is + // that function_name is NOT included. Function names do not fold to identical strings and can + // have heavy binary size overhead when templates cause many permutations to exist. + struct slim_source_location + { + [[nodiscard]] static WINRT_IMPL_CONSTEVAL slim_source_location current( + const std::uint_least32_t line = WINRT_IMPL_BUILTIN_LINE, + const char* const file = WINRT_IMPL_BUILTIN_FILE, + const char* const function = WINRT_IMPL_BUILTIN_FUNCTION) noexcept + { + return slim_source_location{ line, file, function }; + } + + [[nodiscard]] constexpr slim_source_location() noexcept = default; + + [[nodiscard]] constexpr slim_source_location( + const std::uint_least32_t line, + const char* const file, + const char* const function) noexcept : + m_line(line), + m_file(file), + m_function(function) + {} + + [[nodiscard]] constexpr std::uint_least32_t line() const noexcept + { + return m_line; + } + + [[nodiscard]] constexpr const char* file_name() const noexcept + { + return m_file; + } + + [[nodiscard]] constexpr const char* function_name() const noexcept + { + return m_function; + } + + private: + const std::uint_least32_t m_line{}; + const char* const m_file{}; + const char* const m_function{}; + }; +} + +#ifdef _MSC_VER +#pragma detect_mismatch("WINRT_SOURCE_LOCATION", "slim") +#endif // _MSC_VER diff --git a/strings/base_std_hash.h b/strings/base_std_hash.h index eb97db0e9..4777f8082 100644 --- a/strings/base_std_hash.h +++ b/strings/base_std_hash.h @@ -1,19 +1,19 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { - inline size_t hash_data(void const* ptr, size_t const bytes) noexcept + inline std::size_t hash_data(void const* ptr, std::size_t const bytes) noexcept { #ifdef _WIN64 - constexpr size_t fnv_offset_basis = 14695981039346656037ULL; - constexpr size_t fnv_prime = 1099511628211ULL; + constexpr std::size_t fnv_offset_basis = 14695981039346656037ULL; + constexpr std::size_t fnv_prime = 1099511628211ULL; #else - constexpr size_t fnv_offset_basis = 2166136261U; - constexpr size_t fnv_prime = 16777619U; + constexpr std::size_t fnv_offset_basis = 2166136261U; + constexpr std::size_t fnv_prime = 16777619U; #endif - size_t result = fnv_offset_basis; - uint8_t const* const buffer = static_cast(ptr); + std::size_t result = fnv_offset_basis; + std::uint8_t const* const buffer = static_cast(ptr); - for (size_t next = 0; next < bytes; ++next) + for (std::size_t next = 0; next < bytes; ++next) { result ^= buffer[next]; result *= fnv_prime; @@ -24,7 +24,7 @@ namespace winrt::impl struct hash_base { - size_t operator()(Windows::Foundation::IUnknown const& value) const noexcept + std::size_t operator()(Windows::Foundation::IUnknown const& value) const noexcept { void* const abi_value = get_abi(value.try_as()); return std::hash{}(abi_value); @@ -32,11 +32,11 @@ namespace winrt::impl }; } -namespace std +WINRT_IMPL_STD_EXPORT namespace std { template<> struct hash { - size_t operator()(winrt::hstring const& value) const noexcept + std::size_t operator()(winrt::hstring const& value) const noexcept { return std::hash{}(value); } @@ -48,7 +48,7 @@ namespace std template<> struct hash { - size_t operator()(winrt::guid const& value) const noexcept + std::size_t operator()(winrt::guid const& value) const noexcept { return winrt::impl::hash_data(&value, sizeof(value)); } diff --git a/strings/base_string.h b/strings/base_string.h index 244f81e99..50a248c02 100644 --- a/strings/base_string.h +++ b/strings/base_string.h @@ -1,25 +1,25 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { struct atomic_ref_count { atomic_ref_count() noexcept = default; - explicit atomic_ref_count(uint32_t count) noexcept : m_count(count) + explicit atomic_ref_count(std::uint32_t count) noexcept : m_count(count) { } - uint32_t operator=(uint32_t count) noexcept + std::uint32_t operator=(std::uint32_t count) noexcept { return m_count = count; } - uint32_t operator++() noexcept + std::uint32_t operator++() noexcept { - return m_count.fetch_add(1, std::memory_order_relaxed) + 1; + return static_cast(m_count.fetch_add(1, std::memory_order_relaxed) + 1); } - uint32_t operator--() noexcept + std::uint32_t operator--() noexcept { auto const remaining = m_count.fetch_sub(1, std::memory_order_release) - 1; @@ -29,30 +29,30 @@ namespace winrt::impl } else if (remaining < 0) { - abort(); + std::abort(); } - return remaining; + return static_cast(remaining); } - operator uint32_t() const noexcept + operator std::uint32_t() const noexcept { - return m_count; + return static_cast(m_count); } private: - std::atomic m_count; + std::atomic m_count; }; - constexpr uint32_t hstring_reference_flag{ 1 }; + inline constexpr std::uint32_t hstring_reference_flag{ 1 }; struct hstring_header { - uint32_t flags; - uint32_t length; - uint32_t padding1; - uint32_t padding2; + std::uint32_t flags; + std::uint32_t length; + std::uint32_t padding1; + std::uint32_t padding2; wchar_t const* ptr; }; @@ -72,12 +72,12 @@ namespace winrt::impl } } - inline shared_hstring_header* precreate_hstring_on_heap(uint32_t length) + inline shared_hstring_header* precreate_hstring_on_heap(std::uint32_t length) { WINRT_ASSERT(length != 0); - uint64_t bytes_required = static_cast(sizeof(shared_hstring_header)) + static_cast(sizeof(wchar_t)) * static_cast(length); + std::uint64_t bytes_required = static_cast(sizeof(shared_hstring_header)) + static_cast(sizeof(wchar_t)) * static_cast(length); - if (bytes_required > UINT_MAX) + if (bytes_required > (std::numeric_limits::max)()) { throw std::invalid_argument("length"); } @@ -97,7 +97,7 @@ namespace winrt::impl return header; } - inline hstring_header* create_hstring_on_heap(wchar_t const* value, uint32_t length) + inline hstring_header* create_hstring_on_heap(wchar_t const* value, std::uint32_t length) { if (!length) { @@ -105,18 +105,18 @@ namespace winrt::impl } auto header = precreate_hstring_on_heap(length); - memcpy_s(header->buffer, sizeof(wchar_t) * length, value, sizeof(wchar_t) * length); + std::copy_n(value, length, header->buffer); return header; } - inline void create_hstring_on_stack(hstring_header& header, wchar_t const* value, uint32_t length) noexcept + inline void create_hstring_on_stack(hstring_header& header, wchar_t const* value, std::uint32_t length) noexcept { WINRT_ASSERT(value); WINRT_ASSERT(length != 0); if (value[length] != 0) { - abort(); + std::abort(); } header.flags = hstring_reference_flag; @@ -155,6 +155,24 @@ namespace winrt::impl return nullptr; } }; + + template + struct hstring_literal_storage + { + static constexpr std::size_t size = N; + wchar_t value[N]; + + constexpr hstring_literal_storage(wchar_t const (&str)[N]) noexcept + { + for (std::size_t i = 0; i != N; ++i) + { + value[i] = str[i]; + } + } + }; + + template + hstring_literal_storage(wchar_t const (&)[N]) -> hstring_literal_storage; } WINRT_EXPORT namespace winrt @@ -162,7 +180,7 @@ WINRT_EXPORT namespace winrt struct hstring { using value_type = wchar_t; - using size_type = uint32_t; + using size_type = std::uint32_t; using const_reference = value_type const&; using pointer = value_type*; using const_pointer = value_type const*; @@ -191,7 +209,7 @@ WINRT_EXPORT namespace winrt hstring& operator=(std::nullptr_t) = delete; hstring(std::initializer_list value) : - hstring(value.begin(), static_cast(value.size())) + hstring(value.begin(), static_cast(value.size())) {} hstring(wchar_t const* value) : @@ -386,6 +404,30 @@ WINRT_EXPORT namespace winrt handle_type m_handle; }; + struct hstring_reference + { + constexpr hstring_reference() noexcept = default; + + constexpr explicit hstring_reference(impl::hstring_header const* header) noexcept : + m_handle(const_cast(header)) + { + } + + operator hstring const&() const noexcept + { + return *reinterpret_cast(this); + } + + private: + + [[maybe_unused]] void* m_handle{}; + }; + + inline void* get_abi(hstring_reference const& object) noexcept + { + return *(void**)(&object); + } + inline void* get_abi(hstring const& object) noexcept { return *(void**)(&object); @@ -428,21 +470,59 @@ WINRT_EXPORT namespace winrt inline void* detach_abi(std::wstring_view const& value) { - return impl::create_hstring_on_heap(value.data(), static_cast(value.size())); + return impl::create_hstring_on_heap(value.data(), static_cast(value.size())); } inline void* detach_abi(wchar_t const* const value) { - return impl::create_hstring_on_heap(value, static_cast(wcslen(value))); + return impl::create_hstring_on_heap(value, static_cast(std::wcslen(value))); } } +#if defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911L + +WINRT_EXPORT namespace winrt::impl +{ + template + inline constexpr hstring_header hstring_literal_header + { + hstring_reference_flag, + static_cast(Literal.size - 1), + 0, + 0, + Literal.value + }; +} + +WINRT_EXPORT namespace winrt +{ + inline namespace literals + { + template + constexpr hstring_reference operator ""_hs() noexcept + { + static_assert(Literal.value[Literal.size - 1] == L'\0', "_hs requires a null-terminated wide string literal"); + + if constexpr (Literal.size <= 1) + { + return hstring_reference{}; + } + else + { + return hstring_reference{ &impl::hstring_literal_header }; + } + } + } +} + +#endif + #ifdef __cpp_lib_format template<> struct std::formatter : std::formatter {}; #endif -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template <> struct abi { @@ -459,7 +539,7 @@ namespace winrt::impl hstring_builder(hstring_builder const&) = delete; hstring_builder& operator=(hstring_builder const&) = delete; - explicit hstring_builder(uint32_t const size) : + explicit hstring_builder(std::uint32_t const size) : m_handle(impl::precreate_hstring_on_heap(size)) { } @@ -488,11 +568,23 @@ namespace winrt::impl T const& object; +#if !defined(__GNUC__) || defined(__clang__) template operator R const& () const noexcept { return reinterpret_cast(object); } +#else + // HACK: GCC does not handle template deduction of const T& conversion + // function according to CWG issue 976. To make this compile on GCC, + // we have to intentionally drop the const qualifier. + // Ref: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61663 + template + operator R& () const noexcept + { + return const_cast(reinterpret_cast(object)); + } +#endif }; template @@ -550,10 +642,44 @@ namespace winrt::impl auto end = std::copy(std::begin(temp), result.ptr, buffer); return hstring{ std::wstring_view{ buffer, static_cast(end - buffer)} }; } + +#if __cpp_lib_format >= 202207L + template + inline hstring base_format(Args&&... args) + { + // don't forward because an object could be moved-from, causing issues + // for the second format call. + // not forwarding lets us take both rvalues and lvalues but pass them + // further down as an lvalue ref. some types can only be formatted + // when non-const (e.g. ranges::filter_view) so taking a const reference + // as parameter wouldn't work for all scenarios. + auto const size = std::formatted_size(args...); + WINRT_ASSERT(size < static_cast((std::numeric_limits::max)())); + auto const size32 = static_cast(size); + + hstring_builder builder(size32); + WINRT_VERIFY_(size32, std::format_to_n(builder.data(), size32, args...).size); + return builder.to_hstring(); + } +#endif } WINRT_EXPORT namespace winrt { +#if __cpp_lib_format >= 202207L + template + inline hstring format(std::wformat_string const fmt, Args&&... args) + { + return impl::base_format(fmt, args...); + } + + template + inline hstring format(std::locale const& loc, std::wformat_string const fmt, Args&&... args) + { + return impl::base_format(loc, fmt, args...); + } +#endif + inline bool embedded_null(hstring const& value) noexcept { return std::any_of(value.begin(), value.end(), [](auto item) @@ -562,46 +688,47 @@ WINRT_EXPORT namespace winrt }); } - inline hstring to_hstring(uint8_t value) + inline hstring to_hstring(std::uint8_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(int8_t value) + inline hstring to_hstring(std::int8_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(uint16_t value) + inline hstring to_hstring(std::uint16_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(int16_t value) + inline hstring to_hstring(std::int16_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(uint32_t value) + inline hstring to_hstring(std::uint32_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(int32_t value) + inline hstring to_hstring(std::int32_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(uint64_t value) + inline hstring to_hstring(std::uint64_t value) { return impl::hstring_convert(value); } - inline hstring to_hstring(int64_t value) + inline hstring to_hstring(std::int64_t value) { return impl::hstring_convert(value); } +#if !defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 14000 inline hstring to_hstring(float value) { return impl::hstring_convert(value); @@ -611,6 +738,7 @@ WINRT_EXPORT namespace winrt { return impl::hstring_convert(value); } +#endif inline hstring to_hstring(char16_t value) { @@ -640,7 +768,7 @@ WINRT_EXPORT namespace winrt { wchar_t buffer[40]; //{00000000-0000-0000-0000-000000000000} - swprintf_s(buffer, L"{%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}", + std::swprintf(buffer, std::size(buffer), L"{%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx}", value.Data1, value.Data2, value.Data3, value.Data4[0], value.Data4[1], value.Data4[2], value.Data4[3], value.Data4[4], value.Data4[5], value.Data4[6], value.Data4[7]); return hstring{ buffer }; @@ -650,7 +778,7 @@ WINRT_EXPORT namespace winrt hstring to_hstring(T const& value) { std::string_view const view(value); - int const size = WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), nullptr, 0); + int const size = WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), nullptr, 0); if (size == 0) { @@ -658,13 +786,13 @@ WINRT_EXPORT namespace winrt } impl::hstring_builder result(size); - WINRT_VERIFY_(size, WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), result.data(), size)); + WINRT_VERIFY_(size, WINRT_IMPL_MultiByteToWideChar(65001 /*CP_UTF8*/, 0, view.data(), static_cast(view.size()), result.data(), size)); return result.to_hstring(); } inline std::string to_string(std::wstring_view value) { - int const size = WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), nullptr, 0, nullptr, nullptr); + int const size = WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), nullptr, 0, nullptr, nullptr); if (size == 0) { @@ -672,7 +800,7 @@ WINRT_EXPORT namespace winrt } std::string result(size, '?'); - WINRT_VERIFY_(size, WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), result.data(), size, nullptr, nullptr)); + WINRT_VERIFY_(size, WINRT_IMPL_WideCharToMultiByte(65001 /*CP_UTF8*/, 0, value.data(), static_cast(value.size()), result.data(), size, nullptr, nullptr)); return result; } } diff --git a/strings/base_string_input.h b/strings/base_string_input.h index 786b31519..ccf955547 100644 --- a/strings/base_string_input.h +++ b/strings/base_string_input.h @@ -3,17 +3,25 @@ WINRT_EXPORT namespace winrt::param { struct hstring { +#ifdef _MSC_VER #pragma warning(suppress: 26495) +#endif hstring() noexcept : m_handle(nullptr) {} hstring(hstring const& values) = delete; hstring& operator=(hstring const& values) = delete; hstring(std::nullptr_t) = delete; +#ifdef _MSC_VER #pragma warning(suppress: 26495) +#endif hstring(winrt::hstring const& value) noexcept : m_handle(get_abi(value)) { } + hstring(winrt::hstring_reference const& value) noexcept : m_handle(get_abi(value)) + { + } + hstring(std::wstring_view const& value) noexcept { create_string_reference(value.data(), value.size()); @@ -26,7 +34,7 @@ WINRT_EXPORT namespace winrt::param hstring(wchar_t const* const value) noexcept { - create_string_reference(value, wcslen(value)); + create_string_reference(value, std::wcslen(value)); } operator winrt::hstring const&() const noexcept @@ -35,10 +43,10 @@ WINRT_EXPORT namespace winrt::param } private: - void create_string_reference(wchar_t const* const data, size_t size) noexcept + void create_string_reference(wchar_t const* const data, std::size_t size) noexcept { - WINRT_ASSERT(size < UINT_MAX); - auto size32 = static_cast(size); + WINRT_ASSERT(size < (std::numeric_limits::max)()); + auto size32 = static_cast(size); if (size32 == 0) { @@ -61,7 +69,7 @@ WINRT_EXPORT namespace winrt::param } } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template using param_type = std::conditional_t, param::hstring, T>; diff --git a/strings/base_string_operators.h b/strings/base_string_operators.h index 215186b04..223769d01 100644 --- a/strings/base_string_operators.h +++ b/strings/base_string_operators.h @@ -55,9 +55,9 @@ WINRT_EXPORT namespace winrt return left < std::wstring_view(right); } - bool operator<(hstring const& left, nullptr_t) = delete; + bool operator<(hstring const& left, std::nullptr_t) = delete; - bool operator<(nullptr_t, hstring const& right) = delete; + bool operator<(std::nullptr_t, hstring const& right) = delete; inline bool operator!=(hstring const& left, hstring const& right) noexcept { return !(left == right); } inline bool operator>(hstring const& left, hstring const& right) noexcept { return right < left; } inline bool operator<=(hstring const& left, hstring const& right) noexcept { return !(right < left); } @@ -94,18 +94,18 @@ WINRT_EXPORT namespace winrt bool operator>=(std::nullptr_t left, hstring const& right) = delete; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { inline hstring concat_hstring(std::wstring_view const& left, std::wstring_view const& right) { - auto size = static_cast(left.size() + right.size()); + auto size = static_cast(left.size() + right.size()); if (size == 0) { return{}; } hstring_builder text(size); - memcpy_s(text.data(), left.size() * sizeof(wchar_t), left.data(), left.size() * sizeof(wchar_t)); - memcpy_s(text.data() + left.size(), right.size() * sizeof(wchar_t), right.data(), right.size() * sizeof(wchar_t)); + std::copy_n(left.data(), left.size(), text.data()); + std::copy_n(right.data(), right.size(), text.data() + left.size()); return text.to_hstring(); } } @@ -160,4 +160,12 @@ WINRT_EXPORT namespace winrt { return impl::concat_hstring(left, right); } + +#ifndef WINRT_LEAN_AND_MEAN + inline std::wostream& operator<<(std::wostream& stream, hstring const& string) + { + stream << static_cast(string); + return stream; + } +#endif } diff --git a/strings/base_stringable_format.h b/strings/base_stringable_format.h index 86c5acfc6..e8f51c3f2 100644 --- a/strings/base_stringable_format.h +++ b/strings/base_stringable_format.h @@ -1,7 +1,7 @@ #ifdef __cpp_lib_format template -auto std::formatter::format(winrt::Windows::Foundation::IStringable const& obj, FormatContext& fc) +auto std::formatter::format(winrt::Windows::Foundation::IStringable const& obj, FormatContext& fc) const { return std::formatter::format(obj.ToString(), fc); } diff --git a/strings/base_stringable_format_1.h b/strings/base_stringable_format_1.h index 6a7becdfc..82e6afa38 100644 --- a/strings/base_stringable_format_1.h +++ b/strings/base_stringable_format_1.h @@ -4,6 +4,6 @@ template <> struct std::formatter : std::formatter { template - auto format(winrt::Windows::Foundation::IStringable const& obj, FormatContext& fc); + auto format(winrt::Windows::Foundation::IStringable const& obj, FormatContext& fc) const; }; #endif diff --git a/strings/base_stringable_streams.h b/strings/base_stringable_streams.h new file mode 100644 index 000000000..fa17b0f3e --- /dev/null +++ b/strings/base_stringable_streams.h @@ -0,0 +1,11 @@ + +#ifndef WINRT_LEAN_AND_MEAN +namespace winrt::Windows::Foundation +{ + inline std::wostream& operator<<(std::wostream& stream, winrt::Windows::Foundation::IStringable const& stringable) + { + stream << stringable.ToString(); + return stream; + } +} +#endif diff --git a/strings/base_stringable_to_hstring.h b/strings/base_stringable_to_hstring.h new file mode 100644 index 000000000..f92da965b --- /dev/null +++ b/strings/base_stringable_to_hstring.h @@ -0,0 +1,8 @@ + +WINRT_EXPORT namespace winrt +{ + inline hstring to_hstring(Windows::Foundation::IStringable const& stringable) + { + return stringable.ToString(); + } +} diff --git a/strings/base_types.h b/strings/base_types.h index afff3db35..dc2b13632 100644 --- a/strings/base_types.h +++ b/strings/base_types.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { using ptp_io = struct tp_io*; using ptp_timer = struct tp_timer*; @@ -14,25 +14,25 @@ namespace winrt::impl struct com_callback_args { - uint32_t reserved1; - uint32_t reserved2; + std::uint32_t reserved1; + std::uint32_t reserved2; void* data; }; template - constexpr uint8_t hex_to_uint(T const c) + constexpr std::uint8_t hex_to_uint(T const c) { if (c >= '0' && c <= '9') { - return static_cast(c - '0'); + return static_cast(c - '0'); } else if (c >= 'A' && c <= 'F') { - return static_cast(10 + c - 'A'); + return static_cast(10 + c - 'A'); } else if (c >= 'a' && c <= 'f') { - return static_cast(10 + c - 'a'); + return static_cast(10 + c - 'a'); } else { @@ -41,20 +41,20 @@ namespace winrt::impl } template - constexpr uint8_t hex_to_uint8(T const a, T const b) + constexpr std::uint8_t hex_to_uint8(T const a, T const b) { return (hex_to_uint(a) << 4) | hex_to_uint(b); } - constexpr uint16_t uint8_to_uint16(uint8_t a, uint8_t b) + constexpr std::uint16_t uint8_to_uint16(std::uint8_t a, std::uint8_t b) { - return (static_cast(a) << 8) | static_cast(b); + return (static_cast(a) << 8) | static_cast(b); } - constexpr uint32_t uint8_to_uint32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) + constexpr std::uint32_t uint8_to_uint32(std::uint8_t a, std::uint8_t b, std::uint8_t c, std::uint8_t d) { - return (static_cast(uint8_to_uint16(a, b)) << 16) | - static_cast(uint8_to_uint16(c, d)); + return (static_cast(uint8_to_uint16(a, b)) << 16) | + static_cast(uint8_to_uint16(c, d)); } } @@ -66,15 +66,15 @@ WINRT_EXPORT namespace winrt struct hresult { - int32_t value{}; + std::int32_t value{}; constexpr hresult() noexcept = default; - constexpr hresult(int32_t const value) noexcept : value(value) + constexpr hresult(std::int32_t const value) noexcept : value(value) { } - constexpr operator int32_t() const noexcept + constexpr operator std::int32_t() const noexcept { return value; } @@ -85,8 +85,15 @@ WINRT_EXPORT namespace winrt private: template - static constexpr guid parse(TStringView const value) + static constexpr guid parse(TStringView value) { + // Handle {} and () + if (value.size() == 38 && ((value[0] == '{' && value[37] == '}') || (value[0] == '(' && value[37] == ')'))) + { + value.remove_prefix(1); + value.remove_suffix(1); + } + if (value.size() != 36 || value[8] != '-' || value[13] != '-' || value[18] != '-' || value[23] != '-') { throw std::invalid_argument("value is not a valid GUID string"); @@ -126,14 +133,14 @@ WINRT_EXPORT namespace winrt public: - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; + std::uint32_t Data1; + std::uint16_t Data2; + std::uint16_t Data3; + std::uint8_t Data4[8]; guid() noexcept = default; - constexpr guid(uint32_t const Data1, uint16_t const Data2, uint16_t const Data3, std::array const& Data4) noexcept : + constexpr guid(std::uint32_t const Data1, std::uint16_t const Data2, std::uint16_t const Data3, std::array const& Data4) noexcept : Data1(Data1), Data2(Data2), Data3(Data3), @@ -171,7 +178,7 @@ WINRT_EXPORT namespace winrt inline bool operator==(guid const& left, guid const& right) noexcept { - return !memcmp(&left, &right, sizeof(left)); + return !std::memcmp(&left, &right, sizeof(left)); } inline bool operator!=(guid const& left, guid const& right) noexcept @@ -181,13 +188,13 @@ WINRT_EXPORT namespace winrt inline bool operator<(guid const& left, guid const& right) noexcept { - return memcmp(&left, &right, sizeof(left)) < 0; + return std::memcmp(&left, &right, sizeof(left)) < 0; } } WINRT_EXPORT namespace winrt::Windows::Foundation { - enum class TrustLevel : int32_t + enum class TrustLevel : std::int32_t { BaseTrust, PartialTrust, @@ -197,19 +204,19 @@ WINRT_EXPORT namespace winrt::Windows::Foundation struct IUnknown; struct IInspectable; struct IActivationFactory; - using TimeSpan = std::chrono::duration; + using TimeSpan = std::chrono::duration; using DateTime = std::chrono::time_point; } -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { #ifdef WINRT_IMPL_IUNKNOWN_DEFINED using hresult_type = long; using count_type = unsigned long; using guid_type = GUID; #else - using hresult_type = int32_t; - using count_type = uint32_t; + using hresult_type = std::int32_t; + using count_type = std::uint32_t; using guid_type = guid; #endif diff --git a/strings/base_version.h b/strings/base_version.h index 227f10402..13d21fb2a 100644 --- a/strings/base_version.h +++ b/strings/base_version.h @@ -4,19 +4,21 @@ extern "C" __declspec(selectany) char const * const WINRT_version = "C++/WinRT version:" CPPWINRT_VERSION; +#if defined(_MSC_VER) #ifdef _M_IX86 #pragma comment(linker, "/include:_WINRT_version") #else #pragma comment(linker, "/include:WINRT_version") #endif -#if defined(_MSC_VER) #pragma detect_mismatch("C++/WinRT version", CPPWINRT_VERSION) #endif WINRT_EXPORT namespace winrt { - template + inline constexpr char cppwinrt_version[] = CPPWINRT_VERSION; + + template constexpr bool check_version(char const(&base)[BaseSize], char const(&component)[ComponentSize]) noexcept { if constexpr (BaseSize != ComponentSize) @@ -24,7 +26,7 @@ WINRT_EXPORT namespace winrt return false; } - for (size_t i = 0; i != BaseSize - 1; ++i) + for (std::size_t i = 0; i != BaseSize - 1; ++i) { if (base[i] != component[i]) { diff --git a/strings/base_weak_ref.h b/strings/base_weak_ref.h index c98eb93a7..bc480ec2d 100644 --- a/strings/base_weak_ref.h +++ b/strings/base_weak_ref.h @@ -23,8 +23,11 @@ WINRT_EXPORT namespace winrt { impl::com_ref> temp; m_ref->Resolve(guid_of(), put_abi(temp)); - void* result = get_self(temp); - detach_abi(temp); + void* result = nullptr; + if (temp) { + result = get_self(temp); + detach_abi(temp); + } return impl::com_ref{ result, take_ownership_from_abi }; } else diff --git a/strings/base_windows.h b/strings/base_windows.h index 41030d368..dcd164574 100644 --- a/strings/base_windows.h +++ b/strings/base_windows.h @@ -1,17 +1,17 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { #ifdef WINRT_DIAGNOSTICS struct factory_diagnostics_info { bool is_agile{ true }; - uint32_t requests{ 0 }; + std::uint32_t requests{ 0 }; }; struct diagnostics_info { - std::map queries; + std::map queries; std::map factories; }; @@ -131,6 +131,30 @@ namespace winrt::impl ptr->QueryInterface(guid_of(), &result); return wrap_as_result(result); } + + template , int> = 0> + com_ref try_as_with_reason(From* ptr, hresult& code) noexcept + { +#ifdef WINRT_DIAGNOSTICS + get_diagnostics_info().add_query(); +#endif + + if (!ptr) + { + code = 0; + return nullptr; + } + + void* result{}; + code = ptr->QueryInterface(guid_of(), &result); + return wrap_as_result(result); + } + + template + auto try_as_with_reason(From ptr, hresult& code) noexcept + { + return ptr->template try_as_with_reason(code); + } } WINRT_EXPORT namespace winrt::Windows::Foundation @@ -139,7 +163,7 @@ WINRT_EXPORT namespace winrt::Windows::Foundation { IUnknown() noexcept = default; IUnknown(std::nullptr_t) noexcept {} - void* operator new(size_t) = delete; + void* operator new(std::size_t) = delete; IUnknown(void* ptr, take_ownership_from_abi_t) noexcept : m_ptr(static_cast(ptr)) { @@ -205,6 +229,12 @@ WINRT_EXPORT namespace winrt::Windows::Foundation return impl::try_as(m_ptr); } + template + auto try_as_with_reason(hresult& code) const noexcept + { + return impl::try_as_with_reason(m_ptr, code); + } + template void as(To& to) const { @@ -421,3 +451,60 @@ WINRT_EXPORT namespace winrt::Windows::Foundation IInspectable(void* ptr, take_ownership_from_abi_t) noexcept : IUnknown(ptr, take_ownership_from_abi) {} }; } + +WINRT_EXPORT namespace winrt::impl +{ + template + void consume_noexcept_remove_overload(Derive const* d, MemberPointer mptr, Args&&... args) noexcept + { + if constexpr (!std::is_same_v) + { + winrt::hresult _winrt_cast_result_code; + auto const _winrt_casted_result = try_as_with_reason(d, _winrt_cast_result_code); + check_hresult(_winrt_cast_result_code); + auto const _winrt_abi_type = *(abi_t**)&_winrt_casted_result; + (_winrt_abi_type->*mptr)(std::forward(args)...); + } + else + { + auto const _winrt_abi_type = *(abi_t**)d; + (_winrt_abi_type->*mptr)(std::forward(args)...); + } + } + + template + void consume_noexcept(Derive const* d, MemberPointer mptr, Args&&... args) noexcept + { + if constexpr (!std::is_same_v) + { + winrt::hresult _winrt_cast_result_code; + auto const _winrt_casted_result = try_as_with_reason(d, _winrt_cast_result_code); + check_hresult(_winrt_cast_result_code); + auto const _winrt_abi_type = *(abi_t**)&_winrt_casted_result; + WINRT_VERIFY_(0, (_winrt_abi_type->*mptr)(std::forward(args)...)); + } + else + { + auto const _winrt_abi_type = *(abi_t**)d; + WINRT_VERIFY_(0, (_winrt_abi_type->*mptr)(std::forward(args)...)); + } + } + + template + void consume_general(Derive const* d, MemberPointer mptr, Args&&... args) + { + if constexpr (!std::is_same_v) + { + winrt::hresult _winrt_cast_result_code; + auto const _winrt_casted_result = try_as_with_reason(d, _winrt_cast_result_code); + check_hresult(_winrt_cast_result_code); + auto const _winrt_abi_type = *(abi_t**)&_winrt_casted_result; + check_hresult((_winrt_abi_type->*mptr)(std::forward(args)...)); + } + else + { + auto const _winrt_abi_type = *(abi_t**)d; + check_hresult((_winrt_abi_type->*mptr)(std::forward(args)...)); + } + } +} diff --git a/strings/base_xaml_component_connector.h b/strings/base_xaml_component_connector.h new file mode 100644 index 000000000..092944613 --- /dev/null +++ b/strings/base_xaml_component_connector.h @@ -0,0 +1,53 @@ + +WINRT_EXPORT namespace winrt::Windows::UI::Xaml::Markup +{ + template + struct ComponentConnectorT : D + { + using composable_base = typename D::composable_base; + + void InitializeComponent() + { + if constexpr (m_has_connectable_base) + { + m_dispatch_base = true; + composable_base::InitializeComponent(); + m_dispatch_base = false; + } + D::InitializeComponent(); + } + + void Connect(std::int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) + { + if constexpr (m_has_connectable_base) + { + if (m_dispatch_base) + { + composable_base::Connect(connectionId, target); + return; + } + } + D::Connect(connectionId, target); + } + + auto GetBindingConnector(std::int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) + { + if constexpr (m_has_connectable_base) + { + if (m_dispatch_base) + { + return composable_base::GetBindingConnector(connectionId, target); + } + } + return D::GetBindingConnector(connectionId, target); + } + + private: + static constexpr bool m_has_connectable_base{ + impl::has_initializer::value && + impl::has_interface() && + impl::has_interface() }; + + bool m_dispatch_base{}; + }; +} diff --git a/strings/base_xaml_component_connector_winui.h b/strings/base_xaml_component_connector_winui.h new file mode 100644 index 000000000..312f5af29 --- /dev/null +++ b/strings/base_xaml_component_connector_winui.h @@ -0,0 +1,52 @@ + +WINRT_EXPORT namespace winrt::Microsoft::UI::Xaml::Markup +{ + template + struct ComponentConnectorT : D + { + using composable_base = typename D::composable_base; + + void InitializeComponent() + { + if constexpr (m_has_connectable_base) + { + m_dispatch_base = true; + composable_base::InitializeComponent(); + m_dispatch_base = false; + } + D::InitializeComponent(); + } + + void Connect(std::int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) + { + if constexpr (m_has_connectable_base) + { + if (m_dispatch_base) + { + composable_base::Connect(connectionId, target); + return; + } + } + D::Connect(connectionId, target); + } + + auto GetBindingConnector(std::int32_t connectionId, winrt::Windows::Foundation::IInspectable const& target) + { + if constexpr (m_has_connectable_base) + { + if (m_dispatch_base) + { + return composable_base::GetBindingConnector(connectionId, target); + } + } + return D::GetBindingConnector(connectionId, target); + } + + private: + static constexpr bool m_has_connectable_base{ + impl::has_initializer::value && + impl::has_interface() }; + + bool m_dispatch_base{}; + }; +} diff --git a/strings/base_xaml_typename.h b/strings/base_xaml_typename.h index 4a782fc72..2cc45b0bb 100644 --- a/strings/base_xaml_typename.h +++ b/strings/base_xaml_typename.h @@ -1,5 +1,5 @@ -namespace winrt::impl +WINRT_EXPORT namespace winrt::impl { template struct xaml_typename_name @@ -66,42 +66,42 @@ namespace winrt::impl static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; template<> - struct xaml_typename_kind + struct xaml_typename_kind { static constexpr Windows::UI::Xaml::Interop::TypeKind value = Windows::UI::Xaml::Interop::TypeKind::Primitive; }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 000000000..e5ca6e0fb --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,114 @@ +cmake_minimum_required(VERSION 3.16) + +if(NOT DEFINED PROJECT_NAME) + project(cppwinrt-tests) + set(STANDALONE_TESTING 1) + include(CTest) + if(NOT BUILD_TESTING) + message(NOTICE "BUILD_TESTING is OFF, nothing to do.") + return() + endif() +endif() + +# The tests use newer C++ features. +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") + +include_directories("${CMAKE_CURRENT_SOURCE_DIR}") +include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../cppwinrt") + +function(TestIsX64 OUTPUT_VARNAME) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" +#if !defined(__x86_64__) && !defined(_M_X64) +# error Not x86_64 +#endif +int main() {} + " ${OUTPUT_VARNAME}) +endfunction() +TestIsX64(TARGET_IS_X64) +if(TARGET_IS_X64) + add_compile_options(-mcx16) +endif() + + +# Some tests requires windowsnumerics.impl.h, but mingw-w64 didn't have this +# header until very recently. In case it is not present, download a copy if +# DOWNLOAD_WINDOWSNUMERICS is true, otherwise skip the tests which depend on +# this header. +function(TestHasWindowsnumerics OUTPUT_VARNAME) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" +#define _WINDOWS_NUMERICS_NAMESPACE_ winrt::Windows::Foundation::Numerics +#define _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ namespace winrt::Windows::Foundation::Numerics +#define _WINDOWS_NUMERICS_END_NAMESPACE_ +#include +int main() {} + " ${OUTPUT_VARNAME}) +endfunction() +TestHasWindowsnumerics(HAS_WINDOWSNUMERICS) +set(DOWNLOAD_WINDOWSNUMERICS FALSE CACHE BOOL "Whether to download a copy of mingw-w64's windowsnumerics.impl.h if not available.") +if(NOT HAS_WINDOWSNUMERICS AND DOWNLOAD_WINDOWSNUMERICS) + file( + DOWNLOAD https://github.com/mingw-w64/mingw-w64/raw/2b6272b31132e156dd1fc3722c1aa96b705a90dd/mingw-w64-headers/include/windowsnumerics.impl.h + "${CMAKE_CURRENT_BINARY_DIR}/windowsnumerics/windowsnumerics.impl.h" + EXPECTED_HASH SHA256=aff42491e57583c8ad8ca8e71d417a553bd1215ee9a71378679400ecded4b1ab + SHOW_PROGRESS + ) + include_directories("${CMAKE_CURRENT_BINARY_DIR}/windowsnumerics") + set(HAS_WINDOWSNUMERICS TRUE) + message(STATUS "Using windowsnumerics.impl.h downloaded from mingw-w64") +endif() + + +if(STANDALONE_TESTING) + add_custom_target(build-cppwinrt-projection) + set(CPPWINRT_PROJECTION_INCLUDE_DIR "" CACHE PATH "Include path for the C++/WinRT projection headers") + if(NOT CPPWINRT_PROJECTION_INCLUDE_DIR) + message(FATAL_ERROR "CPPWINRT_PROJECTION_INCLUDE_DIR is not specified.") + endif() +else() + set(CPPWINRT_PROJECTION_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt") + add_custom_command( + OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt/winrt/base.h" + COMMAND cppwinrt -input local -output "${CPPWINRT_PROJECTION_INCLUDE_DIR}" -verbose + DEPENDS + cppwinrt + VERBATIM + ) + add_custom_target(build-cppwinrt-projection + DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/cppwinrt/winrt/base.h" + ) +endif() +include_directories("${CPPWINRT_PROJECTION_INCLUDE_DIR}") + + +set(ENABLE_TEST_SANITIZERS FALSE CACHE BOOL "Enable ASan and UBSan for the tests.") +if(ENABLE_TEST_SANITIZERS) + # Disable the 'vptr' check because it seems to produce false-positives when using COM classes. + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,address -fno-sanitize=vptr") +endif() + + +set(USE_ANSI_COLOR FALSE CACHE BOOL "Enable ANSI colour output for Catch2 test runner.") +if(USE_ANSI_COLOR) + add_compile_definitions(CATCH_CONFIG_COLOUR_ANSI) + set(TEST_COLOR_ARG "--use-colour yes") +endif() + + +set(SKIP_LARGE_PCH FALSE CACHE BOOL "Skip building large precompiled headers.") + + +add_subdirectory(test) +add_subdirectory(test_nocoro) +add_subdirectory(test_cpp20) +add_subdirectory(test_cpp20_no_sourcelocation) + +if(HAS_WINDOWSNUMERICS) + add_subdirectory(old_tests) +endif() diff --git a/test/catch.hpp b/test/catch.hpp index 7e706f947..d008973a6 100644 --- a/test/catch.hpp +++ b/test/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.13.7 - * Generated: 2021-07-28 20:29:27.753164 + * Catch v2.13.9 + * Generated: 2022-04-12 22:37:23.260201 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,7 +15,7 @@ #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 13 -#define CATCH_VERSION_PATCH 7 +#define CATCH_VERSION_PATCH 9 #ifdef __clang__ # pragma clang system_header @@ -240,9 +240,6 @@ namespace Catch { // Visual C++ #if defined(_MSC_VER) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) - // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) @@ -251,13 +248,18 @@ namespace Catch { # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif +# if !defined(__clang__) // Handle Clang masquerading for msvc + // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR # endif // MSVC_TRADITIONAL + +// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) # endif // __clang__ #endif // _MSC_VER @@ -1010,34 +1012,34 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) #endif #endif @@ -1050,7 +1052,7 @@ struct AutoReg : NonCopyable { CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ @@ -1072,7 +1074,7 @@ struct AutoReg : NonCopyable { CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ @@ -1113,18 +1115,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \ @@ -1162,18 +1164,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T,__VA_ARGS__) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\ @@ -1204,7 +1206,7 @@ struct AutoReg : NonCopyable { static void TestFunc() #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \ - INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList ) + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, TmplList ) #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ @@ -1237,18 +1239,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\ @@ -1289,18 +1291,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \ @@ -1334,7 +1336,7 @@ struct AutoReg : NonCopyable { void TestName::test() #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \ - INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList ) + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, TmplList ) // end catch_test_registry.h // start catch_capture.hpp @@ -3091,7 +3093,7 @@ namespace Detail { Approx operator-() const; template ::value>::type> - Approx operator()( T const& value ) { + Approx operator()( T const& value ) const { Approx approx( static_cast(value) ); approx.m_epsilon = m_epsilon; approx.m_margin = m_margin; @@ -4163,7 +4165,7 @@ namespace Generators { if (!m_predicate(m_generator.get())) { // It might happen that there are no values that pass the // filter. In that case we throw an exception. - auto has_initial_value = next(); + auto has_initial_value = nextImpl(); if (!has_initial_value) { Catch::throw_exception(GeneratorException("No valid value found in filtered generator")); } @@ -4175,6 +4177,11 @@ namespace Generators { } bool next() override { + return nextImpl(); + } + + private: + bool nextImpl() { bool success = m_generator.next(); if (!success) { return false; @@ -7772,7 +7779,7 @@ namespace Catch { result = -erfc_inv(2.0 * p); // result *= normal distribution standard deviation (1.0) * sqrt(2) result *= /*sd * */ ROOT_TWO; - // result += normal disttribution mean (0) + // result += normal distribution mean (0) return result; } @@ -10800,7 +10807,7 @@ namespace Catch { { static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, }; - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) { for (auto const& def : signalDefs) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { reportFatal(def.name); @@ -10814,7 +10821,7 @@ namespace Catch { // Since we do not support multiple instantiations, we put these // into global variables and rely on cleaning them up in outlined // constructors/destructors - static PVOID exceptionHandlerHandle = nullptr; + static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr; // For MSVC, we reserve part of the stack memory for handling // memory overflow structured exception. @@ -10834,18 +10841,15 @@ namespace Catch { FatalConditionHandler::~FatalConditionHandler() = default; void FatalConditionHandler::engage_platform() { - // Register as first handler in current chain - exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - if (!exceptionHandlerHandle) { - CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); - } + // Register as a the top level exception filter. + previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter); } void FatalConditionHandler::disengage_platform() { - if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { - CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); + if (SetUnhandledExceptionFilter(reinterpret_cast(previousTopLevelExceptionFilter)) != topLevelExceptionFilter) { + CATCH_RUNTIME_ERROR("Could not restore previous top level exception filter"); } - exceptionHandlerHandle = nullptr; + previousTopLevelExceptionFilter = nullptr; } } // end namespace Catch @@ -11306,7 +11310,7 @@ namespace Catch { std::string TagInfo::all() const { size_t size = 0; for (auto const& spelling : spellings) { - // Add 2 for the brackes + // Add 2 for the brackets size += spelling.size() + 2; } @@ -13385,6 +13389,10 @@ namespace Catch { filename.erase(0, lastSlash); filename[0] = '#'; } + else + { + filename.insert(0, "#"); + } auto lastDot = filename.find_last_of('.'); if (lastDot != std::string::npos) { @@ -15380,7 +15388,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 13, 7, "", 0 ); + static Version version( 2, 13, 9, "", 0 ); return version; } @@ -17648,9 +17656,9 @@ int main (int argc, char * const argv[]) { #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) #define CATCH_BENCHMARK(...) \ - INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) #define CATCH_BENCHMARK_ADVANCED(name) \ - INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) #endif // CATCH_CONFIG_ENABLE_BENCHMARKING // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required @@ -17752,9 +17760,9 @@ int main (int argc, char * const argv[]) { #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) #define BENCHMARK(...) \ - INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) #define BENCHMARK_ADVANCED(name) \ - INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) #endif // CATCH_CONFIG_ENABLE_BENCHMARKING using Catch::Detail::Approx; @@ -17801,8 +17809,8 @@ using Catch::Detail::Approx; #define CATCH_WARN( msg ) (void)(0) #define CATCH_CAPTURE( msg ) (void)(0) -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) @@ -17811,7 +17819,7 @@ using Catch::Detail::Approx; #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) @@ -17834,8 +17842,8 @@ using Catch::Detail::Approx; #endif // "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) #define CATCH_GIVEN( desc ) #define CATCH_AND_GIVEN( desc ) #define CATCH_WHEN( desc ) @@ -17883,10 +17891,10 @@ using Catch::Detail::Approx; #define INFO( msg ) (void)(0) #define UNSCOPED_INFO( msg ) (void)(0) #define WARN( msg ) (void)(0) -#define CAPTURE( msg ) (void)(0) +#define CAPTURE( ... ) (void)(0) -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) @@ -17894,7 +17902,7 @@ using Catch::Detail::Approx; #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) @@ -17924,8 +17932,8 @@ using Catch::Detail::Approx; #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // "BDD-style" convenience wrappers -#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) #define GIVEN( desc ) #define AND_GIVEN( desc ) diff --git a/test/mingw_com_support.h b/test/mingw_com_support.h new file mode 100644 index 000000000..80e56455b --- /dev/null +++ b/test/mingw_com_support.h @@ -0,0 +1,13 @@ +#if defined(__clang__) +#define HAS_DECLSPEC_UUID __has_declspec_attribute(uuid) +#elif defined(_MSC_VER) +#define HAS_DECLSPEC_UUID 1 +#else +#define HAS_DECLSPEC_UUID 0 +#endif + +#if HAS_DECLSPEC_UUID +#define DECLSPEC_UUID(x) __declspec(uuid(x)) +#else +#define DECLSPEC_UUID(x) +#endif diff --git a/test/nuget/ConsoleApplication1/ConsoleApplication1.vcxproj b/test/nuget/ConsoleApplication1/ConsoleApplication1.vcxproj index 86453e25f..38f3ee4cc 100644 --- a/test/nuget/ConsoleApplication1/ConsoleApplication1.vcxproj +++ b/test/nuget/ConsoleApplication1/ConsoleApplication1.vcxproj @@ -1,6 +1,5 @@ - true @@ -11,15 +10,21 @@ {4dd64eae-4b27-415a-863e-55cb8d5863dd} Win32Proj ConsoleApplication1 - 10.0.19041.0 - 10.0.17134.0 + + Debug + ARM64 + Debug Win32 + + Release + ARM64 + Release Win32 @@ -35,9 +40,6 @@ Application - v140 - v141 - v142 Unicode @@ -59,7 +61,6 @@ - @@ -69,6 +70,7 @@ $(IntDir)pch.pch _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) Level4 + true %(AdditionalOptions) /permissive- /bigobj @@ -126,11 +128,4 @@ - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/test/nuget/ConsoleApplication1/ConsoleApplication1_TemporaryKey.pfx b/test/nuget/ConsoleApplication1/ConsoleApplication1_TemporaryKey.pfx deleted file mode 100644 index b1f67069d..000000000 Binary files a/test/nuget/ConsoleApplication1/ConsoleApplication1_TemporaryKey.pfx and /dev/null differ diff --git a/test/nuget/ConsoleApplication1/packages.config b/test/nuget/ConsoleApplication1/packages.config deleted file mode 100644 index be196b1fc..000000000 --- a/test/nuget/ConsoleApplication1/packages.config +++ /dev/null @@ -1,4 +0,0 @@ -īģŋ - - - \ No newline at end of file diff --git a/test/nuget/Directory.Build.props b/test/nuget/Directory.Build.props index 9f410480b..a54887b1e 100644 --- a/test/nuget/Directory.Build.props +++ b/test/nuget/Directory.Build.props @@ -23,7 +23,7 @@ $(IntDir)Generated Files\ high $(Platform) - x86 + x86 $(SolutionDir)..\..\_build\$(CppWinRTPlatform)\$(Configuration)\ diff --git a/test/nuget/NuGetTest.sln b/test/nuget/NuGetTest.sln index 24b81d177..c836b2551 100644 --- a/test/nuget/NuGetTest.sln +++ b/test/nuget/NuGetTest.sln @@ -1,7 +1,7 @@ -īģŋ + Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29025.244 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33516.290 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestApp", "TestApp\TestApp.vcxproj", "{A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}" EndProject @@ -45,262 +45,307 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestStaticLibrary7", "TestS EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConsoleApplication1", "ConsoleApplication1\ConsoleApplication1.vcxproj", "{4DD64EAE-4B27-415A-863E-55CB8D5863DD}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestProxyStub", "TestProxyStub\TestProxyStub.vcxproj", "{98E28FC8-2EB7-4544-9B6A-941462C6D3E2}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleApp", "TestModuleApp\TestModuleApp.vcxproj", "{8679913F-D38D-468F-A8B7-75B187A7A8BC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleBuilder", "TestModuleBuilder\TestModuleBuilder.vcxproj", "{AEE91B86-AA17-4C22-B0C2-08B2C287E375}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleComponent1", "TestModuleComponent1\TestModuleComponent1.vcxproj", "{F54D9A50-84D7-4953-8350-BEFE73CC36F6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleComponent2", "TestModuleComponent2\TestModuleComponent2.vcxproj", "{126E9412-E861-47C6-8684-C8F9BF32C0BD}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestModuleConsumerApp", "TestModuleConsumerApp\TestModuleConsumerApp.vcxproj", "{FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}" + ProjectSection(ProjectDependencies) = postProject + {AEE91B86-AA17-4C22-B0C2-08B2C287E375} = {AEE91B86-AA17-4C22-B0C2-08B2C287E375} + {F54D9A50-84D7-4953-8350-BEFE73CC36F6} = {F54D9A50-84D7-4953-8350-BEFE73CC36F6} + {126E9412-E861-47C6-8684-C8F9BF32C0BD} = {126E9412-E861-47C6-8684-C8F9BF32C0BD} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 - Release|ARM = Release|ARM Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|ARM.ActiveCfg = Debug|ARM - {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|ARM.Build.0 = Debug|ARM - {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|ARM.Deploy.0 = Debug|ARM - {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|ARM64.ActiveCfg = Debug|Win32 + {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|ARM64.Build.0 = Debug|ARM64 + {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|ARM64.Deploy.0 = Debug|ARM64 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|x64.ActiveCfg = Debug|x64 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|x64.Build.0 = Debug|x64 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|x64.Deploy.0 = Debug|x64 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|x86.ActiveCfg = Debug|Win32 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|x86.Build.0 = Debug|Win32 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Debug|x86.Deploy.0 = Debug|Win32 - {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|ARM.ActiveCfg = Release|ARM - {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|ARM.Build.0 = Release|ARM - {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|ARM.Deploy.0 = Release|ARM - {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|ARM64.ActiveCfg = Release|Win32 + {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|ARM64.ActiveCfg = Release|ARM64 + {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|ARM64.Build.0 = Release|ARM64 + {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|ARM64.Deploy.0 = Release|ARM64 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|x64.ActiveCfg = Release|x64 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|x64.Build.0 = Release|x64 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|x64.Deploy.0 = Release|x64 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|x86.ActiveCfg = Release|Win32 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|x86.Build.0 = Release|Win32 {A8BDBDE9-1A3D-4F5E-8668-9F6E84790D44}.Release|x86.Deploy.0 = Release|Win32 - {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|ARM.ActiveCfg = Debug|ARM - {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|ARM.Build.0 = Debug|ARM - {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|ARM64.ActiveCfg = Debug|Win32 + {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|ARM64.Build.0 = Debug|ARM64 {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|x64.ActiveCfg = Debug|x64 {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|x64.Build.0 = Debug|x64 {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|x86.ActiveCfg = Debug|Win32 {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Debug|x86.Build.0 = Debug|Win32 - {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|ARM.ActiveCfg = Release|ARM - {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|ARM.Build.0 = Release|ARM - {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|ARM64.ActiveCfg = Release|Win32 + {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|ARM64.ActiveCfg = Release|ARM64 + {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|ARM64.Build.0 = Release|ARM64 {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|x64.ActiveCfg = Release|x64 {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|x64.Build.0 = Release|x64 {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|x86.ActiveCfg = Release|Win32 {E0EBBE54-C046-4611-B048-3CE893B1DF8A}.Release|x86.Build.0 = Release|Win32 - {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|ARM.ActiveCfg = Debug|ARM - {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|ARM.Build.0 = Debug|ARM - {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|ARM64.ActiveCfg = Debug|Win32 + {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|ARM64.Build.0 = Debug|ARM64 {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|x64.ActiveCfg = Debug|x64 {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|x64.Build.0 = Debug|x64 {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|x86.ActiveCfg = Debug|Win32 {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Debug|x86.Build.0 = Debug|Win32 - {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|ARM.ActiveCfg = Release|ARM - {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|ARM.Build.0 = Release|ARM - {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|ARM64.ActiveCfg = Release|Win32 + {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|ARM64.ActiveCfg = Release|ARM64 + {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|ARM64.Build.0 = Release|ARM64 {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|x64.ActiveCfg = Release|x64 {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|x64.Build.0 = Release|x64 {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|x86.ActiveCfg = Release|Win32 {4BBB2DE7-4596-4DA6-A923-E65E838363B5}.Release|x86.Build.0 = Release|Win32 - {2158F418-CA97-4599-8103-EFC133850BAA}.Debug|ARM.ActiveCfg = Debug|Win32 - {2158F418-CA97-4599-8103-EFC133850BAA}.Debug|ARM64.ActiveCfg = Debug|Win32 + {2158F418-CA97-4599-8103-EFC133850BAA}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {2158F418-CA97-4599-8103-EFC133850BAA}.Debug|ARM64.Build.0 = Debug|ARM64 {2158F418-CA97-4599-8103-EFC133850BAA}.Debug|x64.ActiveCfg = Debug|x64 {2158F418-CA97-4599-8103-EFC133850BAA}.Debug|x64.Build.0 = Debug|x64 {2158F418-CA97-4599-8103-EFC133850BAA}.Debug|x86.ActiveCfg = Debug|Win32 {2158F418-CA97-4599-8103-EFC133850BAA}.Debug|x86.Build.0 = Debug|Win32 - {2158F418-CA97-4599-8103-EFC133850BAA}.Release|ARM.ActiveCfg = Release|Win32 - {2158F418-CA97-4599-8103-EFC133850BAA}.Release|ARM64.ActiveCfg = Release|Win32 + {2158F418-CA97-4599-8103-EFC133850BAA}.Release|ARM64.ActiveCfg = Release|ARM64 + {2158F418-CA97-4599-8103-EFC133850BAA}.Release|ARM64.Build.0 = Release|ARM64 {2158F418-CA97-4599-8103-EFC133850BAA}.Release|x64.ActiveCfg = Release|x64 {2158F418-CA97-4599-8103-EFC133850BAA}.Release|x64.Build.0 = Release|x64 {2158F418-CA97-4599-8103-EFC133850BAA}.Release|x86.ActiveCfg = Release|Win32 {2158F418-CA97-4599-8103-EFC133850BAA}.Release|x86.Build.0 = Release|Win32 - {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Debug|ARM.ActiveCfg = Debug|Win32 - {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Debug|ARM64.ActiveCfg = Debug|Win32 + {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Debug|ARM64.Build.0 = Debug|ARM64 {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Debug|x64.ActiveCfg = Debug|x64 {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Debug|x64.Build.0 = Debug|x64 {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Debug|x86.ActiveCfg = Debug|Win32 {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Debug|x86.Build.0 = Debug|Win32 - {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Release|ARM.ActiveCfg = Release|Win32 - {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Release|ARM64.ActiveCfg = Release|Win32 + {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Release|ARM64.ActiveCfg = Release|ARM64 + {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Release|ARM64.Build.0 = Release|ARM64 {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Release|x64.ActiveCfg = Release|x64 {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Release|x64.Build.0 = Release|x64 {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Release|x86.ActiveCfg = Release|Win32 {0011F69F-2363-4DFD-B02A-1E7E909BCE89}.Release|x86.Build.0 = Release|Win32 - {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|ARM.ActiveCfg = Debug|ARM - {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|ARM.Build.0 = Debug|ARM - {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|ARM64.ActiveCfg = Debug|Win32 + {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|ARM64.Build.0 = Debug|ARM64 {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|x64.ActiveCfg = Debug|x64 {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|x64.Build.0 = Debug|x64 {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|x86.ActiveCfg = Debug|Win32 {C2820B98-A31F-46D0-A96D-B8F24392B049}.Debug|x86.Build.0 = Debug|Win32 - {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|ARM.ActiveCfg = Release|ARM - {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|ARM.Build.0 = Release|ARM - {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|ARM64.ActiveCfg = Release|Win32 + {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|ARM64.ActiveCfg = Release|ARM64 + {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|ARM64.Build.0 = Release|ARM64 {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|x64.ActiveCfg = Release|x64 {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|x64.Build.0 = Release|x64 {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|x86.ActiveCfg = Release|Win32 {C2820B98-A31F-46D0-A96D-B8F24392B049}.Release|x86.Build.0 = Release|Win32 - {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|ARM.ActiveCfg = Debug|ARM - {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|ARM.Build.0 = Debug|ARM - {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|ARM64.ActiveCfg = Debug|Win32 + {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|ARM64.Build.0 = Debug|ARM64 {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|x64.ActiveCfg = Debug|x64 {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|x64.Build.0 = Debug|x64 {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|x86.ActiveCfg = Debug|Win32 {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Debug|x86.Build.0 = Debug|Win32 - {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|ARM.ActiveCfg = Release|ARM - {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|ARM.Build.0 = Release|ARM - {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|ARM64.ActiveCfg = Release|Win32 + {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|ARM64.ActiveCfg = Release|ARM64 + {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|ARM64.Build.0 = Release|ARM64 {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|x64.ActiveCfg = Release|x64 {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|x64.Build.0 = Release|x64 {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|x86.ActiveCfg = Release|Win32 {1350E626-038B-4BDF-8E1D-C751EF33D90F}.Release|x86.Build.0 = Release|Win32 - {ADC53200-B456-4386-9851-5BF69DFB8928}.Debug|ARM.ActiveCfg = Debug|ARM - {ADC53200-B456-4386-9851-5BF69DFB8928}.Debug|ARM.Build.0 = Debug|ARM {ADC53200-B456-4386-9851-5BF69DFB8928}.Debug|ARM64.ActiveCfg = Debug|ARM64 {ADC53200-B456-4386-9851-5BF69DFB8928}.Debug|ARM64.Build.0 = Debug|ARM64 {ADC53200-B456-4386-9851-5BF69DFB8928}.Debug|x64.ActiveCfg = Debug|x64 {ADC53200-B456-4386-9851-5BF69DFB8928}.Debug|x64.Build.0 = Debug|x64 {ADC53200-B456-4386-9851-5BF69DFB8928}.Debug|x86.ActiveCfg = Debug|Win32 {ADC53200-B456-4386-9851-5BF69DFB8928}.Debug|x86.Build.0 = Debug|Win32 - {ADC53200-B456-4386-9851-5BF69DFB8928}.Release|ARM.ActiveCfg = Release|ARM - {ADC53200-B456-4386-9851-5BF69DFB8928}.Release|ARM.Build.0 = Release|ARM {ADC53200-B456-4386-9851-5BF69DFB8928}.Release|ARM64.ActiveCfg = Release|ARM64 {ADC53200-B456-4386-9851-5BF69DFB8928}.Release|ARM64.Build.0 = Release|ARM64 {ADC53200-B456-4386-9851-5BF69DFB8928}.Release|x64.ActiveCfg = Release|x64 {ADC53200-B456-4386-9851-5BF69DFB8928}.Release|x64.Build.0 = Release|x64 {ADC53200-B456-4386-9851-5BF69DFB8928}.Release|x86.ActiveCfg = Release|Win32 {ADC53200-B456-4386-9851-5BF69DFB8928}.Release|x86.Build.0 = Release|Win32 - {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|ARM.ActiveCfg = Debug|ARM - {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|ARM.Build.0 = Debug|ARM - {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|ARM64.ActiveCfg = Debug|Win32 + {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|ARM64.Build.0 = Debug|ARM64 {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|x64.ActiveCfg = Debug|x64 {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|x64.Build.0 = Debug|x64 {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|x86.ActiveCfg = Debug|Win32 {432068A4-B206-4468-9254-446CCEB15A2C}.Debug|x86.Build.0 = Debug|Win32 - {432068A4-B206-4468-9254-446CCEB15A2C}.Release|ARM.ActiveCfg = Release|ARM - {432068A4-B206-4468-9254-446CCEB15A2C}.Release|ARM.Build.0 = Release|ARM - {432068A4-B206-4468-9254-446CCEB15A2C}.Release|ARM64.ActiveCfg = Release|Win32 + {432068A4-B206-4468-9254-446CCEB15A2C}.Release|ARM64.ActiveCfg = Release|ARM64 + {432068A4-B206-4468-9254-446CCEB15A2C}.Release|ARM64.Build.0 = Release|ARM64 {432068A4-B206-4468-9254-446CCEB15A2C}.Release|x64.ActiveCfg = Release|x64 {432068A4-B206-4468-9254-446CCEB15A2C}.Release|x64.Build.0 = Release|x64 {432068A4-B206-4468-9254-446CCEB15A2C}.Release|x86.ActiveCfg = Release|Win32 {432068A4-B206-4468-9254-446CCEB15A2C}.Release|x86.Build.0 = Release|Win32 - {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|ARM.ActiveCfg = Debug|ARM - {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|ARM.Build.0 = Debug|ARM - {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|ARM64.ActiveCfg = Debug|Win32 + {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|ARM64.Build.0 = Debug|ARM64 {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|x64.ActiveCfg = Debug|x64 {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|x64.Build.0 = Debug|x64 {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|x86.ActiveCfg = Debug|Win32 {8456C55F-BF01-4798-B79B-7388681C398F}.Debug|x86.Build.0 = Debug|Win32 - {8456C55F-BF01-4798-B79B-7388681C398F}.Release|ARM.ActiveCfg = Release|ARM - {8456C55F-BF01-4798-B79B-7388681C398F}.Release|ARM.Build.0 = Release|ARM - {8456C55F-BF01-4798-B79B-7388681C398F}.Release|ARM64.ActiveCfg = Release|Win32 + {8456C55F-BF01-4798-B79B-7388681C398F}.Release|ARM64.ActiveCfg = Release|ARM64 + {8456C55F-BF01-4798-B79B-7388681C398F}.Release|ARM64.Build.0 = Release|ARM64 {8456C55F-BF01-4798-B79B-7388681C398F}.Release|x64.ActiveCfg = Release|x64 {8456C55F-BF01-4798-B79B-7388681C398F}.Release|x64.Build.0 = Release|x64 {8456C55F-BF01-4798-B79B-7388681C398F}.Release|x86.ActiveCfg = Release|Win32 {8456C55F-BF01-4798-B79B-7388681C398F}.Release|x86.Build.0 = Release|Win32 - {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|ARM.ActiveCfg = Debug|ARM - {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|ARM.Build.0 = Debug|ARM - {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|ARM64.ActiveCfg = Debug|Win32 + {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|ARM64.Build.0 = Debug|ARM64 {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|x64.ActiveCfg = Debug|x64 {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|x64.Build.0 = Debug|x64 {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|x86.ActiveCfg = Debug|Win32 {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Debug|x86.Build.0 = Debug|Win32 - {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|ARM.ActiveCfg = Release|ARM - {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|ARM.Build.0 = Release|ARM - {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|ARM64.ActiveCfg = Release|Win32 + {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|ARM64.ActiveCfg = Release|ARM64 + {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|ARM64.Build.0 = Release|ARM64 {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|x64.ActiveCfg = Release|x64 {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|x64.Build.0 = Release|x64 {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|x86.ActiveCfg = Release|Win32 {DC435C3F-C38E-43D1-B702-DC03F530A3CB}.Release|x86.Build.0 = Release|Win32 - {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|ARM.ActiveCfg = Debug|ARM - {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|ARM.Build.0 = Debug|ARM - {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|ARM64.ActiveCfg = Debug|Win32 + {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|ARM64.Build.0 = Debug|ARM64 {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|x64.ActiveCfg = Debug|x64 {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|x64.Build.0 = Debug|x64 {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|x86.ActiveCfg = Debug|Win32 {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Debug|x86.Build.0 = Debug|Win32 - {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|ARM.ActiveCfg = Release|ARM - {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|ARM.Build.0 = Release|ARM - {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|ARM64.ActiveCfg = Release|Win32 + {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|ARM64.ActiveCfg = Release|ARM64 + {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|ARM64.Build.0 = Release|ARM64 {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|x64.ActiveCfg = Release|x64 {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|x64.Build.0 = Release|x64 {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|x86.ActiveCfg = Release|Win32 {DC435C3F-C38E-43D1-B702-DC03F530A3DD}.Release|x86.Build.0 = Release|Win32 - {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Debug|ARM.ActiveCfg = Debug|ARM - {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Debug|ARM.Build.0 = Debug|ARM {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Debug|ARM64.ActiveCfg = Debug|ARM64 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Debug|ARM64.Build.0 = Debug|ARM64 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Debug|x64.ActiveCfg = Debug|x64 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Debug|x64.Build.0 = Debug|x64 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Debug|x86.ActiveCfg = Debug|x86 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Debug|x86.Build.0 = Debug|x86 - {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Release|ARM.ActiveCfg = Release|ARM - {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Release|ARM.Build.0 = Release|ARM {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Release|ARM64.ActiveCfg = Release|ARM64 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Release|ARM64.Build.0 = Release|ARM64 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Release|x64.ActiveCfg = Release|x64 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Release|x64.Build.0 = Release|x64 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Release|x86.ActiveCfg = Release|x86 {C47F8562-A2B9-4BA3-87AC-B42D015E241D}.Release|x86.Build.0 = Release|x86 - {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|ARM.ActiveCfg = Debug|ARM - {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|ARM.Build.0 = Debug|ARM - {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|ARM64.ActiveCfg = Debug|Win32 + {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|ARM64.Build.0 = Debug|ARM64 {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|x64.ActiveCfg = Debug|x64 {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|x64.Build.0 = Debug|x64 {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|x86.ActiveCfg = Debug|Win32 {8717FA32-34A8-457D-B77B-AE005703EB55}.Debug|x86.Build.0 = Debug|Win32 - {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|ARM.ActiveCfg = Release|ARM - {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|ARM.Build.0 = Release|ARM - {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|ARM64.ActiveCfg = Release|Win32 + {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|ARM64.ActiveCfg = Release|ARM64 + {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|ARM64.Build.0 = Release|ARM64 {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|x64.ActiveCfg = Release|x64 {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|x64.Build.0 = Release|x64 {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|x86.ActiveCfg = Release|Win32 {8717FA32-34A8-457D-B77B-AE005703EB55}.Release|x86.Build.0 = Release|Win32 - {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Debug|ARM.ActiveCfg = Debug|ARM - {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Debug|ARM.Build.0 = Debug|ARM {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Debug|ARM64.ActiveCfg = Debug|ARM64 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Debug|ARM64.Build.0 = Debug|ARM64 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Debug|x64.ActiveCfg = Debug|x64 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Debug|x64.Build.0 = Debug|x64 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Debug|x86.ActiveCfg = Debug|Win32 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Debug|x86.Build.0 = Debug|Win32 - {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Release|ARM.ActiveCfg = Release|ARM - {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Release|ARM.Build.0 = Release|ARM {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Release|ARM64.ActiveCfg = Release|ARM64 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Release|ARM64.Build.0 = Release|ARM64 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Release|x64.ActiveCfg = Release|x64 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Release|x64.Build.0 = Release|x64 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Release|x86.ActiveCfg = Release|Win32 {FF846D79-F4B8-495A-9FB4-79BAAEB98E4F}.Release|x86.Build.0 = Release|Win32 - {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|ARM.ActiveCfg = Debug|ARM - {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|ARM.Build.0 = Debug|ARM - {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|ARM64.ActiveCfg = Debug|Win32 + {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|ARM64.Build.0 = Debug|ARM64 {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|x64.ActiveCfg = Debug|x64 {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|x64.Build.0 = Debug|x64 {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|x86.ActiveCfg = Debug|Win32 {F89C2185-7834-443D-A449-53BD52FFEA3B}.Debug|x86.Build.0 = Debug|Win32 - {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|ARM.ActiveCfg = Release|ARM - {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|ARM.Build.0 = Release|ARM - {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|ARM64.ActiveCfg = Release|Win32 + {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|ARM64.ActiveCfg = Release|ARM64 + {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|ARM64.Build.0 = Release|ARM64 {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|x64.ActiveCfg = Release|x64 {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|x64.Build.0 = Release|x64 {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|x86.ActiveCfg = Release|Win32 {F89C2185-7834-443D-A449-53BD52FFEA3B}.Release|x86.Build.0 = Release|Win32 - {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Debug|ARM.ActiveCfg = Debug|Win32 - {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Debug|ARM64.ActiveCfg = Debug|Win32 + {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Debug|ARM64.Build.0 = Debug|ARM64 {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Debug|x64.ActiveCfg = Debug|x64 {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Debug|x64.Build.0 = Debug|x64 {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Debug|x86.ActiveCfg = Debug|Win32 {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Debug|x86.Build.0 = Debug|Win32 - {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Release|ARM.ActiveCfg = Release|Win32 - {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Release|ARM64.ActiveCfg = Release|Win32 + {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Release|ARM64.ActiveCfg = Release|ARM64 + {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Release|ARM64.Build.0 = Release|ARM64 {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Release|x64.ActiveCfg = Release|x64 {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Release|x64.Build.0 = Release|x64 {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Release|x86.ActiveCfg = Release|Win32 {4DD64EAE-4B27-415A-863E-55CB8D5863DD}.Release|x86.Build.0 = Release|Win32 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Debug|ARM64.Build.0 = Debug|ARM64 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Debug|x64.ActiveCfg = Debug|x64 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Debug|x64.Build.0 = Debug|x64 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Debug|x86.ActiveCfg = Debug|Win32 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Debug|x86.Build.0 = Debug|Win32 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|ARM64.ActiveCfg = Release|ARM64 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|ARM64.Build.0 = Release|ARM64 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|x64.ActiveCfg = Release|x64 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|x64.Build.0 = Release|x64 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|x86.ActiveCfg = Release|Win32 + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2}.Release|x86.Build.0 = Release|Win32 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|ARM64.Build.0 = Debug|ARM64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|x64.ActiveCfg = Debug|x64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|x64.Build.0 = Debug|x64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|x86.ActiveCfg = Debug|Win32 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Debug|x86.Build.0 = Debug|Win32 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|ARM64.ActiveCfg = Release|ARM64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|ARM64.Build.0 = Release|ARM64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|x64.ActiveCfg = Release|x64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|x64.Build.0 = Release|x64 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|x86.ActiveCfg = Release|Win32 + {8679913F-D38D-468F-A8B7-75B187A7A8BC}.Release|x86.Build.0 = Release|Win32 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Debug|ARM64.ActiveCfg = Release|ARM64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Debug|x64.ActiveCfg = Release|x64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Debug|x64.Build.0 = Release|x64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Debug|x86.ActiveCfg = Release|Win32 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|ARM64.ActiveCfg = Release|ARM64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|ARM64.Build.0 = Release|ARM64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|x64.ActiveCfg = Release|x64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|x64.Build.0 = Release|x64 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|x86.ActiveCfg = Release|Win32 + {AEE91B86-AA17-4C22-B0C2-08B2C287E375}.Release|x86.Build.0 = Release|Win32 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Debug|ARM64.ActiveCfg = Release|ARM64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Debug|x64.ActiveCfg = Release|x64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Debug|x64.Build.0 = Release|x64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Debug|x86.ActiveCfg = Release|Win32 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|ARM64.ActiveCfg = Release|ARM64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|ARM64.Build.0 = Release|ARM64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|x64.ActiveCfg = Release|x64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|x64.Build.0 = Release|x64 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|x86.ActiveCfg = Release|Win32 + {F54D9A50-84D7-4953-8350-BEFE73CC36F6}.Release|x86.Build.0 = Release|Win32 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Debug|ARM64.ActiveCfg = Release|ARM64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Debug|x64.ActiveCfg = Release|x64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Debug|x64.Build.0 = Release|x64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Debug|x86.ActiveCfg = Release|Win32 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|ARM64.ActiveCfg = Release|ARM64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|ARM64.Build.0 = Release|ARM64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|x64.ActiveCfg = Release|x64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|x64.Build.0 = Release|x64 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|x86.ActiveCfg = Release|Win32 + {126E9412-E861-47C6-8684-C8F9BF32C0BD}.Release|x86.Build.0 = Release|Win32 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Debug|ARM64.ActiveCfg = Release|ARM64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Debug|x64.ActiveCfg = Release|x64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Debug|x64.Build.0 = Release|x64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Debug|x86.ActiveCfg = Release|Win32 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|ARM64.ActiveCfg = Release|ARM64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|ARM64.Build.0 = Release|ARM64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|x64.ActiveCfg = Release|x64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|x64.Build.0 = Release|x64 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|x86.ActiveCfg = Release|Win32 + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/test/nuget/TestApp/TestApp.vcxproj b/test/nuget/TestApp/TestApp.vcxproj index 894993ff4..f14bd9f0b 100644 --- a/test/nuget/TestApp/TestApp.vcxproj +++ b/test/nuget/TestApp/TestApp.vcxproj @@ -13,14 +13,12 @@ true Windows Store 10.0 - 10.0.19041.0 - 10.0.17134.0 - + Debug - ARM + ARM64 Debug @@ -30,9 +28,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -45,9 +43,6 @@ Application - v140 - v141 - v142 Unicode @@ -75,6 +70,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj @@ -148,6 +144,9 @@ + + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2} + {e0ebbe54-c046-4611-b048-3ce893b1df8a} diff --git a/test/nuget/TestModuleApp/CustomDependencyObject.cpp b/test/nuget/TestModuleApp/CustomDependencyObject.cpp new file mode 100644 index 000000000..81631e387 --- /dev/null +++ b/test/nuget/TestModuleApp/CustomDependencyObject.cpp @@ -0,0 +1,8 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import winrt.Windows.Foundation; +import winrt.Windows.UI.Xaml; + +#include "CustomDependencyObject.h" +#include "CustomDependencyObject.g.cpp" diff --git a/test/nuget/TestModuleApp/CustomDependencyObject.h b/test/nuget/TestModuleApp/CustomDependencyObject.h new file mode 100644 index 000000000..79fd6b1ff --- /dev/null +++ b/test/nuget/TestModuleApp/CustomDependencyObject.h @@ -0,0 +1,23 @@ +#pragma once +#include "CustomDependencyObject.g.h" + +namespace winrt::TestModuleApp::implementation +{ + struct CustomDependencyObject : CustomDependencyObjectT + { + CustomDependencyObject() = default; + + hstring Name() { return m_name; } + void Name(hstring const& value) { m_name = value; } + + private: + hstring m_name; + }; +} + +namespace winrt::TestModuleApp::factory_implementation +{ + struct CustomDependencyObject : CustomDependencyObjectT + { + }; +} diff --git a/test/nuget/TestModuleApp/ModuleTestHelper.cpp b/test/nuget/TestModuleApp/ModuleTestHelper.cpp new file mode 100644 index 000000000..1e3d7bc1a --- /dev/null +++ b/test/nuget/TestModuleApp/ModuleTestHelper.cpp @@ -0,0 +1,7 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import winrt.Windows.Foundation; + +#include "ModuleTestHelper.h" +#include "ModuleTestHelper.g.cpp" diff --git a/test/nuget/TestModuleApp/ModuleTestHelper.h b/test/nuget/TestModuleApp/ModuleTestHelper.h new file mode 100644 index 000000000..c5a699c6b --- /dev/null +++ b/test/nuget/TestModuleApp/ModuleTestHelper.h @@ -0,0 +1,27 @@ +#pragma once +#include "ModuleTestHelper.g.h" + +namespace winrt::TestModuleApp::implementation +{ + struct ModuleTestHelper : ModuleTestHelperT + { + ModuleTestHelper() = default; + + Windows::Foundation::Uri CreateUri(hstring const& url) + { + return Windows::Foundation::Uri(url); + } + + Windows::Foundation::IAsyncOperation GetStringAsync() + { + co_return L"hello from module"; + } + }; +} + +namespace winrt::TestModuleApp::factory_implementation +{ + struct ModuleTestHelper : ModuleTestHelperT + { + }; +} diff --git a/test/nuget/TestModuleApp/PropertySheet.props b/test/nuget/TestModuleApp/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleApp/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleApp/TestModuleApp.def b/test/nuget/TestModuleApp/TestModuleApp.def new file mode 100644 index 000000000..53d2e7cbf --- /dev/null +++ b/test/nuget/TestModuleApp/TestModuleApp.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/test/nuget/TestModuleApp/TestModuleApp.idl b/test/nuget/TestModuleApp/TestModuleApp.idl new file mode 100644 index 000000000..ab3c56707 --- /dev/null +++ b/test/nuget/TestModuleApp/TestModuleApp.idl @@ -0,0 +1,20 @@ +namespace TestModuleApp +{ + // A type that inherits from Windows.UI.Xaml.DependencyObject to exercise + // cross-namespace inheritance in module builds. + [default_interface] + unsealed runtimeclass CustomDependencyObject : Windows.UI.Xaml.DependencyObject + { + CustomDependencyObject(); + String Name{ get; set; }; + } + + // A simple runtime class using platform SDK types. + [default_interface] + runtimeclass ModuleTestHelper + { + ModuleTestHelper(); + Windows.Foundation.Uri CreateUri(String url); + Windows.Foundation.IAsyncOperation GetStringAsync(); + } +} diff --git a/test/nuget/TestModuleApp/TestModuleApp.vcxproj b/test/nuget/TestModuleApp/TestModuleApp.vcxproj new file mode 100644 index 000000000..522e0d911 --- /dev/null +++ b/test/nuget/TestModuleApp/TestModuleApp.vcxproj @@ -0,0 +1,127 @@ + + + + + true + true + true + Windows;TestModuleApp + true + {8679913F-D38D-468F-A8B7-75B187A7A8BC} + TestModuleApp + TestModuleApp + en-US + 14.0 + + + + + Debug + Win32 + + + Debug + x64 + + + Debug + ARM64 + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + Application + v145 + Unicode + + + true + + + false + true + + + + + + + + + + + + + + + + + Use + pch.h + $(IntDir)pch.pch + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + 5311;28204 + NOMINMAX;%(PreprocessorDefinitions) + true + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + + + + TestModuleApp.idl + + + TestModuleApp.idl + + + + + Create + + + + TestModuleApp.idl + + + TestModuleApp.idl + + + + + + + + + + + + + diff --git a/test/nuget/TestModuleApp/main.cpp b/test/nuget/TestModuleApp/main.cpp new file mode 100644 index 000000000..907e4afed --- /dev/null +++ b/test/nuget/TestModuleApp/main.cpp @@ -0,0 +1,42 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import std; +import winrt.Windows.Foundation; +import winrt.Windows.UI.Xaml; + +#include "ModuleTestHelper.h" +#include "CustomDependencyObject.h" + +using namespace winrt; +using namespace Windows::Foundation; + +int main() +{ + init_apartment(); + + // Test ModuleTestHelper + auto helper = TestModuleApp::ModuleTestHelper(); + auto uri = helper.CreateUri(L"https://example.com"); + std::printf("URI: %ls\n", uri.AbsoluteUri().c_str()); + + auto str = helper.GetStringAsync().get(); + std::printf("Async: %ls\n", str.c_str()); + + // Test CustomDependencyObject (inherits from DependencyObject) + // Note: DependencyObject requires XAML runtime, which isn't available in a console app. + // We verify the type compiles and links correctly; runtime creation would need a XAML host. + try + { + auto obj = winrt::make(); + obj.Name(L"test"); + std::printf("Name: %ls\n", obj.Name().c_str()); + } + catch (winrt::hresult_error const& e) + { + std::printf("CustomDependencyObject: expected runtime error (no XAML host): %ls\n", e.message().c_str()); + } + + std::printf("All module tests passed.\n"); + return 0; +} diff --git a/test/test_win7/pch.cpp b/test/nuget/TestModuleApp/pch.cpp similarity index 100% rename from test/test_win7/pch.cpp rename to test/nuget/TestModuleApp/pch.cpp diff --git a/test/nuget/TestModuleApp/pch.h b/test/nuget/TestModuleApp/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleApp/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestModuleBuilder/PropertySheet.props b/test/nuget/TestModuleBuilder/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleBuilder/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleBuilder/TestModuleBuilder.vcxproj b/test/nuget/TestModuleBuilder/TestModuleBuilder.vcxproj new file mode 100644 index 000000000..d2d852240 --- /dev/null +++ b/test/nuget/TestModuleBuilder/TestModuleBuilder.vcxproj @@ -0,0 +1,67 @@ + + + + + true + Windows.Foundation + Windows.Foundation.Diagnostics + true + {AEE91B86-AA17-4C22-B0C2-08B2C287E375} + TestModuleBuilder + TestModuleBuilder + en-US + 14.0 + + + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + StaticLibrary + v145 + Unicode + + + false + true + + + + + + + + + + Use + pch.h + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + true + NOMINMAX;%(PreprocessorDefinitions) + + + + + + + + Create + + + + + diff --git a/test/nuget/TestModuleBuilder/pch.cpp b/test/nuget/TestModuleBuilder/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleBuilder/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleBuilder/pch.h b/test/nuget/TestModuleBuilder/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleBuilder/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestModuleComponent1/Greeter.cpp b/test/nuget/TestModuleComponent1/Greeter.cpp new file mode 100644 index 000000000..04c668e10 --- /dev/null +++ b/test/nuget/TestModuleComponent1/Greeter.cpp @@ -0,0 +1,8 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import winrt_base; +import winrt.Windows.Foundation; + +#include "Greeter.h" +#include "Greeter.g.cpp" diff --git a/test/nuget/TestModuleComponent1/Greeter.h b/test/nuget/TestModuleComponent1/Greeter.h new file mode 100644 index 000000000..726fb7d22 --- /dev/null +++ b/test/nuget/TestModuleComponent1/Greeter.h @@ -0,0 +1,25 @@ +#pragma once +#include "Greeter.g.h" + +namespace winrt::TestModuleComponent1::implementation +{ + struct Greeter : GreeterT + { + Greeter() : m_name(L"World") {} + Greeter(hstring const& name) : m_name(name) {} + + hstring Name() { return m_name; } + hstring Greet() { return L"Hello, " + m_name + L"!"; } + Windows::Foundation::Uri Homepage() { return Windows::Foundation::Uri(L"https://example.com/" + m_name); } + + private: + hstring m_name; + }; +} + +namespace winrt::TestModuleComponent1::factory_implementation +{ + struct Greeter : GreeterT + { + }; +} diff --git a/test/nuget/TestModuleComponent1/PropertySheet.props b/test/nuget/TestModuleComponent1/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleComponent1/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleComponent1/TestModuleComponent1.def b/test/nuget/TestModuleComponent1/TestModuleComponent1.def new file mode 100644 index 000000000..53d2e7cbf --- /dev/null +++ b/test/nuget/TestModuleComponent1/TestModuleComponent1.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/test/nuget/TestModuleComponent1/TestModuleComponent1.idl b/test/nuget/TestModuleComponent1/TestModuleComponent1.idl new file mode 100644 index 000000000..73a983ee2 --- /dev/null +++ b/test/nuget/TestModuleComponent1/TestModuleComponent1.idl @@ -0,0 +1,12 @@ +namespace TestModuleComponent1 +{ + [default_interface] + runtimeclass Greeter + { + Greeter(); + Greeter(String name); + String Name{ get; }; + String Greet(); + Windows.Foundation.Uri Homepage{ get; }; + } +} diff --git a/test/nuget/TestModuleComponent1/TestModuleComponent1.vcxproj b/test/nuget/TestModuleComponent1/TestModuleComponent1.vcxproj new file mode 100644 index 000000000..669b25ff0 --- /dev/null +++ b/test/nuget/TestModuleComponent1/TestModuleComponent1.vcxproj @@ -0,0 +1,92 @@ + + + + + true + true + true + true + {F54D9A50-84D7-4953-8350-BEFE73CC36F6} + TestModuleComponent1 + TestModuleComponent1 + en-US + 14.0 + + + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + DynamicLibrary + v145 + Unicode + + + false + true + + + + + + + + + + Use + pch.h + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + true + _WINRT_DLL;NOMINMAX;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + false + TestModuleComponent1.def + + + + + + TestModuleComponent1.idl + + + + + Create + + + TestModuleComponent1.idl + + + + + + + + + + + + + true + + + + + diff --git a/test/nuget/TestModuleComponent1/pch.cpp b/test/nuget/TestModuleComponent1/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleComponent1/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleComponent1/pch.h b/test/nuget/TestModuleComponent1/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleComponent1/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestModuleComponent2/GreeterGroup.cpp b/test/nuget/TestModuleComponent2/GreeterGroup.cpp new file mode 100644 index 000000000..7c6410b44 --- /dev/null +++ b/test/nuget/TestModuleComponent2/GreeterGroup.cpp @@ -0,0 +1,9 @@ +#include "pch.h" + +#define WINRT_IMPORT_MODULE +import std; +import winrt.Windows.Foundation; +import winrt.TestModuleComponent1; + +#include "GreeterGroup.h" +#include "GreeterGroup.g.cpp" diff --git a/test/nuget/TestModuleComponent2/GreeterGroup.h b/test/nuget/TestModuleComponent2/GreeterGroup.h new file mode 100644 index 000000000..461570425 --- /dev/null +++ b/test/nuget/TestModuleComponent2/GreeterGroup.h @@ -0,0 +1,36 @@ +#pragma once +#include "GreeterGroup.g.h" + +namespace winrt::TestModuleComponent2::implementation +{ + struct GreeterGroup : GreeterGroupT + { + GreeterGroup() = default; + + void Add(winrt::TestModuleComponent1::Greeter const& greeter) + { + m_greeters.push_back(greeter); + } + + hstring GreetAll() + { + hstring result; + for (auto const& g : m_greeters) + { + if (!result.empty()) result = result + L", "; + result = result + g.Greet(); + } + return result; + } + + private: + std::vector m_greeters; + }; +} + +namespace winrt::TestModuleComponent2::factory_implementation +{ + struct GreeterGroup : GreeterGroupT + { + }; +} diff --git a/test/nuget/TestModuleComponent2/PropertySheet.props b/test/nuget/TestModuleComponent2/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleComponent2/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleComponent2/TestModuleComponent2.def b/test/nuget/TestModuleComponent2/TestModuleComponent2.def new file mode 100644 index 000000000..53d2e7cbf --- /dev/null +++ b/test/nuget/TestModuleComponent2/TestModuleComponent2.def @@ -0,0 +1,3 @@ +EXPORTS +DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE +DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE diff --git a/test/nuget/TestModuleComponent2/TestModuleComponent2.idl b/test/nuget/TestModuleComponent2/TestModuleComponent2.idl new file mode 100644 index 000000000..e45eed438 --- /dev/null +++ b/test/nuget/TestModuleComponent2/TestModuleComponent2.idl @@ -0,0 +1,10 @@ +namespace TestModuleComponent2 +{ + [default_interface] + runtimeclass GreeterGroup + { + GreeterGroup(); + void Add(TestModuleComponent1.Greeter greeter); + String GreetAll(); + } +} diff --git a/test/nuget/TestModuleComponent2/TestModuleComponent2.vcxproj b/test/nuget/TestModuleComponent2/TestModuleComponent2.vcxproj new file mode 100644 index 000000000..ff4982965 --- /dev/null +++ b/test/nuget/TestModuleComponent2/TestModuleComponent2.vcxproj @@ -0,0 +1,93 @@ + + + + + true + true + true + true + {126E9412-E861-47C6-8684-C8F9BF32C0BD} + TestModuleComponent2 + TestModuleComponent2 + en-US + 14.0 + + + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + DynamicLibrary + v145 + Unicode + + + false + true + + + + + + + + + + Use + pch.h + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + true + _WINRT_DLL;NOMINMAX;%(PreprocessorDefinitions) + $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) + + + Console + false + TestModuleComponent2.def + + + + + + TestModuleComponent2.idl + + + + + Create + + + TestModuleComponent2.idl + + + + + + + + + + + + + true + + + + + + diff --git a/test/nuget/TestModuleComponent2/pch.cpp b/test/nuget/TestModuleComponent2/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleComponent2/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleComponent2/pch.h b/test/nuget/TestModuleComponent2/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleComponent2/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestModuleConsumerApp/PropertySheet.props b/test/nuget/TestModuleConsumerApp/PropertySheet.props new file mode 100644 index 000000000..379c2c3a2 --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/PropertySheet.props @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/nuget/TestModuleConsumerApp/TestModuleConsumerApp.vcxproj b/test/nuget/TestModuleConsumerApp/TestModuleConsumerApp.vcxproj new file mode 100644 index 000000000..910586a0c --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/TestModuleConsumerApp.vcxproj @@ -0,0 +1,76 @@ + + + + + true + true + {FB7FEAA7-09DE-465C-BA0E-60374D3EFFD9} + TestModuleConsumerApp + TestModuleConsumerApp + en-US + 14.0 + + + + + Release + Win32 + + + Release + x64 + + + Release + ARM64 + + + + Application + v145 + Unicode + + + false + true + + + + + + + + + + Use + pch.h + stdcpplatest + Level4 + true + %(AdditionalOptions) /bigobj + true + NOMINMAX;%(PreprocessorDefinitions) + + + Console + + + + + + + + Create + + + + + + true + + + + + + + diff --git a/test/nuget/TestModuleConsumerApp/main.cpp b/test/nuget/TestModuleConsumerApp/main.cpp new file mode 100644 index 000000000..da930703b --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/main.cpp @@ -0,0 +1,32 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; +import winrt.TestModuleComponent1; +import winrt.TestModuleComponent2; + +using namespace winrt; +using namespace Windows::Foundation; + +int main() +{ + init_apartment(); + + // Platform types from pre-built modules + Uri uri(L"https://example.com/consumer"); + std::printf("URI: %ls\n", uri.AbsoluteUri().c_str()); + + // Component1 + auto greeter = TestModuleComponent1::Greeter(L"Modules"); + std::printf("Greet: %ls\n", greeter.Greet().c_str()); + std::printf("Homepage: %ls\n", greeter.Homepage().AbsoluteUri().c_str()); + + // Component2 (depends on Component1) + auto group = TestModuleComponent2::GreeterGroup(); + group.Add(TestModuleComponent1::Greeter(L"Alice")); + group.Add(TestModuleComponent1::Greeter(L"Bob")); + std::printf("GreetAll: %ls\n", group.GreetAll().c_str()); + + std::printf("All consumer tests passed.\n"); + return 0; +} diff --git a/test/nuget/TestModuleConsumerApp/pch.cpp b/test/nuget/TestModuleConsumerApp/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestModuleConsumerApp/pch.h b/test/nuget/TestModuleConsumerApp/pch.h new file mode 100644 index 000000000..6f70f09be --- /dev/null +++ b/test/nuget/TestModuleConsumerApp/pch.h @@ -0,0 +1 @@ +#pragma once diff --git a/test/nuget/TestProxyStub/IAsyncContract.idl b/test/nuget/TestProxyStub/IAsyncContract.idl new file mode 100644 index 000000000..0a4ae04b4 --- /dev/null +++ b/test/nuget/TestProxyStub/IAsyncContract.idl @@ -0,0 +1,11 @@ +import "Windows.Foundation.idl"; +import "IAsyncContractParameter.idl"; + +namespace TestProxyStub +{ + [uuid("A388AC69-7C0F-4CCB-B108-E091BE3DAB88")] + interface IAsyncContract + { + Windows.Foundation.IAsyncAction RunAsync(IAsyncContractParameter parameter); + }; +} diff --git a/test/nuget/TestProxyStub/IAsyncContractParameter.idl b/test/nuget/TestProxyStub/IAsyncContractParameter.idl new file mode 100644 index 000000000..b6a3769c3 --- /dev/null +++ b/test/nuget/TestProxyStub/IAsyncContractParameter.idl @@ -0,0 +1,11 @@ +import "Windows.Foundation.idl"; + +namespace TestProxyStub +{ + [uuid("F219AC9A-9858-4F66-8DA7-47A9E08438AC")] + interface IAsyncContractParameter + { + String Name{ get; }; + Object Details{ get; }; + }; +} diff --git a/test/nuget/TestProxyStub/TestProxyStub.def b/test/nuget/TestProxyStub/TestProxyStub.def new file mode 100644 index 000000000..753f222d5 --- /dev/null +++ b/test/nuget/TestProxyStub/TestProxyStub.def @@ -0,0 +1,3 @@ +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE \ No newline at end of file diff --git a/test/nuget/TestProxyStub/TestProxyStub.vcxproj b/test/nuget/TestProxyStub/TestProxyStub.vcxproj new file mode 100644 index 000000000..cd646da7f --- /dev/null +++ b/test/nuget/TestProxyStub/TestProxyStub.vcxproj @@ -0,0 +1,127 @@ + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + 16.0 + Win32Proj + {98E28FC8-2EB7-4544-9B6A-941462C6D3E2} + TestProxyStub + 10.0.22621.0 + 10.0.18362.0 + + false + + + + DynamicLibrary + Unicode + + + + + + + + + WIN32;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + Use + pch.h + %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) + Level4 + true + + + Windows + onecore.lib;onecoreuap.lib;%(AdditionalDependencies) + TestProxyStub.def + + + Stub + Stub + true + $(IntDir)dlldata.c + $(IntDir)%(FileName).h + $(IntDir)%(FileName)_i.c + $(IntDir)%(FileName)_p.c + $(WindowsSDK_UnionMetadataPath) + true + false + + + + + _DEBUG;%(PreprocessorDefinitions) + + + + + NDEBUG;%(PreprocessorDefinitions) + + + + + + + + + + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + NotUsing + + + Create + + + + + + + + false + + + false + + + + + \ No newline at end of file diff --git a/test/nuget/TestProxyStub/pch.cpp b/test/nuget/TestProxyStub/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/nuget/TestProxyStub/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/nuget/TestProxyStub/pch.h b/test/nuget/TestProxyStub/pch.h new file mode 100644 index 000000000..3186dac74 --- /dev/null +++ b/test/nuget/TestProxyStub/pch.h @@ -0,0 +1,8 @@ +// +// pch.h +// Header for platform projection include files +// + +#pragma once + +#include diff --git a/test/nuget/TestRuntimeComponent1/TestRuntimeComponent1.vcxproj b/test/nuget/TestRuntimeComponent1/TestRuntimeComponent1.vcxproj index ddd17f254..b1ee4f43f 100644 --- a/test/nuget/TestRuntimeComponent1/TestRuntimeComponent1.vcxproj +++ b/test/nuget/TestRuntimeComponent1/TestRuntimeComponent1.vcxproj @@ -13,14 +13,12 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 - + Debug - ARM + ARM64 Debug @@ -30,9 +28,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -45,9 +43,6 @@ DynamicLibrary - v140 - v141 - v142 Unicode false @@ -79,6 +74,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj 28204 _WINRT_DLL;%(PreprocessorDefinitions) diff --git a/test/nuget/TestRuntimeComponent2/TestRuntimeComponent2.vcxproj b/test/nuget/TestRuntimeComponent2/TestRuntimeComponent2.vcxproj index 7a7803a82..c27db2602 100644 --- a/test/nuget/TestRuntimeComponent2/TestRuntimeComponent2.vcxproj +++ b/test/nuget/TestRuntimeComponent2/TestRuntimeComponent2.vcxproj @@ -13,15 +13,13 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 -lib $(MSBuildProjectName) - + Debug - ARM + ARM64 Debug @@ -31,9 +29,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -46,9 +44,6 @@ DynamicLibrary - v140 - v141 - v142 Unicode false @@ -80,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj 28204 _WINRT_DLL;%(PreprocessorDefinitions) diff --git a/test/nuget/TestRuntimeComponent3/TestRuntimeComponent3.vcxproj b/test/nuget/TestRuntimeComponent3/TestRuntimeComponent3.vcxproj index e1eb6e53d..01c84d830 100644 --- a/test/nuget/TestRuntimeComponent3/TestRuntimeComponent3.vcxproj +++ b/test/nuget/TestRuntimeComponent3/TestRuntimeComponent3.vcxproj @@ -13,15 +13,13 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 -lib $(MSBuildProjectName) - + Debug - ARM + ARM64 Debug @@ -31,9 +29,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -46,9 +44,6 @@ DynamicLibrary - v140 - v141 - v142 Unicode false @@ -80,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj 28204 _WINRT_DLL;%(PreprocessorDefinitions) diff --git a/test/nuget/TestRuntimeComponentCSharp/TestRuntimeComponentCSharp.csproj b/test/nuget/TestRuntimeComponentCSharp/TestRuntimeComponentCSharp.csproj index 869819889..167b32ad9 100644 --- a/test/nuget/TestRuntimeComponentCSharp/TestRuntimeComponentCSharp.csproj +++ b/test/nuget/TestRuntimeComponentCSharp/TestRuntimeComponentCSharp.csproj @@ -11,8 +11,8 @@ TestRuntimeComponentCSharp en-US UAP - 10.0.18362.0 - 10.0.15063.0 + $(WindowsSDKVersion.TrimEnd('\')) + 10.0.18362.0 14 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -36,24 +36,6 @@ false prompt - - ARM - true - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - false - prompt - - - ARM - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - false - prompt - ARM64 true @@ -98,9 +80,7 @@ - - 5.4.7 - + 14.0 @@ -113,4 +93,4 @@ --> - \ No newline at end of file + diff --git a/test/nuget/TestRuntimeComponentCX/TestRuntimeComponentCX.vcxproj b/test/nuget/TestRuntimeComponentCX/TestRuntimeComponentCX.vcxproj index 81767d259..819cff52b 100644 --- a/test/nuget/TestRuntimeComponentCX/TestRuntimeComponentCX.vcxproj +++ b/test/nuget/TestRuntimeComponentCX/TestRuntimeComponentCX.vcxproj @@ -2,10 +2,6 @@ - - Debug - ARM - Debug ARM64 @@ -18,10 +14,6 @@ Debug x64 - - Release - ARM - Release ARM64 @@ -43,15 +35,11 @@ 14.0 true Windows Store - 10.0.18362.0 - 10.0.18362.0 10.0 DynamicLibrary - v141 - v142 true @@ -73,12 +61,6 @@ - - - - - - @@ -99,12 +81,6 @@ false - - false - - - false - false @@ -124,9 +100,11 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -140,41 +118,11 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - true - - - Console - false - - - - - Use - _WINRT_DLL;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - true - - - Console - false - - - - - Use - _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -188,9 +136,11 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -204,9 +154,11 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -220,9 +172,11 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -236,9 +190,11 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) 28204 true + Level4 + true Console @@ -255,8 +211,6 @@ Create Create Create - Create - Create Create Create diff --git a/test/nuget/TestRuntimeComponentCXReferencingWinRTStaticLibrary/TestRuntimeComponentCXReferencingWinRTStaticLibrary.vcxproj b/test/nuget/TestRuntimeComponentCXReferencingWinRTStaticLibrary/TestRuntimeComponentCXReferencingWinRTStaticLibrary.vcxproj index 8864e69c1..6ce188345 100644 --- a/test/nuget/TestRuntimeComponentCXReferencingWinRTStaticLibrary/TestRuntimeComponentCXReferencingWinRTStaticLibrary.vcxproj +++ b/test/nuget/TestRuntimeComponentCXReferencingWinRTStaticLibrary/TestRuntimeComponentCXReferencingWinRTStaticLibrary.vcxproj @@ -2,10 +2,6 @@ - - Debug - ARM - Debug ARM64 @@ -18,10 +14,6 @@ Debug x64 - - Release - ARM - Release ARM64 @@ -43,8 +35,6 @@ 14.0 true Windows Store - 10.0.18362.0 - 10.0.18362.0 10.0 C++/CX @@ -52,46 +42,29 @@ DynamicLibrary true - v142 - - - DynamicLibrary - true - v142 DynamicLibrary true - v142 DynamicLibrary true - v142 DynamicLibrary false true - v142 - - - DynamicLibrary - false - true - v142 DynamicLibrary false true - v142 DynamicLibrary false true - v142 @@ -104,12 +77,6 @@ - - - - - - @@ -130,12 +97,6 @@ false - - false - - - false - false @@ -155,7 +116,9 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -170,37 +133,9 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - false - - - - - Use - _WINRT_DLL;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) - 28204 - - - Console - false - - - - - Use - _WINRT_DLL;NDEBUG;%(PreprocessorDefinitions) - pch.h - $(IntDir)pch.pch - $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -215,7 +150,9 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -230,7 +167,9 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -245,7 +184,9 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -260,7 +201,9 @@ pch.h $(IntDir)pch.pch $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) - /bigobj %(AdditionalOptions) + /bigobj /Zc:twoPhase- %(AdditionalOptions) + Level4 + true 28204 @@ -278,8 +221,6 @@ Create Create Create - Create - Create Create Create diff --git a/test/nuget/TestRuntimeComponentEmpty/TestRuntimeComponentEmpty.vcxproj b/test/nuget/TestRuntimeComponentEmpty/TestRuntimeComponentEmpty.vcxproj index 073c8fd0c..60786eddb 100644 --- a/test/nuget/TestRuntimeComponentEmpty/TestRuntimeComponentEmpty.vcxproj +++ b/test/nuget/TestRuntimeComponentEmpty/TestRuntimeComponentEmpty.vcxproj @@ -13,15 +13,13 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 -lib $(MSBuildProjectName) - + Debug - ARM + ARM64 Debug @@ -31,9 +29,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -46,9 +44,6 @@ DynamicLibrary - v140 - v141 - v142 Unicode false @@ -80,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj 28204 _WINRT_DLL;%(PreprocessorDefinitions) diff --git a/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore.vcxproj b/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore.vcxproj index dae6dcfed..fb8146340 100644 --- a/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore.vcxproj +++ b/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore.vcxproj @@ -14,14 +14,12 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 - + Debug - ARM + ARM64 Debug @@ -31,9 +29,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -46,9 +44,6 @@ DynamicLibrary - v140 - v141 - v142 Unicode false @@ -80,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj _WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) diff --git a/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore_TemporaryKey.pfx b/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore_TemporaryKey.pfx deleted file mode 100644 index dac97059a..000000000 Binary files a/test/nuget/TestRuntimeComponentNamespaceUnderscore/TestRuntimeComponentNamespaceUnderscore_TemporaryKey.pfx and /dev/null differ diff --git a/test/nuget/TestRuntimeComponentNamespaceUnderscore/packages.config b/test/nuget/TestRuntimeComponentNamespaceUnderscore/packages.config deleted file mode 100644 index 17dbbb252..000000000 --- a/test/nuget/TestRuntimeComponentNamespaceUnderscore/packages.config +++ /dev/null @@ -1,4 +0,0 @@ -īģŋ - - - \ No newline at end of file diff --git a/test/nuget/TestStaticLibrary1/TestStaticLibrary1.vcxproj b/test/nuget/TestStaticLibrary1/TestStaticLibrary1.vcxproj index ec6dcd3fc..13ac4e201 100644 --- a/test/nuget/TestStaticLibrary1/TestStaticLibrary1.vcxproj +++ b/test/nuget/TestStaticLibrary1/TestStaticLibrary1.vcxproj @@ -14,15 +14,13 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 -lib $(MSBuildProjectName) - + Debug - ARM + ARM64 Debug @@ -32,9 +30,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -47,8 +45,6 @@ StaticLibrary - v141 - v142 true @@ -74,10 +70,10 @@ - + - + @@ -85,6 +81,7 @@ Use Level4 + true Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) @@ -102,6 +99,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -115,10 +113,11 @@ true - + Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -136,6 +135,7 @@ Use Level4 + true MaxSpeed true true @@ -157,6 +157,7 @@ Use Level4 + true MaxSpeed true true @@ -174,10 +175,11 @@ true - + Use Level4 + true MaxSpeed true true @@ -206,10 +208,10 @@ Create Create - Create + Create Create Create - Create + Create TestStaticLibrary1Class.idl diff --git a/test/nuget/TestStaticLibrary2/TestStaticLibrary2.vcxproj b/test/nuget/TestStaticLibrary2/TestStaticLibrary2.vcxproj index e5ed5219f..b419d183e 100644 --- a/test/nuget/TestStaticLibrary2/TestStaticLibrary2.vcxproj +++ b/test/nuget/TestStaticLibrary2/TestStaticLibrary2.vcxproj @@ -14,15 +14,13 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 -lib $(MSBuildProjectName) - + Debug - ARM + ARM64 Debug @@ -32,9 +30,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -47,8 +45,6 @@ StaticLibrary - v141 - v142 true @@ -74,10 +70,10 @@ - + - + @@ -85,6 +81,7 @@ Use Level4 + true Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) @@ -102,6 +99,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -115,10 +113,11 @@ true - + Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -136,6 +135,7 @@ Use Level4 + true MaxSpeed true true @@ -157,6 +157,7 @@ Use Level4 + true MaxSpeed true true @@ -174,10 +175,11 @@ true - + Use Level4 + true MaxSpeed true true @@ -206,10 +208,10 @@ Create Create - Create + Create Create Create - Create + Create TestStaticLibrary2Class.idl diff --git a/test/nuget/TestStaticLibrary3/TestStaticLibrary3.vcxproj b/test/nuget/TestStaticLibrary3/TestStaticLibrary3.vcxproj index 4ee9932f4..210802841 100644 --- a/test/nuget/TestStaticLibrary3/TestStaticLibrary3.vcxproj +++ b/test/nuget/TestStaticLibrary3/TestStaticLibrary3.vcxproj @@ -14,15 +14,13 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 -lib $(MSBuildProjectName) - + Debug - ARM + ARM64 Debug @@ -32,9 +30,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -47,8 +45,6 @@ StaticLibrary - v141 - v142 true @@ -74,10 +70,10 @@ - + - + @@ -85,6 +81,7 @@ Use Level4 + true Disabled true WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) @@ -102,6 +99,7 @@ Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -115,10 +113,11 @@ true - + Use Level4 + true Disabled true _DEBUG;_LIB;%(PreprocessorDefinitions) @@ -136,6 +135,7 @@ Use Level4 + true MaxSpeed true true @@ -157,6 +157,7 @@ Use Level4 + true MaxSpeed true true @@ -174,10 +175,11 @@ true - + Use Level4 + true MaxSpeed true true @@ -206,10 +208,10 @@ Create Create - Create + Create Create Create - Create + Create TestStaticLibrary3Class.idl diff --git a/test/nuget/TestStaticLibrary4/TestStaticLibrary4.vcxproj b/test/nuget/TestStaticLibrary4/TestStaticLibrary4.vcxproj index 86fea6326..357d0ca70 100644 --- a/test/nuget/TestStaticLibrary4/TestStaticLibrary4.vcxproj +++ b/test/nuget/TestStaticLibrary4/TestStaticLibrary4.vcxproj @@ -2,9 +2,9 @@ - + Debug - ARM + ARM64 Debug @@ -14,9 +14,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -38,16 +38,12 @@ 14.0 true Windows Store - 10.0.18362.0 - 10.0.18362.0 10.0 -lib $(MSBuildProjectName) StaticLibrary - v141 - v142 true @@ -69,10 +65,10 @@ - + - + @@ -89,10 +85,10 @@ false - + false - + false @@ -106,6 +102,8 @@ Use false true + Level4 + true Console @@ -118,6 +116,8 @@ Use false true + Level4 + true Console @@ -125,11 +125,13 @@ false - + Use false true + Level4 + true Console @@ -137,11 +139,13 @@ false - + Use false true + Level4 + true Console @@ -154,6 +158,8 @@ Use false true + Level4 + true Console @@ -166,6 +172,8 @@ Use false true + Level4 + true Console @@ -185,10 +193,10 @@ Create Create - Create - Create Create Create + Create + Create Create Create diff --git a/test/nuget/TestStaticLibrary5/TestStaticLibrary5.vcxproj b/test/nuget/TestStaticLibrary5/TestStaticLibrary5.vcxproj index 92a8a9336..d93446a05 100644 --- a/test/nuget/TestStaticLibrary5/TestStaticLibrary5.vcxproj +++ b/test/nuget/TestStaticLibrary5/TestStaticLibrary5.vcxproj @@ -2,9 +2,9 @@ - + Debug - ARM + ARM64 Debug @@ -14,9 +14,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -38,16 +38,12 @@ 14.0 true Windows Store - 10.0.18362.0 - 10.0.18362.0 10.0 -lib $(MSBuildProjectName) StaticLibrary - v141 - v142 true @@ -69,10 +65,10 @@ - + - + @@ -89,10 +85,10 @@ false - + false - + false @@ -106,6 +102,8 @@ Use false true + Level4 + true Console @@ -118,6 +116,8 @@ Use false true + Level4 + true Console @@ -125,11 +125,13 @@ false - + Use false true + Level4 + true Console @@ -137,11 +139,13 @@ false - + Use false true + Level4 + true Console @@ -154,6 +158,8 @@ Use false true + Level4 + true Console @@ -166,6 +172,8 @@ Use false true + Level4 + true Console @@ -185,10 +193,10 @@ Create Create - Create - Create Create Create + Create + Create Create Create diff --git a/test/nuget/TestStaticLibrary6/TestStaticLibrary6.vcxproj b/test/nuget/TestStaticLibrary6/TestStaticLibrary6.vcxproj index e085518b4..626e60dab 100644 --- a/test/nuget/TestStaticLibrary6/TestStaticLibrary6.vcxproj +++ b/test/nuget/TestStaticLibrary6/TestStaticLibrary6.vcxproj @@ -2,9 +2,9 @@ - + Debug - ARM + ARM64 Debug @@ -14,9 +14,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -38,16 +38,12 @@ 14.0 true Windows Store - 10.0.18362.0 - 10.0.18362.0 10.0 -lib $(MSBuildProjectName) StaticLibrary - v141 - v142 true @@ -69,10 +65,10 @@ - + - + @@ -89,10 +85,10 @@ false - + false - + false @@ -106,6 +102,8 @@ Use false true + Level4 + true Console @@ -118,6 +116,8 @@ Use false true + Level4 + true Console @@ -125,11 +125,13 @@ false - + Use false true + Level4 + true Console @@ -137,11 +139,13 @@ false - + Use false true + Level4 + true Console @@ -154,6 +158,8 @@ Use false true + Level4 + true Console @@ -166,6 +172,8 @@ Use false true + Level4 + true Console @@ -189,10 +197,10 @@ Create Create - Create - Create Create Create + Create + Create Create Create diff --git a/test/nuget/TestStaticLibrary7/TestStaticLibrary7.vcxproj b/test/nuget/TestStaticLibrary7/TestStaticLibrary7.vcxproj index c94b507ee..85d6bec7f 100644 --- a/test/nuget/TestStaticLibrary7/TestStaticLibrary7.vcxproj +++ b/test/nuget/TestStaticLibrary7/TestStaticLibrary7.vcxproj @@ -1,6 +1,6 @@ - + true true @@ -15,14 +15,12 @@ true Windows Store 10.0 - 10.0.18362.0 - 10.0.17134.0 - + Debug - ARM + ARM64 Debug @@ -32,9 +30,9 @@ Debug x64 - + Release - ARM + ARM64 Release @@ -47,9 +45,6 @@ StaticLibrary - v140 - v141 - v142 Unicode false @@ -81,6 +76,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) @@ -132,13 +128,6 @@ - + - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - diff --git a/test/nuget/TestStaticLibrary7/packages.config b/test/nuget/TestStaticLibrary7/packages.config deleted file mode 100644 index c4867c30b..000000000 --- a/test/nuget/TestStaticLibrary7/packages.config +++ /dev/null @@ -1,4 +0,0 @@ -īģŋ - - - \ No newline at end of file diff --git a/test/old_tests/CMakeLists.txt b/test/old_tests/CMakeLists.txt new file mode 100644 index 000000000..e1af6d31c --- /dev/null +++ b/test/old_tests/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(UnitTests) diff --git a/test/old_tests/Component/Component.idl b/test/old_tests/Component/Component.idl index 157297ee9..ad51b5303 100644 --- a/test/old_tests/Component/Component.idl +++ b/test/old_tests/Component/Component.idl @@ -243,11 +243,13 @@ namespace Component HRESULT Create([in] Windows.Foundation.Collections.IVectorView* _in, [out, retval] FastInputVector** _out); }; + midl_pragma warning(disable: 4066) // A member name has been qualified with an interface name because name collisions occurred across interface members on a runtime class. + [version(1.0), activatable(IFastInputVectorFactory, 1.0)] runtimeclass FastInputVector { // Don't confuse this for a high-performance vector. This is for testing fast-input binding support. - // The default interface is intentionally not one of the collection intefaces to force them to be convertible for testing. + // The default interface is intentionally not one of the collection interfaces to force them to be convertible for testing. [default] interface Windows.Foundation.IClosable; interface Windows.Foundation.Collections.IVector; interface Windows.Foundation.Collections.IVectorView; @@ -265,12 +267,14 @@ namespace Component runtimeclass FastInputMap { // Don't confuse this for a high-performance map. This is for testing fast-input binding support. - // The default interface is intentionally not one of the collection intefaces to force them to be convertible for testing. + // The default interface is intentionally not one of the collection interfaces to force them to be convertible for testing. [default] interface Windows.Foundation.IClosable; interface Windows.Foundation.Collections.IMap; interface Windows.Foundation.Collections.IMapView; }; + midl_pragma warning(default: 4066) + // // Boxing support for enums and their underlying types. // diff --git a/test/old_tests/Component/Component.vcxproj b/test/old_tests/Component/Component.vcxproj index 560a73c4e..162c8fec7 100644 --- a/test/old_tests/Component/Component.vcxproj +++ b/test/old_tests/Component/Component.vcxproj @@ -1,10 +1,6 @@ -īģŋ + - - Debug - ARM - Debug ARM64 @@ -17,10 +13,6 @@ Debug x64 - - Release - ARM - Release ARM64 @@ -39,19 +31,13 @@ {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8} Win32Proj Component - 10.0 - + DynamicLibrary true x64 - - DynamicLibrary - true - x64 - DynamicLibrary true @@ -68,12 +54,6 @@ true x64 - - DynamicLibrary - false - true - x64 - DynamicLibrary false @@ -94,18 +74,12 @@ - - - - - - @@ -120,58 +94,36 @@ false false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - Midl - $(OutDir)temp\$(ProjectName)\ - - - false - false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl false false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl false false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - Midl - $(OutDir)temp\$(ProjectName)\ - - - false - false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl false false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl false false - ..\..;$(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); Midl - $(OutDir)temp\$(ProjectName)\ false false - ..\..;$(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); Midl - $(OutDir)temp\$(ProjectName)\ - $(OutputPath)cppwinrt.exe -in $(OutputPath)Component.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk $(OutputPath)Composable.winmd -verbose + $(CppWinRTDir)cppwinrt.exe -in $(OutputPath)Component.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk $(OutputPath)Composable.winmd -verbose C++/WinRT compiler Generated Files\module.g.cpp $(OutputPath)Component.winmd @@ -188,6 +140,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -215,42 +169,6 @@ - - - false - $(ProjectDir);$(OutputPath);Generated Files;..\Composable\Generated Files - false - MultiThreadedDebug - NOMINMAX;_WINDLL;%(PreprocessorDefinitions) - 4100;4297;4458 - - - Console - false - module.def - true - - - - - - - - - ..\Composable - - - - - - - - - - - - - false @@ -258,6 +176,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -293,6 +213,8 @@ $(ProjectDir);$(OutputPath);Generated Files;..\Composable\Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -320,47 +242,14 @@ - - - false - $(ProjectDir);$(OutputPath);Generated Files;..\Composable\Generated Files - MultiThreaded - NOMINMAX;_WINDLL;%(PreprocessorDefinitions) - 4100;4297;4458 - - - Console - false - module.def - true - - - - - - - - - ..\Composable - - - - - - - - - - - - - false $(ProjectDir);$(OutputPath);Generated Files;..\Composable\Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -397,6 +286,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -430,6 +321,8 @@ $(ProjectDir);$(OutputPath);Generated Files;..\Composable\Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 @@ -483,50 +376,38 @@ $(SystemRoot)\System32\WinMetadata - $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata - $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata $(OutputPath)$(ProjectName).winmd - $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd - $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd true - true true true - true true true true $(OutputPath)$(ProjectName)_h.h - $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h - $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h ..\Composable - ..\Composable ..\Composable ..\Composable - ..\Composable ..\Composable ..\Composable ..\Composable true - true true true - true true true true diff --git a/test/old_tests/Component/pch.h b/test/old_tests/Component/pch.h index 7d1624884..b73230946 100644 --- a/test/old_tests/Component/pch.h +++ b/test/old_tests/Component/pch.h @@ -1,9 +1,14 @@ īģŋ#pragma once +#ifdef _MSC_VER #pragma warning(disable:4100) +#endif #include "winrt/Windows.Foundation.Collections.h" #include "winrt/Composable.h" // This is used to validate WRL interop support. +#pragma warning(push) +#pragma warning(disable: 4324) // structure was padded due to alignment specifier #include +#pragma warning(pop) \ No newline at end of file diff --git a/test/old_tests/Composable/Base.cpp b/test/old_tests/Composable/Base.cpp index 77ded2403..af2423569 100644 --- a/test/old_tests/Composable/Base.cpp +++ b/test/old_tests/Composable/Base.cpp @@ -41,6 +41,11 @@ namespace winrt::Composable::implementation return 42; } + int32_t Base::ProtectedMethod() + { + return static_cast(0xDEADBEEF); + } + hstring Base::Name() const { return m_name; diff --git a/test/old_tests/Composable/Base.h b/test/old_tests/Composable/Base.h index bbc05d820..4b23c6c88 100644 --- a/test/old_tests/Composable/Base.h +++ b/test/old_tests/Composable/Base.h @@ -18,6 +18,7 @@ namespace winrt::Composable::implementation hstring OverridableMethod() ; virtual hstring OverridableVirtualMethod(); int32_t OverridableNoexceptMethod() noexcept; + int32_t ProtectedMethod(); hstring Name() const; diff --git a/test/old_tests/Composable/Composable.idl b/test/old_tests/Composable/Composable.idl index 83e0c5868..7f298e195 100644 --- a/test/old_tests/Composable/Composable.idl +++ b/test/old_tests/Composable/Composable.idl @@ -39,10 +39,17 @@ namespace Composable HRESULT OverridableVirtualMethod([out, retval] HSTRING* value); [noexcept2] HRESULT OverridableNoexceptMethod([out, retval] int* value); }; + + [version(1.0), uuid(6EA77EAE-56BC-419D-AE70-211C1A631496), exclusiveto(Base)] + interface IBaseProtected : IInspectable + { + HRESULT ProtectedMethod([out, retval] int* value); + }; [version(1.0), uuid(5f3996e1-3cf7-4716-9a3d-11eb5d32caff), exclusiveto(Derived)] interface IDerived : IInspectable { + HRESULT CallProtectedMethod([out, retval] int* value); }; [version(1.0), uuid(56dc2c28-edd1-4fa3-91e5-f63c3db47070), exclusiveto(Derived)] @@ -60,6 +67,7 @@ namespace Composable { [default] interface IBase; [overridable] interface Composable.IBaseOverrides; + [protected] interface Composable.IBaseProtected; }; [composable(Composable.IDerivedFactory, public, 1.0)] diff --git a/test/old_tests/Composable/Composable.vcxproj b/test/old_tests/Composable/Composable.vcxproj index fb299024e..fcfd095fc 100644 --- a/test/old_tests/Composable/Composable.vcxproj +++ b/test/old_tests/Composable/Composable.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -17,10 +13,6 @@ Debug x64 - - Release - ARM - Release ARM64 @@ -39,19 +31,13 @@ {152e4c6e-9a9d-4d5a-b38d-4905d173649a} Win32Proj Composable - 10.0 - + DynamicLibrary true x64 - - DynamicLibrary - true - x64 - DynamicLibrary true @@ -68,12 +54,6 @@ true x64 - - DynamicLibrary - false - true - x64 - DynamicLibrary false @@ -94,18 +74,12 @@ - - - - - - @@ -120,58 +94,36 @@ false false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - Midl - $(OutDir)temp\$(ProjectName)\ - - - false - false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl false false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl false false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - Midl - $(OutDir)temp\$(ProjectName)\ - - - false - false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl false false - ..\..;$(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl false false - ..\..;$(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); Midl - $(OutDir)temp\$(ProjectName)\ false false - ..\..;$(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); Midl - $(OutDir)temp\$(ProjectName)\ - $(OutDir)cppwinrt.exe -in $(OutDir)Composable.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk -verbose -pch precomp.hpp -name Composable + $(CppWinRTDir)cppwinrt.exe -in $(OutDir)Composable.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk -verbose -pch precomp.hpp -name Composable C++/WinRT compiler Generated Files\module.g.cpp $(OutDir)Composable.winmd @@ -188,6 +140,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -215,42 +169,6 @@ - - - false - $(ProjectDir);$(OutDir);Generated Files - false - MultiThreadedDebug - NOMINMAX;_WINDLL;%(PreprocessorDefinitions) - 4100;4297;4458 - precomp.hpp - - - Console - false - module.def - true - - - - - - - - - - - - - - - - - - - - - false @@ -258,6 +176,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -293,6 +213,8 @@ $(ProjectDir);$(OutDir);Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -320,47 +242,14 @@ - - - false - $(ProjectDir);$(OutDir);Generated Files - MultiThreaded - NOMINMAX;_WINDLL;%(PreprocessorDefinitions) - 4100;4297;4458 - precomp.hpp - - - Console - false - module.def - true - - - - - - - - - - - - - - - - - - - - - false $(ProjectDir);$(OutDir);Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -397,6 +286,8 @@ false MultiThreadedDebug NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -430,6 +321,8 @@ $(ProjectDir);$(OutDir);Generated Files MultiThreaded NOMINMAX;_WINDLL;%(PreprocessorDefinitions) + Level4 + true 4100;4297;4458 precomp.hpp @@ -475,42 +368,32 @@ $(SystemRoot)\System32\WinMetadata - $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata - $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata $(SystemRoot)\System32\WinMetadata $(OutputPath)$(ProjectName).winmd - $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd - $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd $(OutputPath)$(ProjectName).winmd true - true true true - true true true true $(OutputPath)$(ProjectName)_h.h - $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h - $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h $(OutputPath)$(ProjectName)_h.h true - true true true - true true true true diff --git a/test/old_tests/Composable/Derived.cpp b/test/old_tests/Composable/Derived.cpp index b4c74e433..19fdbcc77 100644 --- a/test/old_tests/Composable/Derived.cpp +++ b/test/old_tests/Composable/Derived.cpp @@ -12,4 +12,9 @@ namespace winrt::Composable::implementation { return L"Derived::OverridableVirtualMethod"; } + + int32_t Derived::CallProtectedMethod() + { + return ProtectedMethod(); + } } diff --git a/test/old_tests/Composable/Derived.h b/test/old_tests/Composable/Derived.h index ff6d7778f..7d2463c81 100644 --- a/test/old_tests/Composable/Derived.h +++ b/test/old_tests/Composable/Derived.h @@ -14,6 +14,7 @@ namespace winrt::Composable::implementation hstring VirtualMethod() override; hstring OverridableVirtualMethod() override; + int32_t CallProtectedMethod(); }; } diff --git a/test/old_tests/Composable/precomp.hpp b/test/old_tests/Composable/precomp.hpp index aa5d110c2..29f44db46 100644 --- a/test/old_tests/Composable/precomp.hpp +++ b/test/old_tests/Composable/precomp.hpp @@ -1,6 +1,8 @@ īģŋ#pragma once +#ifdef _MSC_VER #pragma warning(disable:4100) +#endif #include "winrt/Windows.Foundation.h" #include "winrt/Composable.h" diff --git a/test/old_tests/UnitTests/Boxing2.cpp b/test/old_tests/UnitTests/Boxing2.cpp index cd912ce58..43ca7efd9 100644 --- a/test/old_tests/UnitTests/Boxing2.cpp +++ b/test/old_tests/UnitTests/Boxing2.cpp @@ -41,19 +41,19 @@ namespace REQUIRE(unbox_value_or(wrong_type, v2) == v2); } - REQUIRE(object.as() == v1); - REQUIRE(object.try_as() == v1); - REQUIRE(nothing.try_as() == std::nullopt); + REQUIRE(object.template as() == v1); + REQUIRE(object.template try_as() == v1); + REQUIRE(nothing.template try_as() == std::nullopt); REQUIRE(wrong_type.try_as() == std::nullopt); T result{ v2 }; - object.as(result); + object.template as(result); REQUIRE(result == v1); result = v1; REQUIRE(v1 != empty()); // Test must pass a v1 that is not equal to the empty value. - REQUIRE(!nothing.try_as(result)); + REQUIRE(!nothing.template try_as(result)); REQUIRE(result == empty()); // try_as explicitly empties the result on failure result = v1; diff --git a/test/old_tests/UnitTests/CMakeLists.txt b/test/old_tests/UnitTests/CMakeLists.txt new file mode 100644 index 000000000..908691653 --- /dev/null +++ b/test/old_tests/UnitTests/CMakeLists.txt @@ -0,0 +1,63 @@ +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(Main|pch)\\.cpp") + + +# We can't build custom Component for mingw-w64 because it doesn't have an +# alternative to midl that can produce winmd files. +list(APPEND BROKEN_TESTS + Boxing2 + Composable + Errors + Events + FastInput + Parameters + StructCodeGen + Structures + delegate_weak_strong + factory_cache + get_activation_factory + smart_pointers +) + +list(APPEND BROKEN_TESTS + # Missing `Windows.Applicationmodel.Activation.h` + constexpr + + # Missing `Windows.ApplicationModel.Appointments.h` + enum_flags + + # Missing component `Reflect`. + # Test is also not included in the VS project. + reflect + + # Segfault in winrt::impl::natvis::abi_val. + # Test is also not included in the VS project. + natvis +) + +# Exclude broken tests +foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS) + list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp") +endforeach() + +add_executable(test_old Main.cpp ${TEST_SRCS}) +target_link_libraries(test_old runtimeobject synchronization) + +if(NOT SKIP_LARGE_PCH) + target_precompile_headers(test_old PRIVATE pch.h) + set_source_files_properties( + conditional_implements_pure.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true + ) +endif() + +add_dependencies(test_old build-cppwinrt-projection) + +add_test( + NAME test_old + COMMAND "$" ${TEST_COLOR_ARG} +) diff --git a/test/old_tests/UnitTests/Composable.cpp b/test/old_tests/UnitTests/Composable.cpp index 56fc97e1c..a9d354c08 100644 --- a/test/old_tests/UnitTests/Composable.cpp +++ b/test/old_tests/UnitTests/Composable.cpp @@ -14,6 +14,7 @@ namespace constexpr auto Base_OverridableMethod{ L"Base::OverridableMethod"sv }; constexpr auto Base_OverridableVirtualMethod{ L"Base::OverridableVirtualMethod"sv }; constexpr auto Base_OverridableNoexceptMethod{ 42 }; + constexpr auto Base_ProtectedMethod{ static_cast(0xDEADBEEF) }; constexpr auto Derived_VirtualMethod{ L"Derived::VirtualMethod"sv }; constexpr auto Derived_OverridableVirtualMethod{ L"Derived::OverridableVirtualMethod"sv }; @@ -61,12 +62,20 @@ TEST_CASE("Composable.OverriddenBase") { return OverriddenBase_OverridableNoexceptMethod; } + + int32_t CallProtectedMethod() + { + return ProtectedMethod(); + } }; - auto object = make(); + + auto object_self = make_self(); + auto object = object_self.as(); REQUIRE(object.VirtualMethod() == Base_VirtualMethod); REQUIRE(object.CallOverridableMethod() == OverriddenBase_OverridableMethod); REQUIRE(object.CallOverridableVirtualMethod() == OverriddenBase_OverridableVirtualMethod); REQUIRE(object.CallOverridableNoexceptMethod() == OverriddenBase_OverridableNoexceptMethod); + REQUIRE(object_self->CallProtectedMethod() == Base_ProtectedMethod); } { const std::wstring OverridableMethodResult = std::wstring(OverriddenBase_OverridableMethod) + L"=>" + Base_OverridableMethod.data(); @@ -106,6 +115,7 @@ TEST_CASE("Composable.Derived") REQUIRE(obj.CallOverridableMethod() == Base_OverridableMethod); REQUIRE(obj.CallOverridableVirtualMethod() == Derived_OverridableVirtualMethod); REQUIRE(obj.CallOverridableNoexceptMethod() == Base_OverridableNoexceptMethod); + REQUIRE(obj.CallProtectedMethod() == Base_ProtectedMethod); } namespace @@ -133,10 +143,44 @@ namespace CallIDerived(obj); CallDerived(obj); } + + template + struct has_ProtectedMember : std::false_type { }; + + template + struct has_ProtectedMember>> : std::true_type { }; + + // make sure we can't access protected members directly + static_assert(!has_ProtectedMember::value); + static_assert(!has_ProtectedMember::value); + static_assert(!has_ProtectedMember::value); + static_assert(!has_ProtectedMember::value); + + // make sure we can't implicitly convert to IBaseProtected + static_assert(!std::is_convertible_v); + static_assert(!std::is_convertible_v); + static_assert(!std::is_convertible_v); + static_assert(!std::is_convertible_v); } TEST_CASE("Composable conversions") { TestCalls(*make_self()); TestCalls(*make_self()); -} \ No newline at end of file +} + +TEST_CASE("Composable get_interfaces") +{ + struct Foo : Composable::BaseT { + hstring ToString() const { return L"Foo"; } + }; + + auto obj = make(); + auto iids = winrt::get_interfaces(obj); + // BaseOverrides IID gets repeated twice. There are only 4 unique interfaces. + REQUIRE(iids.size() == 5); + REQUIRE(std::find(iids.begin(), iids.end(), guid_of()) != iids.end()); + REQUIRE(std::find(iids.begin(), iids.end(), guid_of()) != iids.end()); + REQUIRE(std::find(iids.begin(), iids.end(), guid_of()) != iids.end()); + REQUIRE(std::find(iids.begin(), iids.end(), guid_of()) != iids.end()); +} diff --git a/test/old_tests/UnitTests/Errors.cpp b/test/old_tests/UnitTests/Errors.cpp index 85a2d2a60..f8656a508 100644 --- a/test/old_tests/UnitTests/Errors.cpp +++ b/test/old_tests/UnitTests/Errors.cpp @@ -66,7 +66,9 @@ void test_exception(HRESULT const code, std::wstring_view message) } } +#ifdef _MSC_VER #pragma warning(disable: 4702) // unreachable code +#endif TEST_CASE("Errors") { // These won't throw. @@ -93,7 +95,7 @@ TEST_CASE("Errors") try { init_apartment(apartment_type::single_threaded); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const & e) { @@ -104,7 +106,7 @@ TEST_CASE("Errors") try { Uri uri(L"BAD"); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const & e) // catching specific exception type { @@ -115,7 +117,7 @@ TEST_CASE("Errors") try { Uri uri(L"BAD"); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const& e) { @@ -128,7 +130,7 @@ TEST_CASE("Errors") { Errors errors; errors.Propagate(); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const & e) // catching specific exception type { @@ -140,7 +142,7 @@ TEST_CASE("Errors") { Errors errors; errors.Fail(L"Failure message"); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_not_implemented const& e) { @@ -158,7 +160,7 @@ TEST_CASE("Errors") { Errors errors; errors.std_out_of_range(); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_out_of_bounds const& e) { @@ -169,7 +171,7 @@ TEST_CASE("Errors") { Errors errors; errors.std_invalid_argument(); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const& e) { @@ -180,7 +182,7 @@ TEST_CASE("Errors") { Errors errors; errors.std_exception(); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const& e) { @@ -200,6 +202,8 @@ TEST_CASE("Errors") SetLastError(ERROR_CANCELLED); REQUIRE_THROWS_AS(check_bool(static_cast(false)), hresult_canceled); + REQUIRE(check_bool(true) == true); + // Support for Win32 errors. check_win32(ERROR_SUCCESS); REQUIRE_THROWS_AS(check_win32(ERROR_CANCELLED), hresult_canceled); @@ -207,7 +211,7 @@ TEST_CASE("Errors") try { check_win32(ERROR_NO_NETWORK); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const& e) { @@ -220,7 +224,7 @@ TEST_CASE("Errors") try { check_nt(STATUS_STACK_OVERFLOW); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const& e) { @@ -229,6 +233,7 @@ TEST_CASE("Errors") // Make sure trimming works. hresult_error e(E_FAIL, L":) is \u263A \n \t "); + auto x = e.message(); REQUIRE(e.message() == L":) is \u263A"); // Make sure delegates propagate correctly. diff --git a/test/old_tests/UnitTests/Hash.cpp b/test/old_tests/UnitTests/Hash.cpp index 756beacab..7464da6ab 100644 --- a/test/old_tests/UnitTests/Hash.cpp +++ b/test/old_tests/UnitTests/Hash.cpp @@ -1,5 +1,5 @@ #include "pch.h" -#include "winrt\Windows.Foundation.h" +#include "winrt/Windows.Foundation.h" #include "catch.hpp" #include #include diff --git a/test/old_tests/UnitTests/IInspectable_GetRuntimeClassName.cpp b/test/old_tests/UnitTests/IInspectable_GetRuntimeClassName.cpp index 7db7ed869..53b5260fb 100644 --- a/test/old_tests/UnitTests/IInspectable_GetRuntimeClassName.cpp +++ b/test/old_tests/UnitTests/IInspectable_GetRuntimeClassName.cpp @@ -18,10 +18,17 @@ struct Test_GetRuntimeClassName_NoOverride : implements { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Woverloaded-virtual" +#endif hstring GetRuntimeClassName() { return L"GetRuntimeClassName"; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif }; TEST_CASE("Test_GetRuntimeClassName_NoOverride") diff --git a/test/old_tests/UnitTests/IReference.cpp b/test/old_tests/UnitTests/IReference.cpp index 50a349f89..cc03c5b9b 100644 --- a/test/old_tests/UnitTests/IReference.cpp +++ b/test/old_tests/UnitTests/IReference.cpp @@ -1,7 +1,9 @@ #include "pch.h" #include "catch.hpp" +#ifdef _MSC_VER #pragma warning(disable:4471) // a forward declaration of an unscoped enumeration must have an underlying type +#endif #include using namespace winrt; @@ -55,4 +57,4 @@ TEST_CASE("IReference, set WinRT runtime class property") { HttpContentDispositionHeaderValue value(L"inline"); value.Size(200); -} \ No newline at end of file +} diff --git a/test/old_tests/UnitTests/Main.cpp b/test/old_tests/UnitTests/Main.cpp index de63b39fc..60b1eb6d8 100644 --- a/test/old_tests/UnitTests/Main.cpp +++ b/test/old_tests/UnitTests/Main.cpp @@ -1,6 +1,11 @@ +#include #include "pch.h" #define CATCH_CONFIG_RUNNER + +// Force reportFatal to be available on mingw-w64 +#define CATCH_CONFIG_WINDOWS_SEH + #include "catch.hpp" int main(int argc, char * argv[]) @@ -9,6 +14,11 @@ int main(int argc, char * argv[]) init_apartment(); std::set_terminate([]{ reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + SetThreadUILanguage(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); int const result = Catch::Session().run(argc, argv); // Completely unnecessary in an app, but useful for testing clear_factory_cache behavior. @@ -31,3 +41,8 @@ int main(int argc, char * argv[]) uninit_apartment(); return result; } + +CATCH_TRANSLATE_EXCEPTION(winrt::hresult_error const& e) +{ + return to_string(e.message()); +} diff --git a/test/old_tests/UnitTests/Tests.vcxproj b/test/old_tests/UnitTests/Tests.vcxproj index 85aadb456..c5169ad4d 100644 --- a/test/old_tests/UnitTests/Tests.vcxproj +++ b/test/old_tests/UnitTests/Tests.vcxproj @@ -1,10 +1,6 @@ īģŋ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -118,6 +110,7 @@ + @@ -137,20 +130,14 @@ {C8B95FCB-9B0B-4E9F-B7D5-643883C192C9} Win32Proj Tests - 10.0 test_old - + Application true x64 - - Application - true - x64 - Application true @@ -162,12 +149,6 @@ x64 true - - Application - false - x64 - true - Application false @@ -193,18 +174,12 @@ - - - - - - @@ -215,34 +190,12 @@ - + true - $(OutDir)temp\$(ProjectName)\ - - true - - - true - - - true - $(OutDir)temp\$(ProjectName)\ - - - false - $(OutDir)temp\$(ProjectName)\ - - + false - - false - - - false - $(OutDir)temp\$(ProjectName)\ - Disabled @@ -253,25 +206,8 @@ false false MultiThreadedDebug - 4100;4297;4458 - - - Console - true - false - $(OutDir)test_old.exe - - - - - Disabled - _HAS_AUTO_PTR_ETC;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(OutputPath);..\Composable\Generated Files;..\Component\Generated Files;..\Composable;..\Reflection\Generated Files;..\..\; - ProgramDatabase - Default - false - false - MultiThreadedDebug + Level4 + true 4100;4297;4458 @@ -291,6 +227,8 @@ false false MultiThreadedDebug + Level4 + true 4100;4297;4458 @@ -310,6 +248,8 @@ false false MultiThreadedDebug + Level4 + true 4100;4297;4458 @@ -327,25 +267,8 @@ _HAS_AUTO_PTR_ETC;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(OutputPath);..\Composable\Generated Files;..\Component\Generated Files;..\Composable;..\Reflection\Generated Files;..\..\; MultiThreaded - 4100;4297;4458 - - - Console - true - true - true - false - $(OutDir)test_old.exe - - - - - MaxSpeed - true - true - _HAS_AUTO_PTR_ETC;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(OutputPath);..\Composable\Generated Files;..\Component\Generated Files;..\Composable;..\Reflection\Generated Files;..\..\; - MultiThreaded + Level4 + true 4100;4297;4458 @@ -365,6 +288,8 @@ _HAS_AUTO_PTR_ETC;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(OutputPath);..\Composable\Generated Files;..\Component\Generated Files;..\Composable;..\Reflection\Generated Files;..\..\; MultiThreaded + Level4 + true 4100;4297;4458 @@ -384,6 +309,8 @@ _HAS_AUTO_PTR_ETC;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) $(OutputPath);..\Composable\Generated Files;..\Component\Generated Files;..\Composable;..\Reflection\Generated Files;..\..\; MultiThreaded + Level4 + true 4100;4297;4458 diff --git a/test/old_tests/UnitTests/Tests.vcxproj.filters b/test/old_tests/UnitTests/Tests.vcxproj.filters index 3e95c4a98..e1a6813a5 100644 --- a/test/old_tests/UnitTests/Tests.vcxproj.filters +++ b/test/old_tests/UnitTests/Tests.vcxproj.filters @@ -88,6 +88,7 @@ + diff --git a/test/old_tests/UnitTests/TryLookup.cpp b/test/old_tests/UnitTests/TryLookup.cpp index 3c6c54580..350fa9006 100644 --- a/test/old_tests/UnitTests/TryLookup.cpp +++ b/test/old_tests/UnitTests/TryLookup.cpp @@ -143,4 +143,129 @@ TEST_CASE("TryLookup TryRemove error") REQUIRE(!map.TryLookup(123)); REQUIRE(!map.TryRemove(123)); -} \ No newline at end of file +} + +TEST_CASE("trylookup_from_abi specialization") +{ + // A map that throws a specific error, used to verify various edge cases. + // and implements tryLookup, to take advantage of an optimization to avoid a throw. + struct map_with_try_lookup : implements> + { + hresult codeToThrow{ S_OK }; + bool shouldThrowOnTryLookup{ false }; + std::optional TryLookup(int, trylookup_from_abi_t) + { + if (shouldThrowOnTryLookup) + { + throw_hresult(codeToThrow); + } + else + { + return { std::nullopt }; + } + } + int Lookup(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + int32_t Size() { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + bool HasKey(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + void Split(IMapView&, IMapView&) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + }; + + auto self = make_self(); + IMapView map = *self; + + // Make sure that we use the TryLookup specialization, and don't throw an unexpected exception. + self->shouldThrowOnTryLookup = false; + REQUIRE(!map.TryLookup(123)); + // make sure regular lookup stll throws bounds + REQUIRE_THROWS_AS(map.Lookup(123), hresult_out_of_bounds); + + // Simulate a non-agile map that is being accessed from the wrong thread. + // "Try" operations should throw rather than erroneously report "not found". + // Because they didn't even try. The operation never got off the ground. + self->shouldThrowOnTryLookup = true; + self->codeToThrow = RPC_E_WRONG_THREAD; + REQUIRE_THROWS_AS(map.TryLookup(123), hresult_wrong_thread); + // regular lookup should throw the same error + REQUIRE_THROWS_AS(map.Lookup(123), hresult_wrong_thread); +} + +TEST_CASE("trylookup_from_abi NOT opt-in, no special tag") +{ + // Makes sure that an existing TryLookup method is not called without the trylookup_from_abi_t tag. + struct map_without_try_lookup : implements> + { + hresult codeToThrow{ S_OK }; + std::optional TryLookup(int) // notice no trylookup_from_abi_t, so no opt-in + { + // throw an unexpectd hresult, this should not be called. + throw_hresult(RPC_E_WRONG_THREAD); + } + int Lookup(int) { return 42; } // Behave as if the item was found + + int32_t Size() { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + bool HasKey(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + void Split(IMapView&, IMapView&) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + }; + + auto self = make_self(); + IMapView map = *self; + + // Make sure that we don't use the TryLookup specialization, we use the Successful Lookup + REQUIRE(map.TryLookup(123).value() == 42); + REQUIRE(map.Lookup(123) == 42); +} + +TEST_CASE("trylookup_from_abi specialization with IInspectable") +{ + // A map that throws a specific error, used to verify various edge cases. + // and implements tryLookup, to take advantage of an optimization to avoid a throw. + struct map_with_try_lookup : implements> + { + hresult codeToThrow{ S_OK }; + bool shouldThrowOnTryLookup{ false }; + bool returnNullptr{ false }; + std::optional TryLookup(int, trylookup_from_abi_t) + { + if (returnNullptr) + { + return { nullptr }; + } + else if (shouldThrowOnTryLookup) + { + throw_hresult(codeToThrow); + } + else + { + return { std::nullopt }; + } + } + IInspectable Lookup(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + int32_t Size() { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + bool HasKey(int) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + void Split(IMapView&, IMapView&) { throw_hresult(E_UNEXPECTED); } // shouldn't be called by the test + }; + + auto self = make_self(); + IMapView map = *self; + + // Ensure that we return a value on nullptr, a nullptr is a valid IInspectable in the Map + self->returnNullptr = true; + REQUIRE(map.TryLookup(123) == IInspectable{nullptr}); + REQUIRE(map.Lookup(123) == IInspectable{nullptr}); + + // Make sure that we use the TryLookup specialization, and don't throw an unexpected exception. + self->shouldThrowOnTryLookup = false; + self->returnNullptr = false; + REQUIRE(map.TryLookup(123) == IInspectable{nullptr}); + // make sure regular lookup stll throws bounds + REQUIRE_THROWS_AS(map.Lookup(123), hresult_out_of_bounds); + + // Simulate a non-agile map that is being accessed from the wrong thread. + // "Try" operations should throw rather than erroneously report "not found". + // Because they didn't even try. The operation never got off the ground. + self->shouldThrowOnTryLookup = true; + self->codeToThrow = RPC_E_WRONG_THREAD; + REQUIRE_THROWS_AS(map.TryLookup(123), hresult_wrong_thread); + // regular lookup should throw the same error + REQUIRE_THROWS_AS(map.Lookup(123), hresult_wrong_thread); +} diff --git a/test/old_tests/UnitTests/VariadicDelegate.cpp b/test/old_tests/UnitTests/VariadicDelegate.cpp index af5f86e2a..47c5da0fc 100644 --- a/test/old_tests/UnitTests/VariadicDelegate.cpp +++ b/test/old_tests/UnitTests/VariadicDelegate.cpp @@ -101,7 +101,7 @@ TEST_CASE("Variadic delegate - event") TEST_CASE("Variadic delegate - exception") { - delegate<> d = [] { throw std::exception("what"); }; + delegate<> d = [] { throw std::runtime_error("what"); }; REQUIRE_THROWS_AS(d(), std::exception); } @@ -120,4 +120,4 @@ TEST_CASE("Variadic delegate - object") REQUIRE(object.m_state == 0); d(123); REQUIRE(object.m_state == 123); -} \ No newline at end of file +} diff --git a/test/old_tests/UnitTests/abi_guard.cpp b/test/old_tests/UnitTests/abi_guard.cpp index 3108baf62..70800323c 100644 --- a/test/old_tests/UnitTests/abi_guard.cpp +++ b/test/old_tests/UnitTests/abi_guard.cpp @@ -12,7 +12,7 @@ using namespace Windows::Foundation; namespace { // - // This implemenetation uses the simplest abi_enter and abi_exit methods. + // This implementation uses the simplest abi_enter and abi_exit methods. // struct A : implements { @@ -60,7 +60,7 @@ namespace } // - // This implemenetation uses the abi_enter but omits the abi_exit method. + // This implementation uses the abi_enter but omits the abi_exit method. // struct B : implements { @@ -102,7 +102,7 @@ namespace } // - // This implemenetation throws from the abi_enter method. + // This implementation throws from the abi_enter method. // struct C : implements { @@ -145,7 +145,7 @@ namespace } // - // This implemenetation provides a nested abi_guard + // This implementation provides a nested abi_guard // struct D : implements { @@ -223,7 +223,7 @@ namespace }; // - // This implemenetation use an abi_guard type alias + // This implementation use an abi_guard type alias // struct E : implements { @@ -275,7 +275,7 @@ namespace }; // - // This implemenetation use an abi_guard type alias that thows + // This implementation use an abi_guard type alias that throws // struct F : implements { diff --git a/test/old_tests/UnitTests/agile_ref.cpp b/test/old_tests/UnitTests/agile_ref.cpp index cfb97bb50..13f76e17f 100644 --- a/test/old_tests/UnitTests/agile_ref.cpp +++ b/test/old_tests/UnitTests/agile_ref.cpp @@ -36,7 +36,15 @@ IAsyncAction test_agile_ref() }); } +#if defined(__clang__) && defined(_MSC_VER) && (defined(_M_IX86) || defined(__i386__)) +// FIXME: Test is known to crash from calling invalid address on x86 when built with Clang. +TEST_CASE("agile_ref", "[.clang-crash]") +#elif defined(__GNUC__) && !defined(__clang__) +// FIXME: Test is known to randomly crash or abort when built with GCC (segfaults under appverifier). +TEST_CASE("agile_ref", "[.gcc-crash]") +#else TEST_CASE("agile_ref") +#endif { test_agile_ref().get(); } diff --git a/test/old_tests/UnitTests/apartment_context.cpp b/test/old_tests/UnitTests/apartment_context.cpp index e7c152fd2..1bdab7c8b 100644 --- a/test/old_tests/UnitTests/apartment_context.cpp +++ b/test/old_tests/UnitTests/apartment_context.cpp @@ -35,6 +35,11 @@ namespace context2 = nullptr; REQUIRE(!context2); +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#pragma clang diagnostic ignored "-Wself-move" +#endif // Self-copy-assignment context = context; REQUIRE(context); @@ -42,10 +47,18 @@ namespace // Self-move-assignment context = std::move(context); REQUIRE(context); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif co_await context; } +// Not yet buildable on mingw-w64. The lambda needs to have __stdcall +// specified on it but there is a Clang crash bug blocking this: +// https://github.com/llvm/llvm-project/issues/58366 +#if !defined(__MINGW32__) + template void InvokeInContext(IContextCallback* context, TLambda&& lambda) { @@ -69,6 +82,10 @@ namespace return context; } +#endif + +// Exclude on mingw-w64 to suppress `-Wunused-function` +#if !defined(__MINGW32__) bool is_nta_on_mta() { APTTYPE type; @@ -76,6 +93,7 @@ namespace check_hresult(CoGetApartmentType(&type, &qualifier)); return (type == APTTYPE_NA) && (qualifier == APTTYPEQUALIFIER_NA_ON_MTA || qualifier == APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA); } +#endif bool is_mta() { @@ -90,6 +108,10 @@ namespace return (hr == RPC_E_SERVER_DIED_DNE) || (hr == RPC_E_DISCONNECTED); } +// Not yet buildable on mingw-w64. +// Missing __uuidof(IContextCallback). +#if !defined(__MINGW32__) + IAsyncAction TestNeutralApartmentContext() { auto controller = DispatcherQueueController::CreateOnDedicatedThread(); @@ -102,6 +124,8 @@ namespace REQUIRE(is_nta_on_mta()); } +#endif + IAsyncAction TestStaToStaApartmentContext() { bool pass = false; @@ -245,17 +269,28 @@ TEST_CASE("apartment_context coverage") Async().get(); } +// Not yet buildable on mingw-w64. +// Missing __uuidof(IContextCallback). +#if !defined(__MINGW32__) + TEST_CASE("apartment_context nta") { TestNeutralApartmentContext().get(); } +#endif + TEST_CASE("apartment_context sta") { TestStaToStaApartmentContext().get(); } +#if defined(__clang__) && defined(_MSC_VER) && (defined(_M_IX86) || defined(__i386__)) +// FIXME: Test is known to segfault on x86 when built with Clang. +TEST_CASE("apartment_context disconnected", "[.clang-crash]") +#else TEST_CASE("apartment_context disconnected") +#endif { TestDisconnectedApartmentContext().get(); } diff --git a/test/old_tests/UnitTests/array.cpp b/test/old_tests/UnitTests/array.cpp index bb3901564..2b5952004 100644 --- a/test/old_tests/UnitTests/array.cpp +++ b/test/old_tests/UnitTests/array.cpp @@ -17,7 +17,7 @@ using namespace Windows::Security::Cryptography::Certificates; // // This is a helper to create a data reader for use in testing arrays. // -static IAsyncOperation CreateDataReader(std::initializer_list values) +static IAsyncOperation CreateDataReader(std::initializer_list /*values*/) { InMemoryRandomAccessStream stream; DataWriter writer(stream); @@ -344,7 +344,7 @@ TEST_CASE("array,at,throw") try { a.at(3); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (std::out_of_range const & e) { @@ -357,7 +357,7 @@ TEST_CASE("array,at,throw") try { test_array_ref_at_throw({ 1, 2, 3 }); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (std::out_of_range const & e) { @@ -372,7 +372,7 @@ TEST_CASE("array,at,throw") try { a.at(5); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (std::out_of_range const & e) { @@ -941,13 +941,20 @@ TEST_CASE("array_view,cv array_view") array_view a2 = a; REQUIRE(a2.data() == a.data()); REQUIRE(a2.size() == 3); + // For libc++ as of LLVM 15, std::equal is unable to compare between + // volatile and non-volatile elements of ranges. + // https://github.com/llvm/llvm-project/issues/59021 +#if !defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 160000 REQUIRE(a2 == a); +#endif } { array_view a2 = a; REQUIRE(a2.data() == a.data()); REQUIRE(a2.size() == 3); +#if !defined(_LIBCPP_VERSION) || _LIBCPP_VERSION >= 160000 REQUIRE(a2 == a); +#endif } } diff --git a/test/old_tests/UnitTests/as_implements.cpp b/test/old_tests/UnitTests/as_implements.cpp index 4c99631fb..60b27342f 100644 --- a/test/old_tests/UnitTests/as_implements.cpp +++ b/test/old_tests/UnitTests/as_implements.cpp @@ -138,3 +138,13 @@ TEST_CASE("as_implements_inheritance") REQUIRE(bar.get() == foo2.get()); } } + +TEST_CASE("convert_to_implements_via_uniform_initialization") +{ + // uniform initialization relies on IStringable(IStringable&&), + // which requires non-const rvalue semantics. + com_ptr foo = make_self(); + IStringable stringable{ *foo }; + com_ptr foo2 = stringable.as(); + REQUIRE(foo.get() == foo2.get()); +} diff --git a/test/old_tests/UnitTests/async.cpp b/test/old_tests/UnitTests/async.cpp index 4452e6db4..7a7382004 100644 --- a/test/old_tests/UnitTests/async.cpp +++ b/test/old_tests/UnitTests/async.cpp @@ -391,7 +391,12 @@ namespace #endif } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Throw_IAsyncAction", "[.clang-crash]") +#else TEST_CASE("async, Throw_IAsyncAction") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncAction async = Throw_IAsyncAction(event.get()); @@ -431,7 +436,12 @@ TEST_CASE("async, Throw_IAsyncAction") } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Throw_IAsyncAction, 2", "[.clang-crash]") +#else TEST_CASE("async, Throw_IAsyncAction, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncAction async = Throw_IAsyncAction(event.get()); @@ -472,7 +482,12 @@ TEST_CASE("async, Throw_IAsyncAction, 2") } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Throw_IAsyncActionWithProgress", "[.clang-crash]") +#else TEST_CASE("async, Throw_IAsyncActionWithProgress") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncActionWithProgress async = Throw_IAsyncActionWithProgress(event.get()); @@ -512,7 +527,12 @@ TEST_CASE("async, Throw_IAsyncActionWithProgress") } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Throw_IAsyncActionWithProgress, 2", "[.clang-crash]") +#else TEST_CASE("async, Throw_IAsyncActionWithProgress, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncActionWithProgress async = Throw_IAsyncActionWithProgress(event.get()); @@ -553,7 +573,12 @@ TEST_CASE("async, Throw_IAsyncActionWithProgress, 2") } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Throw_IAsyncOperation", "[.clang-crash]") +#else TEST_CASE("async, Throw_IAsyncOperation") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperation async = Throw_IAsyncOperation(event.get()); @@ -593,7 +618,12 @@ TEST_CASE("async, Throw_IAsyncOperation") } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Throw_IAsyncOperation, 2", "[.clang-crash]") +#else TEST_CASE("async, Throw_IAsyncOperation, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperation async = Throw_IAsyncOperation(event.get()); @@ -634,7 +664,12 @@ TEST_CASE("async, Throw_IAsyncOperation, 2") } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Throw_IAsyncOperationWithProgress", "[.clang-crash]") +#else TEST_CASE("async, Throw_IAsyncOperationWithProgress") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperationWithProgress async = Throw_IAsyncOperationWithProgress(event.get()); @@ -674,7 +709,12 @@ TEST_CASE("async, Throw_IAsyncOperationWithProgress") } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Throw_IAsyncOperationWithProgress, 2", "[.clang-crash]") +#else TEST_CASE("async, Throw_IAsyncOperationWithProgress, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperationWithProgress async = Throw_IAsyncOperationWithProgress(event.get()); @@ -767,7 +807,12 @@ namespace } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Cancel_IAsyncAction", "[.clang-crash]") +#else TEST_CASE("async, Cancel_IAsyncAction") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncAction async = Cancel_IAsyncAction(event.get()); @@ -797,7 +842,12 @@ TEST_CASE("async, Cancel_IAsyncAction") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Cancel_IAsyncAction, 2", "[.clang-crash]") +#else TEST_CASE("async, Cancel_IAsyncAction, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncAction async = Cancel_IAsyncAction(event.get()); @@ -827,7 +877,12 @@ TEST_CASE("async, Cancel_IAsyncAction, 2") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Cancel_IAsyncActionWithProgress", "[.clang-crash]") +#else TEST_CASE("async, Cancel_IAsyncActionWithProgress") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncActionWithProgress async = Cancel_IAsyncActionWithProgress(event.get()); @@ -858,7 +913,12 @@ TEST_CASE("async, Cancel_IAsyncActionWithProgress") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Cancel_IAsyncActionWithProgress, 2", "[.clang-crash]") +#else TEST_CASE("async, Cancel_IAsyncActionWithProgress, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncActionWithProgress async = Cancel_IAsyncActionWithProgress(event.get()); @@ -889,7 +949,12 @@ TEST_CASE("async, Cancel_IAsyncActionWithProgress, 2") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Cancel_IAsyncOperation", "[.clang-crash]") +#else TEST_CASE("async, Cancel_IAsyncOperation") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperation async = Cancel_IAsyncOperation(event.get()); @@ -919,7 +984,12 @@ TEST_CASE("async, Cancel_IAsyncOperation") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Cancel_IAsyncOperation, 2", "[.clang-crash]") +#else TEST_CASE("async, Cancel_IAsyncOperation, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperation async = Cancel_IAsyncOperation(event.get()); @@ -949,7 +1019,12 @@ TEST_CASE("async, Cancel_IAsyncOperation, 2") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Cancel_IAsyncOperationWithProgress", "[.clang-crash]") +#else TEST_CASE("async, Cancel_IAsyncOperationWithProgress") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperationWithProgress async = Cancel_IAsyncOperationWithProgress(event.get()); @@ -980,7 +1055,12 @@ TEST_CASE("async, Cancel_IAsyncOperationWithProgress") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, Cancel_IAsyncOperationWithProgress, 2", "[.clang-crash]") +#else TEST_CASE("async, Cancel_IAsyncOperationWithProgress, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperationWithProgress async = Cancel_IAsyncOperationWithProgress(event.get()); @@ -1012,7 +1092,7 @@ TEST_CASE("async, Cancel_IAsyncOperationWithProgress, 2") } // -// These tests confirm the implicit cancelation behavior. The obeservable behavior should be the same as above +// These tests confirm the implicit cancelation behavior. The observable behavior should be the same as above // but the implementation relies on an exception so we confirm that the state changes occur as before. // @@ -1032,7 +1112,7 @@ namespace { signal_done d{ go }; co_await resume_on_signal(go); - co_await std::experimental::suspend_never{}; + co_await std::suspend_never{}; REQUIRE(false); } @@ -1040,7 +1120,7 @@ namespace { signal_done d{ go }; co_await resume_on_signal(go); - co_await std::experimental::suspend_never{}; + co_await std::suspend_never{}; REQUIRE(false); } @@ -1048,7 +1128,7 @@ namespace { signal_done d{ go }; co_await resume_on_signal(go); - co_await std::experimental::suspend_never{}; + co_await std::suspend_never{}; REQUIRE(false); co_return 0; } @@ -1057,13 +1137,18 @@ namespace { signal_done d{ go }; co_await resume_on_signal(go); - co_await std::experimental::suspend_never{}; + co_await std::suspend_never{}; REQUIRE(false); co_return 0; } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, AutoCancel_IAsyncAction", "[.clang-crash]") +#else TEST_CASE("async, AutoCancel_IAsyncAction") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncAction async = AutoCancel_IAsyncAction(event.get()); @@ -1091,7 +1176,12 @@ TEST_CASE("async, AutoCancel_IAsyncAction") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, AutoCancel_IAsyncAction, 2", "[.clang-crash]") +#else TEST_CASE("async, AutoCancel_IAsyncAction, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncAction async = AutoCancel_IAsyncAction(event.get()); @@ -1119,7 +1209,12 @@ TEST_CASE("async, AutoCancel_IAsyncAction, 2") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("", "[.clang-crash]") +#else TEST_CASE("async, AutoCancel_IAsyncActionWithProgress") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncActionWithProgress async = AutoCancel_IAsyncActionWithProgress(event.get()); @@ -1147,7 +1242,12 @@ TEST_CASE("async, AutoCancel_IAsyncActionWithProgress") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, AutoCancel_IAsyncActionWithProgress, 2", "[.clang-crash]") +#else TEST_CASE("async, AutoCancel_IAsyncActionWithProgress, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncActionWithProgress async = AutoCancel_IAsyncActionWithProgress(event.get()); @@ -1175,7 +1275,12 @@ TEST_CASE("async, AutoCancel_IAsyncActionWithProgress, 2") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, AutoCancel_IAsyncOperation", "[.clang-crash]") +#else TEST_CASE("async, AutoCancel_IAsyncOperation") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperation async = AutoCancel_IAsyncOperation(event.get()); @@ -1203,7 +1308,12 @@ TEST_CASE("async, AutoCancel_IAsyncOperation") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, AutoCancel_IAsyncOperation, 2", "[.clang-crash]") +#else TEST_CASE("async, AutoCancel_IAsyncOperation, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperation async = AutoCancel_IAsyncOperation(event.get()); @@ -1231,7 +1341,12 @@ TEST_CASE("async, AutoCancel_IAsyncOperation, 2") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, AutoCancel_IAsyncOperationWithProgress", "[.clang-crash]") +#else TEST_CASE("async, AutoCancel_IAsyncOperationWithProgress") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperationWithProgress async = AutoCancel_IAsyncOperationWithProgress(event.get()); @@ -1259,7 +1374,12 @@ TEST_CASE("async, AutoCancel_IAsyncOperationWithProgress") REQUIRE(statusMatches); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, AutoCancel_IAsyncOperationWithProgress, 2", "[.clang-crash]") +#else TEST_CASE("async, AutoCancel_IAsyncOperationWithProgress, 2") +#endif { handle event { CreateEvent(nullptr, false, false, nullptr)}; IAsyncOperationWithProgress async = AutoCancel_IAsyncOperationWithProgress(event.get()); @@ -1317,7 +1437,12 @@ TEST_CASE("async, get, suspend with success") REQUIRE(456 == d.get()); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async, get, failure", "[.clang-crash]") +#else TEST_CASE("async, get, failure") +#endif { handle event{ CreateEvent(nullptr, true, false, nullptr) }; SetEvent(event.get()); @@ -1403,10 +1528,10 @@ namespace { IAsyncAction test_resume_after(uint32_t & before, uint32_t & after) { - co_await 0s; // should not suspend + co_await resume_after(0s); // should not suspend before = GetCurrentThreadId(); - co_await 1us; // should suspend and resume on background thread + co_await resume_after(1us); // should suspend and resume on background thread after = GetCurrentThreadId(); } } @@ -1435,10 +1560,12 @@ namespace co_await resume_on_signal(signal); // should not suspend because already signaled REQUIRE(caller == GetCurrentThreadId()); // still on calling thread - REQUIRE(false == co_await resume_on_signal(signal, 1us)); // should suspend but timeout + bool suspend_but_timeout_result = co_await resume_on_signal(signal, 1us); + REQUIRE(false == suspend_but_timeout_result); // should suspend but timeout REQUIRE(caller != GetCurrentThreadId()); // now on background thread - REQUIRE(true == co_await resume_on_signal(signal, 1s)); // should eventually succeed + bool suspend_and_succeed_result = co_await resume_on_signal(signal, 1s); + REQUIRE(true == suspend_and_succeed_result); // should eventually succeed } } diff --git a/test/old_tests/UnitTests/async_cancel.cpp b/test/old_tests/UnitTests/async_cancel.cpp index 515b5fcff..1464b6c4e 100644 --- a/test/old_tests/UnitTests/async_cancel.cpp +++ b/test/old_tests/UnitTests/async_cancel.cpp @@ -122,7 +122,12 @@ TEST_CASE("async_cancel_no_async") REQUIRE(a.Status() == AsyncStatus::Completed); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async_cancel_before_callback", "[.clang-crash]") +#else TEST_CASE("async_cancel_before_callback") +#endif { handle begin{ CreateEvent(nullptr, true, false, nullptr) }; handle end{ CreateEvent(nullptr, true, false, nullptr) }; @@ -139,7 +144,12 @@ TEST_CASE("async_cancel_before_callback") REQUIRE(async.Status() == AsyncStatus::Canceled); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to randomly crash when built with Clang. +TEST_CASE("async_cancel_after_callback", "[.clang-crash]") +#else TEST_CASE("async_cancel_after_callback") +#endif { handle end{ CreateEvent(nullptr, true, false, nullptr) }; handle callback{ CreateEvent(nullptr, true, false, nullptr) }; @@ -154,7 +164,12 @@ TEST_CASE("async_cancel_after_callback") REQUIRE(async.Status() == AsyncStatus::Canceled); } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async_cancel_use_status", "[.clang-crash]") +#else TEST_CASE("async_cancel_use_status") +#endif { // Validate that co_await preserves cancellation. handle complete{ CreateEvent(nullptr, true, false, nullptr) }; diff --git a/test/old_tests/UnitTests/capture.cpp b/test/old_tests/UnitTests/capture.cpp index 936f5ed77..3cfa2a684 100644 --- a/test/old_tests/UnitTests/capture.cpp +++ b/test/old_tests/UnitTests/capture.cpp @@ -4,12 +4,17 @@ using namespace winrt; using namespace Windows::Foundation; -struct __declspec(uuid("5fb96f8d-409c-42a9-99a7-8a95c1459dbd")) ICapture : ::IUnknown +struct DECLSPEC_UUID("5fb96f8d-409c-42a9-99a7-8a95c1459dbd") ICapture : ::IUnknown { virtual int32_t __stdcall GetValue() noexcept = 0; virtual int32_t __stdcall CreateMemberCapture(int32_t value, GUID const& iid, void** object) noexcept = 0; + virtual int32_t __stdcall CreateMemberCapture2(int32_t value, GUID const& iid, ::IUnknown** object) noexcept = 0; }; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(ICapture, 0x5fb96f8d, 0x409c, 0x42a9, 0x99, 0xa7, 0x8a, 0x95, 0xc1, 0x45, 0x9d, 0xbd) +#endif + struct Capture : implements { int32_t const m_value{}; @@ -29,6 +34,12 @@ struct Capture : implements auto capture = make(value); return capture->QueryInterface(iid, object); } + + int32_t __stdcall CreateMemberCapture2(int32_t value, GUID const& iid, ::IUnknown** object) noexcept override + { + auto capture = make(value); + return capture->QueryInterface(iid, reinterpret_cast(object)); + } }; HRESULT __stdcall CreateCapture(int value, GUID const& iid, void** object) noexcept @@ -37,6 +48,12 @@ HRESULT __stdcall CreateCapture(int value, GUID const& iid, void** object) noexc return capture->QueryInterface(iid, object); } +HRESULT __stdcall CreateCapture2(int value, GUID const& iid, ::IInspectable** object) noexcept +{ + auto capture = make(value); + return capture->QueryInterface(iid, reinterpret_cast(object)); +} + TEST_CASE("capture") { // Capture from global function. @@ -63,6 +80,19 @@ TEST_CASE("capture") com_ptr d; + // Capture with an unconventional result type. + auto e = capture(a, &ICapture::CreateMemberCapture2, 30); + REQUIRE(e->GetValue() == 30); + e = nullptr; + e.capture(a, &ICapture::CreateMemberCapture2, 40); + REQUIRE(e->GetValue() == 40); + + com_ptr f = capture(CreateCapture2, 10); + REQUIRE(f->GetValue() == 10); + f = nullptr; + f.capture(CreateCapture2, 20); + REQUIRE(a->GetValue() == 20); + REQUIRE_THROWS_AS(capture(CreateCapture, 0), hresult_no_interface); REQUIRE_THROWS_AS(d.capture(CreateCapture, 0), hresult_no_interface); REQUIRE_THROWS_AS(capture(a, &ICapture::CreateMemberCapture, 0), hresult_no_interface); @@ -100,6 +130,19 @@ TEST_CASE("try_capture") com_ptr d; + // Capture with an unconventional result type. + auto e = try_capture(a, &ICapture::CreateMemberCapture2, 30); + REQUIRE(e->GetValue() == 30); + e = nullptr; + REQUIRE(e.try_capture(a, &ICapture::CreateMemberCapture2, 40)); + REQUIRE(e->GetValue() == 40); + + com_ptr f = try_capture(CreateCapture2, 10); + REQUIRE(f->GetValue() == 10); + f = nullptr; + REQUIRE(f.try_capture(CreateCapture2, 20)); + REQUIRE(f->GetValue() == 20); + REQUIRE(!try_capture(CreateCapture, 0)); REQUIRE(!d.try_capture(CreateCapture, 0)); REQUIRE(!try_capture(a, &ICapture::CreateMemberCapture, 0)); diff --git a/test/old_tests/UnitTests/clock.cpp b/test/old_tests/UnitTests/clock.cpp index c18b5431a..2898d34af 100644 --- a/test/old_tests/UnitTests/clock.cpp +++ b/test/old_tests/UnitTests/clock.cpp @@ -17,6 +17,18 @@ namespace winrt } } +// To confirm that two clocks have the same epoch, we +// capture one clock, then the other, then the first again, +// and verify that the three timestamps are ordered. This avoids +// spurious failures if a test machine is slow or experiences a +// clock tick at just the wrong time. +// +// We use a duration_cast to milliseconds so that the assertion +// failure message tells us how many milliseconds of error we encountered. +#define REQUIRE_ORDERED(a, b, c) \ + REQUIRE(duration_cast((b) - (a)).count() >= 0); \ + REQUIRE(duration_cast((c) - (b)).count() >= 0) + namespace Catch { template @@ -46,11 +58,13 @@ namespace Catch TEST_CASE("clock, now") { - Calendar calendar; - calendar.SetToNow(); + // Confirm that clock::now agrees with Calendar::SetToNow. + Calendar calendar1; + calendar1.SetToNow(); auto time = clock::now(); - auto diff = calendar.GetDateTime() - time; - REQUIRE(abs(diff) < milliseconds{ 100 }); + Calendar calendar2; + calendar2.SetToNow(); + REQUIRE_ORDERED(calendar1.GetDateTime(), time, calendar2.GetDateTime()); } TEST_CASE("clock, units") @@ -66,72 +80,73 @@ TEST_CASE("clock, units") TEST_CASE("clock, time_t") { + const DateTime now1_dt = clock::now(); + const time_t now_tt = time(nullptr); + const DateTime now2_dt = clock::now(); + // Round trip from DateTime to time_t and back. // confirm that nothing happens other than truncating the fractional seconds - const DateTime now_dt = clock::now(); - REQUIRE(clock::from_time_t(clock::to_time_t(now_dt)) == time_point_cast(now_dt)); + REQUIRE(clock::from_time_t(clock::to_time_t(now1_dt)) == time_point_cast(now1_dt)); // Same thing in reverse - const time_t now_tt = time(nullptr); REQUIRE(clock::to_time_t(clock::from_time_t(now_tt)) == now_tt); // Conversions are verified to be consistent. Now, verify that we're correctly converting epochs - const auto diff = abs(clock::now() - clock::from_time_t(time(nullptr))); - REQUIRE(diff < seconds{ 1 }); + // Note that time_t has only 1s resolution, so we need to add 2 seconds of slop on either side. + // (One second for measurement error, and another second for rounding error.) + REQUIRE_ORDERED(now1_dt - 2s, clock::from_time_t(now_tt), now2_dt + 2s); } TEST_CASE("clock, FILETIME") { - // Round trip conversions - const DateTime now_dt = clock::now(); - REQUIRE(clock::from_file_time(clock::to_file_time(now_dt)) == now_dt); - + const DateTime now1_dt = clock::now(); FILETIME now_ft; ::GetSystemTimePreciseAsFileTime(&now_ft); + const DateTime now2_dt = clock::now(); + + // Round trip conversions + REQUIRE(clock::from_file_time(clock::to_file_time(now1_dt)) == now1_dt); + REQUIRE(clock::to_file_time(clock::from_file_time(now_ft)) == now_ft); // Verify epoch - ::GetSystemTimePreciseAsFileTime(&now_ft); - const auto diff = abs(clock::now() - clock::from_file_time(now_ft)); - REQUIRE(diff < milliseconds{ 100 }); + REQUIRE_ORDERED(now1_dt, clock::from_file_time(now_ft), now2_dt); } TEST_CASE("clock, system_clock") { - DateTime const now_dt = clock::now(); - auto const now_sys = system_clock::now(); + DateTime const now1_dt = clock::now(); + auto const now1_sys = system_clock::now(); + DateTime const now2_dt = clock::now(); + auto const now2_sys = system_clock::now(); // Round trip DateTime to std::chrono::system_clock::time_point and back - REQUIRE(clock::from_sys(clock::to_sys(now_dt)) == now_dt); + REQUIRE(clock::from_sys(clock::to_sys(now1_dt)) == now1_dt); // Round trip other direction - REQUIRE(clock::to_sys(clock::from_sys(now_sys)) == now_sys); + REQUIRE(clock::to_sys(clock::from_sys(now1_sys)) == now1_sys); // Round trip with custom resolution { - auto const now_dt_sec = time_point_cast(now_dt); + auto const now_dt_sec = time_point_cast(now1_dt); REQUIRE(clock::from_sys(clock::to_sys(now_dt_sec)) == now_dt_sec); } { - auto const now_dt_mins = time_point_cast(now_dt); + auto const now_dt_mins = time_point_cast(now1_dt); REQUIRE(clock::from_sys(clock::to_sys(now_dt_mins)) == now_dt_mins); } { - auto const now_sys_sec = time_point_cast(now_sys); + auto const now_sys_sec = time_point_cast(now1_sys); REQUIRE(clock::to_sys(clock::from_sys(now_sys_sec)) == now_sys_sec); } { - auto const now_sys_mins = time_point_cast(now_sys); + auto const now_sys_mins = time_point_cast(now1_sys); REQUIRE(clock::to_sys(clock::from_sys(now_sys_mins)) == now_sys_mins); } // Verify that the epoch calculations are correct. { - auto const diff = now_dt - clock::from_sys(now_sys); - REQUIRE(abs(diff) < milliseconds{ 100 }); - } - { - auto const diff = now_sys - clock::to_sys(now_dt); - REQUIRE(abs(diff) < milliseconds{ 100 }); + REQUIRE_ORDERED(now1_dt, clock::from_sys(now1_sys), now2_dt); + REQUIRE_ORDERED(clock::from_sys(now1_sys), now2_dt, clock::from_sys(now2_sys)); } } diff --git a/test/old_tests/UnitTests/com_ref.cpp b/test/old_tests/UnitTests/com_ref.cpp index 5457c493a..0d3e69120 100644 --- a/test/old_tests/UnitTests/com_ref.cpp +++ b/test/old_tests/UnitTests/com_ref.cpp @@ -3,7 +3,7 @@ namespace { - struct __declspec(uuid("52bb7805-e46e-46f9-8508-86606d2f6bc1")) IClassic : ::IUnknown + struct DECLSPEC_UUID("52bb7805-e46e-46f9-8508-86606d2f6bc1") IClassic : ::IUnknown { }; @@ -12,6 +12,17 @@ namespace }; } +#ifdef __CRT_UUID_DECL +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +__CRT_UUID_DECL(IClassic, 0x52bb7805, 0xe46e, 0x46f9, 0x85, 0x08, 0x86, 0x60, 0x6d, 0x2f, 0x6b, 0xc1); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#endif + TEST_CASE("com_ref agile_ref") { { diff --git a/test/old_tests/UnitTests/constexpr.cpp b/test/old_tests/UnitTests/constexpr.cpp index a881a2659..686d6ede9 100644 --- a/test/old_tests/UnitTests/constexpr.cpp +++ b/test/old_tests/UnitTests/constexpr.cpp @@ -2,7 +2,9 @@ #include "catch.hpp" #include "string_view_compare.h" +#ifdef _MSC_VER #pragma warning(disable:4471) // a forward declaration of an unscoped enumeration must have an underlying type +#endif #include using namespace std::string_view_literals; diff --git a/test/old_tests/UnitTests/delegate.cpp b/test/old_tests/UnitTests/delegate.cpp index ab83a2a65..5951b7bf6 100644 --- a/test/old_tests/UnitTests/delegate.cpp +++ b/test/old_tests/UnitTests/delegate.cpp @@ -680,7 +680,7 @@ TEST_CASE("delegate,MapChangedEventHandler") TEST_CASE("delegate,collection") { // - // Mostly a compiliation test to ensure that we can create collections of delegates. This is a rare corner case that was + // Mostly a compilation test to ensure that we can create collections of delegates. This is a rare corner case that was // previously not working. // diff --git a/test/old_tests/UnitTests/delegate_weak_strong.cpp b/test/old_tests/UnitTests/delegate_weak_strong.cpp index b042d6da0..84990c750 100644 --- a/test/old_tests/UnitTests/delegate_weak_strong.cpp +++ b/test/old_tests/UnitTests/delegate_weak_strong.cpp @@ -8,78 +8,157 @@ using namespace Windows::Foundation::Collections; namespace { - bool destroyed{}; - int strong_count{}; - int weak_count{}; + struct Counters + { + bool destroyed{}; + int strong_count{}; + int weak_count{}; + int weak_lambda_count{}; + + bool is_count(int value) + { + return strong_count == value && weak_count == value && weak_lambda_count == value; + } + }; template struct Object : implements, IInspectable> { + std::shared_ptr m_counters; + + Object(std::shared_ptr const& counters) : m_counters(counters) {} + + static auto make(std::shared_ptr const& counters) + { + return make_self(counters); + } + + auto strong() { return this->get_strong(); } + auto weak() { return this->get_weak(); } + ~Object() { - destroyed = true; + m_counters->destroyed = true; } void StrongHandler(Sender const&, Args const&) { - ++strong_count; + REQUIRE(!m_counters->destroyed); + ++m_counters->strong_count; } void WeakHandler(Sender const&, Args const&) { - ++weak_count; + REQUIRE(!m_counters->destroyed); + ++m_counters->weak_count; } }; - struct ReturnObject : implements + template + struct ObjectStd : std::enable_shared_from_this> { - ~ReturnObject() + std::shared_ptr m_counters; + + ObjectStd(std::shared_ptr const& counters) : m_counters(counters) {} + + static auto make(std::shared_ptr const& counters) + { + return std::make_shared(counters); + } + + auto strong() { return this->shared_from_this(); } + auto weak() { return this->weak_from_this(); } + + ~ObjectStd() + { + m_counters->destroyed = true; + } + + void StrongHandler(Sender const&, Args const&) + { + ++m_counters->strong_count; + } + + void WeakHandler(Sender const&, Args const&) { - destroyed = true; + ++m_counters->weak_count; } + }; + struct ReturnObject : implements + { int Handler(int a, int b) { return a + b; } }; - template - void test_delegate() + struct ReturnObjectStd : std::enable_shared_from_this { - auto object = make_self>(); + int Handler(int a, int b) + { + return a + b; + } + }; - Delegate strong{ object->get_strong(), &Object::StrongHandler }; - Delegate weak{ object->get_weak(), &Object::WeakHandler }; + template + void test_delegate_pattern() + { + auto counters = std::make_shared(); + auto object = Recipient::make(counters); - destroyed = false; - strong_count = 0; - weak_count = 0; + Delegate strong{ object->strong(), &Recipient::StrongHandler}; + Delegate weak{ object->weak(), &Recipient::WeakHandler }; + Delegate weak_lambda{ object->weak(),[counters](auto&&, auto&&) { + REQUIRE(!counters->destroyed); + ++counters->weak_lambda_count; + } }; - // Both weak and strong handlers + // All handlers are active at this point strong({}, {}); weak({}, {}); - REQUIRE(strong_count == 1); - REQUIRE(weak_count == 1); + weak_lambda({}, {}); + REQUIRE(counters->is_count(1)); // Local 'object' strong reference is released object = nullptr; - // Still both since strong handler keeps object alive + // Still invoked since strong handler keeps object alive strong({}, {}); weak({}, {}); - REQUIRE(strong_count == 2); - REQUIRE(weak_count == 2); + weak_lambda({}, {}); + REQUIRE(counters->is_count(2)); - // ~Object is called since the strong delegate is destroyed - REQUIRE(!destroyed); + // ~Recipient is called since the strong delegate is destroyed + REQUIRE(!counters->destroyed); strong = nullptr; - REQUIRE(destroyed); + REQUIRE(counters->destroyed); // Weak delegate remains but no longer fires - REQUIRE(weak_count == 2); + // Strong delegate shouldn't fire either + REQUIRE(counters->is_count(2)); weak({}, {}); - REQUIRE(weak_count == 2); + weak_lambda({}, {}); + REQUIRE(counters->is_count(2)); + } + + template + void test_delegate_winrt() + { + test_delegate_pattern, Delegate>(); + } + + template + void test_delegate_std() + { + test_delegate_pattern, Delegate>(); + } + + template + void test_delegate() + { + test_delegate_winrt(); + test_delegate_std(); } } @@ -111,8 +190,10 @@ TEST_CASE("delegate_weak_strong") // scenarios such as callbacks so weak support isn't interesting anyway, but it does work with get_strong. auto object = make_self(); - Component::TwoArgDelegateReturn strong{ object->get_strong(), &ReturnObject::Handler }; - REQUIRE(5 == strong(2, 3)); + + auto objectStd = std::make_shared(); + Component::TwoArgDelegateReturn strongStd{ objectStd->shared_from_this(), &ReturnObjectStd::Handler }; + REQUIRE(5 == strongStd(2, 3)); } diff --git a/test/old_tests/UnitTests/enum_flags.cpp b/test/old_tests/UnitTests/enum_flags.cpp index 3b8274f7e..670199c88 100644 --- a/test/old_tests/UnitTests/enum_flags.cpp +++ b/test/old_tests/UnitTests/enum_flags.cpp @@ -1,7 +1,9 @@ #include "pch.h" #include "catch.hpp" +#ifdef _MSC_VER #pragma warning(disable:4471) // a forward declaration of an unscoped enumeration must have an underlying type +#endif #include #include "winrt/Windows.ApplicationModel.Appointments.h" diff --git a/test/old_tests/UnitTests/handle.cpp b/test/old_tests/UnitTests/handle.cpp index 1b06aac87..f2e69a54d 100644 --- a/test/old_tests/UnitTests/handle.cpp +++ b/test/old_tests/UnitTests/handle.cpp @@ -76,7 +76,7 @@ static void test_put(HANDLE * value) REQUIRE(value != nullptr); REQUIRE(*value == nullptr); - *value = CreateEvent(nullptr, true, true, nullptr);; + *value = CreateEvent(nullptr, true, true, nullptr); } TEST_CASE("handle, put") diff --git a/test/old_tests/UnitTests/hresult_error.cpp b/test/old_tests/UnitTests/hresult_error.cpp index b9db219f4..fa15c2a1d 100644 --- a/test/old_tests/UnitTests/hresult_error.cpp +++ b/test/old_tests/UnitTests/hresult_error.cpp @@ -1,6 +1,11 @@ #include "pch.h" #include "catch.hpp" +// Missing in mingw-w64 +#ifndef E_BOUNDS +#define E_BOUNDS ((HRESULT)0x8000000B) +#endif + extern "C" BOOL __stdcall RoOriginateLanguageException(HRESULT error, void* message, void* languageException); using namespace winrt; @@ -23,7 +28,7 @@ TEST_CASE("hresult,S_FALSE") try { check_hresult(S_FALSE); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const & e) { @@ -40,7 +45,7 @@ TEST_CASE("hresult,init_apartment") try { init_apartment(apartment_type::single_threaded); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const & e) { @@ -55,7 +60,7 @@ TEST_CASE("hresult,restricted,consuming") try { Uri uri(L"BAD"); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const & e) // catching specific exception type { @@ -66,7 +71,7 @@ TEST_CASE("hresult,restricted,consuming") try { Uri uri(L"BAD"); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const & e) // catching generic exception type { @@ -477,7 +482,9 @@ TEST_CASE("hresult, exception") } } +#ifdef _MSC_VER #pragma warning(disable: 4702) // unreachable code +#endif TEST_CASE("hresult, throw_last_error") { SetLastError(ERROR_CANCELLED); @@ -497,11 +504,11 @@ TEST_CASE("hresult, std abi support") { EventHandler handler = [](auto&& ...) { - throw std::exception("std__exception"); + throw std::runtime_error("std__exception"); }; handler(nullptr, 0); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const& e) { @@ -517,7 +524,7 @@ TEST_CASE("hresult, std abi support") }; handler(nullptr, 0); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (std::bad_alloc const&) { @@ -531,7 +538,7 @@ TEST_CASE("hresult, std abi support") }; handler(nullptr, 0); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_out_of_bounds const& e) { @@ -547,7 +554,7 @@ TEST_CASE("hresult, std abi support") }; handler(nullptr, 0); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const& e) { @@ -575,4 +582,4 @@ TEST_CASE("hresult, to_message") { REQUIRE(to_message() == L"oh no, invalid handle"); } -} \ No newline at end of file +} diff --git a/test/old_tests/UnitTests/hstring.cpp b/test/old_tests/UnitTests/hstring.cpp index 1369fd229..2abd9769f 100644 --- a/test/old_tests/UnitTests/hstring.cpp +++ b/test/old_tests/UnitTests/hstring.cpp @@ -272,7 +272,6 @@ TEST_CASE("hstring,operator,std::wstring_view") REQUIRE(L"abc" == ws); hs.clear(); - REQUIRE(L"abc" == ws); ws = hs; REQUIRE(ws.empty()); } diff --git a/test/old_tests/UnitTests/interop.cpp b/test/old_tests/UnitTests/interop.cpp index 1f3ae56fd..357904a19 100644 --- a/test/old_tests/UnitTests/interop.cpp +++ b/test/old_tests/UnitTests/interop.cpp @@ -7,6 +7,10 @@ using namespace Windows::Foundation; namespace { + struct IClassicComInterface : ::IUnknown {}; + + struct ClassicCom : implements {}; + struct Stringable : implements { Stringable(std::wstring_view const& value = L"Stringable") : m_value(value) @@ -30,8 +34,16 @@ namespace object->AddRef(); return object->Release(); } + + template + uint32_t get_ref_count(com_ptr const& object) + { + return get_ref_count(object.get()); + } } +template <> inline constexpr winrt::guid winrt::impl::guid_v{ 0xc136bb75, 0xbc03, 0x41a6, { 0xa5, 0xdc, 0x5e, 0xfa, 0x67, 0x92, 0x4e, 0xbf } }; + TEST_CASE("interop") { uint32_t const before = get_module_lock(); @@ -108,6 +120,43 @@ TEST_CASE("self") REQUIRE(get_ref_count(object) == 1); object = nullptr; + strong = weak.get(); + REQUIRE(!strong); +} + +TEST_CASE("self_classic_com") +{ + com_ptr strong = make_self(); + + REQUIRE(get_ref_count(strong.get()) == 1); + + com_ptr object = strong.as(); + + REQUIRE(get_ref_count(strong.get()) == 2); + + ClassicCom* ptr = get_self(object); + REQUIRE(ptr == strong.get()); + + REQUIRE(get_ref_count(strong.get()) == 2); + strong = nullptr; + REQUIRE(get_ref_count(object) == 1); + + strong = get_self(object)->get_strong(); + REQUIRE(get_ref_count(object) == 2); + strong = nullptr; + REQUIRE(get_ref_count(object) == 1); + + weak_ref weak = get_self(object)->get_weak(); + REQUIRE(get_ref_count(object) == 1); // <-- still just one! + + strong = weak.get(); + REQUIRE(strong); + REQUIRE(get_ref_count(object) == 2); + + strong = nullptr; + REQUIRE(get_ref_count(object) == 1); + object = nullptr; + strong = weak.get(); REQUIRE(!strong); } \ No newline at end of file diff --git a/test/old_tests/UnitTests/make_self.cpp b/test/old_tests/UnitTests/make_self.cpp index 9924b4619..6ac17a3c0 100644 --- a/test/old_tests/UnitTests/make_self.cpp +++ b/test/old_tests/UnitTests/make_self.cpp @@ -1,8 +1,14 @@ #include "pch.h" #include "catch.hpp" +#if defined(_MSC_VER) +#define WDECLSPECL_NOVTABLE __declspec(novtable) +#else +#define WDECLSPECL_NOVTABLE +#endif + // -// These tests ensure that the make_self function works as expected to provide direct acccess +// These tests ensure that the make_self function works as expected to provide direct access // to an implementation. // // The IMakeSelf IUnknown interface is also tested as this covers an edge case in the implements @@ -11,11 +17,15 @@ using namespace winrt; -struct __declspec(uuid("eebb3a22-13a6-43b9-9d53-b7deb5a20ae5")) __declspec(novtable) IMakeSelf : IUnknown +struct DECLSPEC_UUID("eebb3a22-13a6-43b9-9d53-b7deb5a20ae5") WDECLSPECL_NOVTABLE IMakeSelf : IUnknown { virtual HRESULT __stdcall Call() = 0; }; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IMakeSelf, 0xeebb3a22, 0x13a6, 0x43b9, 0x9d, 0x53, 0xb7, 0xde, 0xb5, 0xa2, 0x0a, 0xe5); +#endif + struct MakeSelfStringable : implements { hstring ToString() diff --git a/test/old_tests/UnitTests/marshal.cpp b/test/old_tests/UnitTests/marshal.cpp index e183aa674..b260e7528 100644 --- a/test/old_tests/UnitTests/marshal.cpp +++ b/test/old_tests/UnitTests/marshal.cpp @@ -2,7 +2,7 @@ #include "catch.hpp" // These tests do not attempt to test the FTM itself, but merely to confirm that the presence and -// absence of the non_agile marker does indeed produce the correct reponses from QueryInterface. +// absence of the non_agile marker does indeed produce the correct responses from QueryInterface. // CoMarshalInterfaceXxxx is also used to exercise the code paths. Also, these tests confirm that // the weak reference object inherits the same agility as the source. Although much of this is // tested elsewhere, it was helpful to have these tests as a set. diff --git a/test/old_tests/UnitTests/meta.cpp b/test/old_tests/UnitTests/meta.cpp index e19a7202a..e8e61dda6 100644 --- a/test/old_tests/UnitTests/meta.cpp +++ b/test/old_tests/UnitTests/meta.cpp @@ -1,7 +1,9 @@ #include "pch.h" #include "catch.hpp" +#ifdef _MSC_VER #pragma warning(disable: 4505) +#endif using namespace winrt; using namespace Windows::Foundation; diff --git a/test/old_tests/UnitTests/param_iterable.cpp b/test/old_tests/UnitTests/param_iterable.cpp index 567e86859..758ff929d 100644 --- a/test/old_tests/UnitTests/param_iterable.cpp +++ b/test/old_tests/UnitTests/param_iterable.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "catch.hpp" +#include using namespace winrt; using namespace Windows::Foundation::Collections; diff --git a/test/old_tests/UnitTests/pch.h b/test/old_tests/UnitTests/pch.h index 51c6bc820..4b940b552 100644 --- a/test/old_tests/UnitTests/pch.h +++ b/test/old_tests/UnitTests/pch.h @@ -4,33 +4,35 @@ #define WINRT_NATVIS #define _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING +#include "mingw_com_support.h" + // Light up ::IUnknown interop by including this first #include #undef GetCurrentTime -#include "winrt\Windows.Foundation.Collections.h" -#include "winrt\Windows.Foundation.Diagnostics.h" -#include "winrt\Windows.ApplicationModel.Activation.h" -#include "winrt\Windows.ApplicationModel.Core.h" -#include "winrt\Windows.ApplicationModel.DataTransfer.h" -#include "winrt\Windows.ApplicationModel.Store.h" -#include "winrt\Windows.Data.Json.h" -#include "winrt\Windows.Devices.Perception.Provider.h" -#include "winrt\Windows.Devices.Sms.h" -#include "winrt\Windows.Graphics.Display.h" -#include "winrt\Windows.Graphics.Effects.h" -#include "winrt\Windows.Management.Deployment.h" -#include "winrt\Windows.Media.Audio.h" -#include "winrt\Windows.Media.Core.h" -#include "winrt\Windows.Media.Transcoding.h" -#include "winrt\Windows.Networking.Sockets.h" -#include "winrt\Windows.Security.Cryptography.Certificates.h" -#include "winrt\Windows.Storage.Streams.h" -#include "winrt\Windows.System.Threading.h" -#include "winrt\Windows.UI.Core.h" -#include "winrt\Windows.UI.Composition.h" -#include "winrt\Windows.UI.Xaml.Controls.h" -#include "winrt\Windows.UI.Xaml.Interop.h" -#include "winrt\Windows.Web.AtomPub.h" -#include "winrt\Windows.Web.Http.Headers.h" -#include "winrt\Windows.Web.Syndication.h" +#include "winrt/Windows.Foundation.Collections.h" +#include "winrt/Windows.Foundation.Diagnostics.h" +#include "winrt/Windows.ApplicationModel.Activation.h" +#include "winrt/Windows.ApplicationModel.Core.h" +#include "winrt/Windows.ApplicationModel.DataTransfer.h" +#include "winrt/Windows.ApplicationModel.Store.h" +#include "winrt/Windows.Data.Json.h" +#include "winrt/Windows.Devices.Perception.Provider.h" +#include "winrt/Windows.Devices.Sms.h" +#include "winrt/Windows.Graphics.Display.h" +#include "winrt/Windows.Graphics.Effects.h" +#include "winrt/Windows.Management.Deployment.h" +#include "winrt/Windows.Media.Audio.h" +#include "winrt/Windows.Media.Core.h" +#include "winrt/Windows.Media.Transcoding.h" +#include "winrt/Windows.Networking.Sockets.h" +#include "winrt/Windows.Security.Cryptography.Certificates.h" +#include "winrt/Windows.Storage.Streams.h" +#include "winrt/Windows.System.Threading.h" +#include "winrt/Windows.UI.Core.h" +#include "winrt/Windows.UI.Composition.h" +#include "winrt/Windows.UI.Xaml.Controls.h" +#include "winrt/Windows.UI.Xaml.Interop.h" +#include "winrt/Windows.Web.AtomPub.h" +#include "winrt/Windows.Web.Http.Headers.h" +#include "winrt/Windows.Web.Syndication.h" diff --git a/test/old_tests/UnitTests/produce.cpp b/test/old_tests/UnitTests/produce.cpp index 403f0df2b..9ac76ad18 100644 --- a/test/old_tests/UnitTests/produce.cpp +++ b/test/old_tests/UnitTests/produce.cpp @@ -4,7 +4,7 @@ // // These tests cover the production of the three core interfaces namely IUnknown, IInspectable, and IActivationFactory. // Tests ensure that the ABI surface lines up on the consumer and producer sides and this is mainly done simply by calling -// the various inteface methods. +// the various interface methods. // using namespace winrt; @@ -124,10 +124,17 @@ struct produce_IInspectable_No_RuntimeClassName : implements { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Woverloaded-virtual" +#endif hstring GetRuntimeClassName() { return L"produce_IInspectable_RuntimeClassName"; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif }; TEST_CASE("produce_IInspectable_RuntimeClassName") diff --git a/test/old_tests/UnitTests/produce_async.cpp b/test/old_tests/UnitTests/produce_async.cpp index e37842e12..ed8ee50db 100644 --- a/test/old_tests/UnitTests/produce_async.cpp +++ b/test/old_tests/UnitTests/produce_async.cpp @@ -4,7 +4,7 @@ // // These tests cover the production of the various async interfaces. // Tests ensure that the ABI surface lines up on the consumer and producer sides and this is mainly done simply by calling -// the various inteface methods. +// the various interface methods. // using namespace winrt; diff --git a/test/old_tests/UnitTests/produce_map.cpp b/test/old_tests/UnitTests/produce_map.cpp index b456082a4..0c66a1820 100644 --- a/test/old_tests/UnitTests/produce_map.cpp +++ b/test/old_tests/UnitTests/produce_map.cpp @@ -5,7 +5,7 @@ // // These tests cover the production of the various map-related interfaces. // Tests ensure that the ABI surface lines up on the consumer and producer sides and this is mainly done simply by calling -// the various inteface methods. +// the various interface methods. // using namespace winrt; diff --git a/test/old_tests/UnitTests/produce_vector.cpp b/test/old_tests/UnitTests/produce_vector.cpp index fbf3d3b84..16111f96d 100644 --- a/test/old_tests/UnitTests/produce_vector.cpp +++ b/test/old_tests/UnitTests/produce_vector.cpp @@ -5,7 +5,7 @@ // // These tests cover the production of the various vector-related interfaces. // Tests ensure that the ABI surface lines up on the consumer and producer sides and this is mainly done simply by calling -// the various inteface methods. +// the various interface methods. // using namespace winrt; diff --git a/test/old_tests/UnitTests/smart_pointers.cpp b/test/old_tests/UnitTests/smart_pointers.cpp index fc760fb48..92dca1396 100644 --- a/test/old_tests/UnitTests/smart_pointers.cpp +++ b/test/old_tests/UnitTests/smart_pointers.cpp @@ -7,6 +7,12 @@ using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Component; + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wself-assign-overloaded" +#pragma clang diagnostic ignored "-Wself-move" +#endif + namespace { struct Type : implements diff --git a/test/old_tests/UnitTests/streams.cpp b/test/old_tests/UnitTests/streams.cpp new file mode 100644 index 000000000..b6bc0f089 --- /dev/null +++ b/test/old_tests/UnitTests/streams.cpp @@ -0,0 +1,36 @@ + #include "pch.h" +#include "catch.hpp" +#include + +struct stringable : winrt::implements +{ + winrt::hstring ToString() + { + return L"a stringable object"; + } +}; + +TEST_CASE("streams") +{ + { + std::wstringstream ss; + winrt::hstring str = L"Hello World"; + ss << str; + REQUIRE(ss.str() == str); + } + + { + // Support embedded nulls. + std::wstringstream ss; + winrt::hstring str = L"Hello\0World"; + ss << str; + REQUIRE(ss.str() == str); + } + + { + std::wstringstream ss; + winrt::Windows::Foundation::IStringable obj = winrt::make(); + ss << obj; + REQUIRE(ss.str() == obj.ToString()); + } +} diff --git a/test/old_tests/UnitTests/struct.cpp b/test/old_tests/UnitTests/struct.cpp index bce62e25d..995f495a4 100644 --- a/test/old_tests/UnitTests/struct.cpp +++ b/test/old_tests/UnitTests/struct.cpp @@ -10,7 +10,7 @@ using namespace Windows::Web::Http; // // This first test ensures that structures with HSTRING fields are projected correctly. // In this case, a suitable interface is provided by the Windows SDK to simplify testing. -// IControlTemplate provides the necessary methods for excercising input and output +// IControlTemplate provides the necessary methods for exercising input and output // patterns for code generation. // @@ -47,7 +47,7 @@ TEST_CASE("struct, TypeName") // // This second test ensures that structures with IReference fields are projected correctly. // In this case, a suitable interface is not available in the Windows SDK so we hand-roll the -// the necessary intput and output patterms for code generation. We also rely on a custom +// the necessary input and output patterns for code generation. We also rely on a custom // implementation of IReference so that we can additionally check that the object is // destroyed correctly. // diff --git a/test/old_tests/UnitTests/to_hstring.cpp b/test/old_tests/UnitTests/to_hstring.cpp index 9f3463a56..1d287c09b 100644 --- a/test/old_tests/UnitTests/to_hstring.cpp +++ b/test/old_tests/UnitTests/to_hstring.cpp @@ -4,6 +4,14 @@ using namespace winrt; +struct stringable : winrt::implements +{ + winrt::hstring ToString() + { + return L"a stringable object"; + } +}; + namespace { void test_cases() @@ -82,6 +90,10 @@ namespace hstring const c = to_hstring(b); REQUIRE(a == c); } + { + auto const obj = make(); + REQUIRE(to_hstring(obj) == obj.ToString()); + } } } diff --git a/test/old_tests/UnitTests/weak.cpp b/test/old_tests/UnitTests/weak.cpp index b253e6010..46b89bf6f 100644 --- a/test/old_tests/UnitTests/weak.cpp +++ b/test/old_tests/UnitTests/weak.cpp @@ -22,7 +22,7 @@ namespace } }; - struct NoWeak : implements + struct WeakClassicCom : implements { }; @@ -50,6 +50,8 @@ namespace } }; +// FIXME: Fail to compile with Clang and GCC due to incomplete type. +#if !defined(__clang__) && !defined(__GNUC__) struct WeakWithSelfReference : implements { winrt::weak_ref weak_self = get_weak(); @@ -68,6 +70,50 @@ namespace REQUIRE(weak_self.get() == nullptr); } }; +#endif + + struct WeakCreateWeakInDestructor : implements + { + winrt::weak_ref& weak_self; + + WeakCreateWeakInDestructor(winrt::weak_ref& magic) : weak_self(magic) {} + + ~WeakCreateWeakInDestructor() + { + // Creates a weak reference to itself in the destructor. + weak_self = get_weak(); + } + + hstring ToString() + { + return L"WeakCreateWeakInDestructor"; + } + }; + +#ifdef WINRT_IMPL_COROUTINES + // Returns an IAsyncAction that has already completed. + winrt::Windows::Foundation::IAsyncAction Action() + { + co_return; + } + + // Returns an IAsyncAction that has not completed. + // Call the resume() handle to complete it. + winrt::Windows::Foundation::IAsyncAction SuspendAction(std::coroutine_handle<>& resume) + { + struct awaiter + { + std::coroutine_handle<>& resume; + bool await_ready() { return false; } + void await_suspend(std::coroutine_handle<> handle) { resume = handle; } + void await_resume() {} + }; + + co_await awaiter{ resume }; + co_return; + } + +#endif } TEST_CASE("weak,source") @@ -118,6 +164,26 @@ TEST_CASE("weak,source") REQUIRE(b.ToString() == L"Weak"); } + SECTION("classic-com") + { + com_ptr<::IUnknown> a = make(); + + weak_ref<::IUnknown> w = a; + com_ptr<::IUnknown> b = w.get(); + REQUIRE(b == a); + + // still one outstanding reference + b = nullptr; + b = w.get(); + REQUIRE(b != nullptr); + + // no outstanding references + a = nullptr; + b = nullptr; + b = w.get(); + REQUIRE(b == nullptr); + } + // Verify that deduction guides work. static_assert(std::is_same_v, decltype(weak_ref(IStringable()))>); static_assert(std::is_same_v, decltype(weak_ref(std::declval()))>); @@ -163,12 +229,24 @@ TEST_CASE("weak,QI") REQUIRE(ref.as<::IUnknown>() != object.as<::IUnknown>()); } - SECTION("no-weak") + SECTION("weak-classic-com") { - com_ptr<::IUnknown> object = make(); + com_ptr<::IUnknown> object = make(); REQUIRE(!object.try_as()); - REQUIRE(!object.try_as()); + REQUIRE(object.try_as()); REQUIRE(!object.try_as()); + + com_ptr source = object.as(); + REQUIRE(!source.try_as()); + REQUIRE(source.try_as()); + REQUIRE(object.as<::IUnknown>() == source.as<::IUnknown>()); + + com_ptr ref; + REQUIRE(S_OK == source->GetWeakReference(ref.put())); + REQUIRE(!ref.try_as()); + REQUIRE(!ref.try_as()); + REQUIRE(ref.as() == ref); + REQUIRE(ref.as<::IUnknown>() != object.as<::IUnknown>()); } SECTION("factory") @@ -369,10 +447,13 @@ TEST_CASE("weak,assignment") // Not constructible from L"" (because Uri constructor is explicit) static_assert(!std::is_constructible_v, const wchar_t*>); +// FIXME: WeakWithSelfReference fails to compile with Clang and GCC. +#if !defined(__clang__) && !defined(__GNUC__) // Constructible from com_ptr because com_ptr is // implicitly convertible to com_ptr. struct Derived : WeakWithSelfReference {}; weak_ref decay{ winrt::com_ptr{nullptr} }; +#endif } TEST_CASE("weak,module_lock") @@ -406,6 +487,8 @@ TEST_CASE("weak,no_module_lock") REQUIRE(get_module_lock() == object_count); } +// FIXME: WeakWithSelfReference fails to compile with Clang and GCC. +#if !defined(__clang__) && !defined(__GNUC__) TEST_CASE("weak,self") { // The REQUIRE statements are in the WeakWithSelfReference class itself. @@ -413,3 +496,38 @@ TEST_CASE("weak,self") a.ToString(); a = nullptr; } +#endif + +TEST_CASE("weak,create_weak_in_destructor") +{ + weak_ref magic; + IStringable a = make(magic); + a.ToString(); + a = nullptr; + REQUIRE(magic.get() == nullptr); +} + +#ifdef WINRT_IMPL_COROUTINES +TEST_CASE("weak,coroutine") +{ + // Run a coroutine to completion. Confirm that weak references fail to resolve. + auto weak = winrt::weak_ref(Action()); + REQUIRE(weak.get() == nullptr); + + // Start a coroutine but don't complete it yet. + // Confirm that weak references resolve. + std::coroutine_handle<> resume; + weak = winrt::weak_ref(SuspendAction(resume)); + REQUIRE(weak.get() != nullptr); + // Now complete the coroutine. Confirm that weak references no longer resolve. + resume(); + REQUIRE(weak.get() == nullptr); + + // Verify that weak reference resolves as long as strong reference exists. + auto action = Action(); + weak = winrt::weak_ref(action); + REQUIRE(weak.get() == action); + action = nullptr; + REQUIRE(weak.get() == nullptr); +} +#endif diff --git a/test/test/CMakeLists.txt b/test/test/CMakeLists.txt new file mode 100644 index 000000000..ba174d41b --- /dev/null +++ b/test/test/CMakeLists.txt @@ -0,0 +1,92 @@ +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp") + + +# We can't build test_component[*] for mingw-w64 because it doesn't have an +# alternative to midl that can produce winmd files. Also, even if we do manage +# to reuse the MSVC-compiled binaries, mingw-w64 is still missing +# windowsnumerics.impl.h which is needed to provide the types +# winrt::Windows::Foundation::Numerics::float2 and friends that the components +# use. +list(APPEND BROKEN_TESTS + agility + delegates + enum + event_deferral + in_params + in_params_abi + no_make_detection + noexcept + optional + out_params + out_params_abi + parent_includes + rational + return_params + return_params_abi + struct_delegate + structs + uniform_in_params + velocity +) + +list(APPEND BROKEN_TESTS + # depends on pplawait.h + when +) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # FIXME: GCC does not compile co_await on thread_pool because it wants + # a copy constructor. Disabling this test for now. + # This might be related to upstream bug: + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103963 + list(APPEND BROKEN_TESTS + thread_pool + ) +endif() + +# Exclude broken tests +foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS) + list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp") +endforeach() + +add_executable(test-vanilla main.cpp ${TEST_SRCS}) +set_target_properties(test-vanilla PROPERTIES OUTPUT_NAME "test") +target_link_libraries(test-vanilla runtimeobject synchronization) + +target_precompile_headers(test-vanilla PRIVATE pch.h) +set_source_files_properties( + main.cpp + coro_foundation.cpp + coro_system.cpp + coro_threadpool.cpp + coro_uicore.cpp + custom_activation.cpp + generic_type_names.cpp + guid_include.cpp + inspectable_interop.cpp + module_lock_dll.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true +) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # GCC seems to miscompile out_params_bad.cpp if -fdevirtualize is enabled. + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108040 + set_source_files_properties(out_params_bad.cpp PROPERTIES COMPILE_OPTIONS "-fno-devirtualize") + + if(CMAKE_BUILD_TYPE STREQUAL "Release") + # GCC miscompiles multi_threaded_vector.cpp with -O3 + set_source_files_properties(multi_threaded_vector.cpp PROPERTIES COMPILE_OPTIONS "-O2") + endif() +endif() + +add_dependencies(test-vanilla build-cppwinrt-projection) + +add_test( + NAME test + COMMAND "$" ${TEST_COLOR_ARG} +) diff --git a/test/test/GetMany.cpp b/test/test/GetMany.cpp index 23ea63e1e..292912046 100644 --- a/test/test/GetMany.cpp +++ b/test/test/GetMany.cpp @@ -255,6 +255,9 @@ TEST_CASE("GetMany") REQUIRE(buffer[3] == L""); } +// FIXME: Fail to compile with Clang due to recursive template instantiation using single_threaded_generator. +#if !defined(__clang__) + // Similar tests but with a list to ensure optimal code gen for containers that don't offer random access. // All @@ -358,6 +361,7 @@ TEST_CASE("GetMany") REQUIRE(buffer[2] == L"3"); REQUIRE(buffer[3] == L""); } +#endif // Pair { diff --git a/test/test/abi_guard.cpp b/test/test/abi_guard.cpp index c0244a475..b2931b278 100644 --- a/test/test/abi_guard.cpp +++ b/test/test/abi_guard.cpp @@ -6,7 +6,7 @@ using namespace Windows::Foundation; namespace { // - // This implemenetation uses the simplest abi_enter and abi_exit methods + // This implementation uses the simplest abi_enter and abi_exit methods // struct Simple : implements { @@ -34,7 +34,7 @@ namespace }; // - // This implemenetation uses the abi_enter but omits the abi_exit method + // This implementation uses the abi_enter but omits the abi_exit method // struct OnlyEnter : implements { @@ -56,7 +56,7 @@ namespace }; // - // This implemenetation throws from the abi_enter method + // This implementation throws from the abi_enter method // struct Throwing : implements { @@ -83,7 +83,7 @@ namespace }; // - // This implemenetation provides a nested abi_guard + // This implementation provides a nested abi_guard // struct NestedGuard : implements { @@ -138,7 +138,7 @@ namespace }; // - // This implemenetation use an abi_guard type alias + // This implementation use an abi_guard type alias // struct GuardAlias : implements { @@ -167,7 +167,7 @@ namespace }; // - // This implemenetation use an abi_guard type alias that thows + // This implementation use an abi_guard type alias that throws // struct ThrowAlias : implements { diff --git a/test/test/async_auto_cancel.cpp b/test/test/async_auto_cancel.cpp index 2b1fdc728..b0a541535 100644 --- a/test/test/async_auto_cancel.cpp +++ b/test/test/async_auto_cancel.cpp @@ -12,21 +12,21 @@ namespace IAsyncAction Action(HANDLE event) { co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } IAsyncActionWithProgress ActionWithProgress(HANDLE event) { co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } IAsyncOperation Operation(HANDLE event) { co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -34,7 +34,7 @@ namespace IAsyncOperationWithProgress OperationWithProgress(HANDLE event) { co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -48,7 +48,7 @@ namespace auto cancel = co_await get_cancellation_token(); cancel.callback(nullptr); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -77,7 +77,12 @@ namespace } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async_auto_cancel", "[.clang-crash]") +#else TEST_CASE("async_auto_cancel") +#endif { Check(Action); Check(ActionWithProgress); diff --git a/test/test/async_cancel_callback.cpp b/test/test/async_cancel_callback.cpp index a69575a88..75a3aac0c 100644 --- a/test/test/async_cancel_callback.cpp +++ b/test/test/async_cancel_callback.cpp @@ -23,7 +23,7 @@ namespace }(); co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -38,7 +38,7 @@ namespace }); co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -53,7 +53,7 @@ namespace }); co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -69,7 +69,7 @@ namespace }); co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } @@ -87,7 +87,12 @@ namespace } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async_cancel_callback", "[.clang-crash]") +#else TEST_CASE("async_cancel_callback") +#endif { Check(Action); Check(ActionWithProgress); diff --git a/test/test/async_check_cancel.cpp b/test/test/async_check_cancel.cpp index 38d21f48b..c98519f06 100644 --- a/test/test/async_check_cancel.cpp +++ b/test/test/async_check_cancel.cpp @@ -5,6 +5,28 @@ using namespace Windows::Foundation; namespace { + static bool s_exceptionLoggerCalled = false; + + static struct { + uint32_t lineNumber; + char const* fileName; + char const* functionName; + void* returnAddress; + winrt::hresult result; + } s_exceptionLoggerArgs{}; + + void __stdcall exceptionLogger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept + { + s_exceptionLoggerArgs = { + /*.lineNumber =*/ lineNumber, + /*.fileName =*/ fileName, + /*.functionName =*/ functionName, + /*.returnAddress =*/ returnAddress, + /*.result =*/ result, + }; + s_exceptionLoggerCalled = true; + } + // // Checks that manual cancellation checks work. // @@ -20,7 +42,7 @@ namespace canceled = true; } - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -35,7 +57,7 @@ namespace canceled = true; } - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); } @@ -50,11 +72,12 @@ namespace canceled = true; } - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } + IAsyncOperationWithProgress OperationWithProgress(HANDLE event, bool& canceled) { co_await resume_on_signal(event); @@ -66,11 +89,64 @@ namespace canceled = true; } - co_await std::experimental::suspend_never(); + co_await std::suspend_never(); REQUIRE(false); co_return 1; } + IAsyncAction OperationCancelLogged(HANDLE event, bool& canceled) + { + REQUIRE(!s_exceptionLoggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = exceptionLogger; + + co_await resume_on_signal(event); + auto cancel = co_await get_cancellation_token(); + + if (cancel()) + { + REQUIRE(!canceled); + canceled = true; + REQUIRE(s_exceptionLoggerCalled); + REQUIRE(s_exceptionLoggerArgs.result == HRESULT_FROM_WIN32(ERROR_CANCELLED)); + } + + winrt_throw_hresult_handler = nullptr; + s_exceptionLoggerCalled = false; + + co_await std::suspend_never(); + + REQUIRE(false); + co_return; + } + + IAsyncAction OperationAvoidLoggingCancel(HANDLE event, bool& canceled) + { + REQUIRE(!s_exceptionLoggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = exceptionLogger; + + auto cancel = co_await get_cancellation_token(); + cancel.originate_on_cancel(false); + + co_await resume_on_signal(event); + + if (cancel()) + { + REQUIRE(!canceled); + canceled = true; + REQUIRE(!s_exceptionLoggerCalled); + } + + winrt_throw_hresult_handler = nullptr; + s_exceptionLoggerCalled = false; + + co_await std::suspend_never(); + + REQUIRE(false); + co_return; + } + template void Check(F make) { @@ -90,7 +166,7 @@ namespace async.Cancel(); SetEvent(start.get()); - REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0); + REQUIRE(WaitForSingleObject(completed.get(), IsDebuggerPresent() ? INFINITE : 1000) == WAIT_OBJECT_0); REQUIRE(async.Status() == AsyncStatus::Canceled); REQUIRE(async.ErrorCode() == HRESULT_FROM_WIN32(ERROR_CANCELLED)); @@ -98,10 +174,17 @@ namespace } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async_check_cancel", "[.clang-crash]") +#else TEST_CASE("async_check_cancel") +#endif { Check(Action); Check(ActionWithProgress); Check(Operation); Check(OperationWithProgress); + Check(OperationCancelLogged); + Check(OperationAvoidLoggingCancel); } diff --git a/test/test/async_propagate_cancel.cpp b/test/test/async_propagate_cancel.cpp index f735f1bf2..9e0ab8ee9 100644 --- a/test/test/async_propagate_cancel.cpp +++ b/test/test/async_propagate_cancel.cpp @@ -104,7 +104,7 @@ namespace } template - void Check(F make) + void CheckWithWait(F make, bool wait) { handle completed{ CreateEvent(nullptr, true, false, nullptr) }; auto async = make(); @@ -117,6 +117,12 @@ namespace SetEvent(completed.get()); }); + if (wait) + { + // ensure we hit the co_await that's cancellable before trying to cancel. + Sleep(1000); + } + async.Cancel(); // Wait indefinitely if a debugger is present, to make it easier to debug this test. @@ -126,9 +132,21 @@ namespace REQUIRE(async.ErrorCode() == HRESULT_FROM_WIN32(ERROR_CANCELLED)); REQUIRE_THROWS_AS(async.GetResults(), hresult_canceled); } + + template + void Check(F make) + { + CheckWithWait(make, false); + CheckWithWait(make, true); + } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async_propagate_cancel", "[.clang-crash]") +#else TEST_CASE("async_propagate_cancel") +#endif { Check(Action); Check(ActionWithProgress); diff --git a/test/test/async_ref_result.cpp b/test/test/async_ref_result.cpp deleted file mode 100644 index 015bb7b31..000000000 --- a/test/test/async_ref_result.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that references returned by awaitables - // are not accidentally decayed. - // - // This test "runs" at compile time via static_assert. - - template - struct awaitable : std::experimental::suspend_never - { - std::decay_t value; - T await_resume() { return static_cast(value); } - }; - - template - struct awaitable_member_awaiter : std::experimental::suspend_never - { - decltype(auto) get_awaiter() { return *this; } - std::decay_t value; - T await_resume() { return static_cast(value); } - }; - - template - struct awaitable_free_awaiter : std::experimental::suspend_never - { - std::decay_t value; - T await_resume() { return static_cast(value); } - }; - template - decltype(auto) get_awaiter(awaitable_free_awaiter&& value) { return std::move(value); } - - template typename A, typename T> - IAsyncAction Check() - { - decltype(auto) value = co_await A(); - static_assert(std::is_same_v); - } - - template typename A> - IAsyncAction Check() - { - co_await Check(); - co_await Check(); - co_await Check(); - co_await Check(); - } - - IAsyncAction Test() - { - co_await Check(); - co_await Check(); - co_await Check(); - } -} - -TEST_CASE("async_ref_result") -{ - Test().get(); -} diff --git a/test/test/async_throw.cpp b/test/test/async_throw.cpp index 2d50acfd9..88e38d323 100644 --- a/test/test/async_throw.cpp +++ b/test/test/async_throw.cpp @@ -77,7 +77,12 @@ namespace } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async_throw", "[.clang-crash]") +#else TEST_CASE("async_throw") +#endif { Check(Action); Check(ActionWithProgress); diff --git a/test/test/async_wait_for.cpp b/test/test/async_wait_for.cpp index 2173a5e86..d7613083c 100644 --- a/test/test/async_wait_for.cpp +++ b/test/test/async_wait_for.cpp @@ -96,7 +96,12 @@ namespace } } +#if defined(__clang__) && defined(_MSC_VER) +// FIXME: Test is known to segfault when built with Clang. +TEST_CASE("async_wait_for", "[.clang-crash]") +#else TEST_CASE("async_wait_for") +#endif { check( Action(0s, AsyncStatus::Completed), diff --git a/test/test/await_adapter.cpp b/test/test/await_adapter.cpp index 16575699b..dccb9ce3d 100644 --- a/test/test/await_adapter.cpp +++ b/test/test/await_adapter.cpp @@ -18,13 +18,9 @@ namespace static handle signal{ CreateEventW(nullptr, false, false, nullptr) }; - IAsyncAction OtherForegroundAsync() + IAsyncAction OtherForegroundAsync(DispatcherQueue dispatcher) { - // Simple coroutine that completes on a unique STA thread. - - auto controller = DispatcherQueueController::CreateOnDedicatedThread(); - auto dispatcher = controller.DispatcherQueue(); - + // Simple coroutine that completes on the specified STA thread. co_await resume_foreground(dispatcher); } @@ -35,37 +31,37 @@ namespace co_await resume_background(); } - IAsyncAction ForegroundAsync(DispatcherQueue dispatcher) + // Coroutine that completes on dispatcher1, while potentially blocking dispatcher2. + IAsyncAction ForegroundAsync(DispatcherQueue dispatcher1, DispatcherQueue dispatcher2) { REQUIRE(!is_sta()); - co_await resume_foreground(dispatcher); + co_await resume_foreground(dispatcher1); REQUIRE(is_sta()); // This exercises one STA thread waiting on another thus one context callback // completing on another. uint32_t id = GetCurrentThreadId(); - co_await OtherForegroundAsync(); + co_await OtherForegroundAsync(dispatcher2); REQUIRE(id == GetCurrentThreadId()); - // This just avoids the ForegroundAsync coroutine completing before - // BackgroundAsync waits on the result, forcing the Completed handler - // to be called on the foreground thread. This just makes the test - // success/failure more predictable. + // This Sleep() makes it more likely that the caller will actually suspend in await_suspend, + // so that the Completed handler triggers a resumption from the dispatcher1 thread. Sleep(100); } - fire_and_forget SignalFromForeground(DispatcherQueue dispatcher) + fire_and_forget SignalFromForeground(DispatcherQueue dispatcher1) { REQUIRE(!is_sta()); - co_await resume_foreground(dispatcher); + co_await resume_foreground(dispatcher1); REQUIRE(is_sta()); - // Previously, this signal was never raised because the foreground thread - // was always blocked waiting for ContextCallback to return. + // Previously, we never got here because of a deadlock: + // The dispatcher1 thread was blocked waiting for ContextCallback to return, + // but the ContextCallback is waiting for this event to get signaled. REQUIRE(SetEvent(signal.get())); } - IAsyncAction BackgroundAsync(DispatcherQueue dispatcher) + IAsyncAction BackgroundAsync(DispatcherQueue dispatcher1, DispatcherQueue dispatcher2) { // Switch to a background (MTA) thread. co_await resume_background(); @@ -76,27 +72,100 @@ namespace co_await OtherBackgroundAsync(); REQUIRE(!is_sta()); - // Wait for a coroutine that completes on a foreground (STA) thread. - co_await ForegroundAsync(dispatcher); + // Wait for a coroutine that completes on a the dispatcher1 thread (STA). + co_await ForegroundAsync(dispatcher1, dispatcher2); // Resumption should automatically switch to a background (MTA) thread - // without blocking the Completed handler (which would in turn block the foreground thread). + // without blocking the Completed handler (which would in turn block the dispatcher1 thread). REQUIRE(!is_sta()); - // Attempt to signal from the foreground thread under the assumption - // that the foreground thread is not blocked. - SignalFromForeground(dispatcher); + // Attempt to signal from the dispatcher1 thread under the assumption + // that the dispatcher1 thread is not blocked. + SignalFromForeground(dispatcher1); - // Block the background (MTA) thread indefinitely until the signal is raied. - // Previously this would deadlock. + // Block the background (MTA) thread indefinitely until the signal is raised. + // Previously this would hang because the signal never got raised. REQUIRE(WAIT_OBJECT_0 == WaitForSingleObject(signal.get(), INFINITE)); } } +#if defined(__clang__) && defined(_MSC_VER) && (defined(_M_IX86) || defined(__i386__)) +// FIXME: Test is known to segfault on x86 when built with Clang. +TEST_CASE("await_adapter", "[.clang-crash]") +#else TEST_CASE("await_adapter") +#endif +{ + auto controller1 = DispatcherQueueController::CreateOnDedicatedThread(); + auto controller2 = DispatcherQueueController::CreateOnDedicatedThread(); + + BackgroundAsync(controller1.DispatcherQueue(), controller2.DispatcherQueue()).get(); + controller1.ShutdownQueueAsync().get(); + controller2.ShutdownQueueAsync().get(); +} + +namespace +{ + IAsyncAction OtherBackgroundDelayAsync() + { + // Simple coroutine that completes on some MTA thread after a brief delay + // to ensure that the caller has suspended. + + co_await resume_after(100ms); + } + + IAsyncAction AgileAsync(DispatcherQueue dispatcher) + { + // Switch to the STA. + co_await resume_foreground(dispatcher); + REQUIRE(is_sta()); + + // Ask for agile resumption of a coroutine that finishes on a background thread. + // Add a 100ms delay to ensure we suspend. + co_await resume_agile(OtherBackgroundDelayAsync()); + // We should be on the background thread now. + REQUIRE(!is_sta()); + } +} + +TEST_CASE("await_adapter_agile") +{ + auto controller = DispatcherQueueController::CreateOnDedicatedThread(); + auto dispatcher = controller.DispatcherQueue(); + + AgileAsync(dispatcher).get(); + controller.ShutdownQueueAsync().get(); +} + +namespace +{ + IAsyncAction AgileAsyncVariable(DispatcherQueue dispatcher) + { + // Switch to the STA. + co_await resume_foreground(dispatcher); + REQUIRE(is_sta()); + + // Ask for agile resumption of a coroutine that finishes on a background thread. + // Add a 100ms delay to ensure we suspend. Store the resume_agile in a variable + // and await the variable. + auto op = resume_agile(OtherBackgroundDelayAsync()); + co_await op; + // We should be on the background thread now. + REQUIRE(!is_sta()); + + // Second attempt to await the op should fail cleanly. + REQUIRE_THROWS_AS(co_await op, hresult_illegal_delegate_assignment); + // We should still be on the background thread. + REQUIRE(!is_sta()); + } +} + + +TEST_CASE("await_adapter_agile_variable") { auto controller = DispatcherQueueController::CreateOnDedicatedThread(); auto dispatcher = controller.DispatcherQueue(); - BackgroundAsync(dispatcher).get(); + AgileAsyncVariable(dispatcher).get(); + controller.ShutdownQueueAsync().get(); } diff --git a/test/test/await_completed.cpp b/test/test/await_completed.cpp index fed776e90..1d6143eb1 100644 --- a/test/test/await_completed.cpp +++ b/test/test/await_completed.cpp @@ -27,43 +27,33 @@ namespace } #endif - // Simple awaiter that (inefficiently) resumes from inside - // await_suspend, for the purpose of measuring how much stack it consumes. - // This is the best we can do with MSVC prerelease coroutines prior to 16.11. - struct resume_sync_from_await_suspend - { - bool await_ready() { return false; } - void await_suspend(winrt::impl::coroutine_handle<> h) { h(); } - void await_resume() { } - }; - IAsyncAction SyncCompletion() { uintptr_t initial = approximate_stack_pointer(); - co_await resume_sync_from_await_suspend(); - uintptr_t sync_usage = initial - approximate_stack_pointer(); - - initial = approximate_stack_pointer(); co_await AlreadyCompleted(); uintptr_t consumed = initial - approximate_stack_pointer(); -#ifdef _RESUMABLE_FUNCTIONS_SUPPORTED - // This branch is taken only for MSVC prerelease coroutines. - // - // MSVC prerelease coroutines prior to 16.11 do not implement "bool await_suspend" reliably, - // so we can't use it impl::await_adapter. We must resume inline inside await_suspend, - // so there is a small amount of stack usage. (Pre-16.11 and post-16.11 prerelease coroutines - // are interoperable, so we cannot change behavior based on which compiler we are using, - // because that would introduce ODR violations. Our first opportunity to change behavior - // is the ABI breaking change with MSVC standard-conforming coroutines.) - REQUIRE(consumed <= sync_usage); -#else - // MSVC standard-conforming coroutines (as well as gcc and clang coroutines) - // support "bool await_suspend" just fine. REQUIRE(consumed == 0); -#endif + } + + // co_await the same apartment context and confirm that stack does not grow. + // This is in await_completed.cpp because it's basically the same thing as awaiting + // an already-completed coroutine, so the test uses the same infrastructure. + IAsyncAction TestApartmentContextNop() + { + winrt::apartment_context same_context; + + uintptr_t initial = approximate_stack_pointer(); + co_await same_context; + uintptr_t consumed = initial - approximate_stack_pointer(); + REQUIRE(consumed == 0); } } TEST_CASE("await_completed_await") { SyncCompletion().get(); -} \ No newline at end of file +} + +TEST_CASE("apartment_context_nop") +{ + TestApartmentContextNop().get(); +} diff --git a/test/test/box_array.cpp b/test/test/box_array.cpp index 1c5b4a966..04377b334 100644 --- a/test/test/box_array.cpp +++ b/test/test/box_array.cpp @@ -8,17 +8,17 @@ namespace T defaultValue{}; winrt::com_array ary{ otherValue, defaultValue }; auto box = winrt::box_value(ary); - winrt::com_array unbox = box.try_as>().value(); + winrt::com_array unbox = box.template try_as>().value(); REQUIRE(unbox.size() == 2); REQUIRE(unbox.at(0) == otherValue); REQUIRE(unbox.at(1) == defaultValue); - unbox = box.as>(); + unbox = box.template as>(); REQUIRE(unbox.size() == 2); REQUIRE(unbox.at(0) == otherValue); REQUIRE(unbox.at(1) == defaultValue); if constexpr (!std::is_same_v) { - unbox = box.as>>().Value(); + unbox = box.template as>>().Value(); REQUIRE(unbox.size() == 2); REQUIRE(unbox.at(0) == otherValue); REQUIRE(unbox.at(1) == defaultValue); @@ -53,4 +53,4 @@ TEST_CASE("box_array") Verify({ 1,1 }); Verify({ 1,1 }); Verify({ 1,1,1,1 }); -} \ No newline at end of file +} diff --git a/test/test/box_string.cpp b/test/test/box_string.cpp new file mode 100644 index 000000000..7294eeb79 --- /dev/null +++ b/test/test/box_string.cpp @@ -0,0 +1,53 @@ +#include "pch.h" + +TEST_CASE("box_string") +{ + // hstring + { + winrt::hstring value = L"hstring"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"hstring"); + } + + // wchar_t const* (string literal) + { + auto boxed = winrt::box_value(L"literal"); + REQUIRE(winrt::unbox_value(boxed) == L"literal"); + } + + // std::wstring + { + std::wstring value = L"wstring"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"wstring"); + } + + // std::wstring_view (null-terminated) + { + std::wstring_view value = L"view"; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"view"); + } + + // std::wstring_view (not null-terminated) + // Regression test for https://github.com/microsoft/cppwinrt/issues/1527 + { + std::wstring source = L"ABCDE"; + std::wstring_view value(source.data(), 3); // "ABC" + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L"ABC"); + } + + // Empty string + { + auto boxed = winrt::box_value(winrt::hstring{}); + REQUIRE(winrt::unbox_value(boxed) == L""); + } + + // Empty wstring_view + { + std::wstring_view value; + auto boxed = winrt::box_value(value); + REQUIRE(winrt::unbox_value(boxed) == L""); + } +} diff --git a/test/test/capture.cpp b/test/test/capture.cpp index 8c75681b4..9019d1e34 100644 --- a/test/test/capture.cpp +++ b/test/test/capture.cpp @@ -3,12 +3,16 @@ using namespace winrt; using namespace Windows::Foundation; -struct __declspec(uuid("5fb96f8d-409c-42a9-99a7-8a95c1459dbd")) ICapture : ::IUnknown +struct DECLSPEC_UUID("5fb96f8d-409c-42a9-99a7-8a95c1459dbd") ICapture : ::IUnknown { virtual int32_t __stdcall GetValue() noexcept = 0; virtual int32_t __stdcall CreateMemberCapture(int32_t value, GUID const& iid, void** object) noexcept = 0; }; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(ICapture, 0x5fb96f8d, 0x409c, 0x42a9, 0x99, 0xa7, 0x8a, 0x95, 0xc1, 0x45, 0x9d, 0xbd) +#endif + struct Capture : implements { int32_t const m_value{}; diff --git a/test/test/cmd_reader.cpp b/test/test/cmd_reader.cpp index 731922fd8..a7b9a7ad1 100644 --- a/test/test/cmd_reader.cpp +++ b/test/test/cmd_reader.cpp @@ -122,7 +122,7 @@ TEST_CASE("cmd_reader") REQUIRE_FALSE(args.exists("verbose")); } - // response file #4: really really long path + // response file #4: really, really, long path { const char* argv[] = { "progname", "@respfile.txt" }; const size_t argc = _countof(argv); diff --git a/test/test/coro_ui_core.cpp b/test/test/coro_ui_core.cpp index 70d7ef071..90841cbc7 100644 --- a/test/test/coro_ui_core.cpp +++ b/test/test/coro_ui_core.cpp @@ -25,4 +25,4 @@ namespace TEST_CASE("coro_ui_core") { Async(nullptr, true); -} \ No newline at end of file +} diff --git a/test/test/custom_error.cpp b/test/test/custom_error.cpp index a39024c03..dbdf31ab9 100644 --- a/test/test/custom_error.cpp +++ b/test/test/custom_error.cpp @@ -57,11 +57,23 @@ namespace static bool s_loggerCalled = false; + static struct { + uint32_t lineNumber; + char const* fileName; + char const* functionName; + void* returnAddress; + winrt::hresult result; + } s_loggerArgs{}; + void __stdcall logger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept { - lineNumber; fileName; functionName; - REQUIRE(returnAddress); - REQUIRE(result == 0x80000018); // E_ILLEGAL_DELEGATE_ASSIGNMENT) + s_loggerArgs = { + /*.lineNumber =*/ lineNumber, + /*.fileName =*/ fileName, + /*.functionName =*/ functionName, + /*.returnAddress =*/ returnAddress, + /*.result =*/ result, + }; s_loggerCalled = true; } @@ -90,6 +102,19 @@ TEST_CASE("custom_error_logger") // Validate that handler translated exception REQUIRE_THROWS_AS(check_hresult(0x80000018), hresult_illegal_delegate_assignment); REQUIRE(s_loggerCalled); +#ifndef __cpp_lib_source_location + // In C++17 these fields cannot be filled in so they are expected to be empty. + REQUIRE(s_loggerArgs.lineNumber == 0); + REQUIRE(s_loggerArgs.fileName == nullptr); + REQUIRE(s_loggerArgs.functionName == nullptr); +#else + // GCC/Clang can only compile these tests in C++20 mode. If source_location + // is available these fields will be filled in. Don't do any checks here + // because these are already tested in `test_cpp20/custom_error.cpp`. +#endif + + REQUIRE(s_loggerArgs.returnAddress); + REQUIRE(s_loggerArgs.result == static_cast(0x80000018)); // E_ILLEGAL_DELEGATE_ASSIGNMENT) // Remove global handler winrt_throw_hresult_handler = nullptr; diff --git a/test/test/disconnected.cpp b/test/test/disconnected.cpp index 41733e2f8..be356fcb3 100644 --- a/test/test/disconnected.cpp +++ b/test/test/disconnected.cpp @@ -35,6 +35,8 @@ namespace co_return 123; } +// Exclude on mingw-w64 to suppress `-Wunused-function` +#if !defined(__MINGW32__) bool is_mta() { APTTYPE type; @@ -42,96 +44,103 @@ namespace check_hresult(CoGetApartmentType(&type, &qualifier)); return type == APTTYPE_MTA; } +#endif } -TEST_CASE("disconnected,handler") +TEST_CASE("disconnected,handler,1") { - { - event> source; + event> source; - source.add([](auto...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); + source.add([](auto...) + { + throw hresult_error(RPC_E_DISCONNECTED); + }); - auto token = source.add([](auto...) - { - throw hresult_error(E_INVALIDARG); - }); + auto token = source.add([](auto...) + { + throw hresult_error(E_INVALIDARG); + }); - // Should have two delegates - REQUIRE(source); + // Should have two delegates + REQUIRE(source); - // Should lose the disconnected delegate - source(nullptr, 123); - REQUIRE(source); + // Should lose the disconnected delegate + source(nullptr, 123); + REQUIRE(source); - // Fire the remaining delegate - source(nullptr, 123); - REQUIRE(source); + // Fire the remaining delegate + source(nullptr, 123); + REQUIRE(source); - // Remove the final delegate - source.remove(token); + // Remove the final delegate + source.remove(token); - // No more delegates - REQUIRE(!source); + // No more delegates + REQUIRE(!source); - source(nullptr, 123); - } + source(nullptr, 123); +} - { - auto async = Action(); +TEST_CASE("disconnected,handler,2") +{ + auto async = Action(); - async.Completed([](auto&&...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); - } + async.Completed([](auto&&...) + { + throw hresult_error(RPC_E_DISCONNECTED); + }); +} - { - auto async = ActionProgress(); - handle signal{ CreateEventW(nullptr, true, false, nullptr) }; +TEST_CASE("disconnected,handler,3") +{ + auto async = ActionProgress(); + handle signal{ CreateEventW(nullptr, true, false, nullptr) }; - async.Progress([](auto&&...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); + async.Progress([](auto&&...) + { + throw hresult_error(RPC_E_DISCONNECTED); + }); - async.Completed([&](auto&&...) - { - SetEvent(signal.get()); - throw hresult_error(RPC_E_DISCONNECTED); - }); + async.Completed([&](auto&&...) + { + SetEvent(signal.get()); + throw hresult_error(RPC_E_DISCONNECTED); + }); - WaitForSingleObject(signal.get(), INFINITE); - } + WaitForSingleObject(signal.get(), INFINITE); + // Give some time for to_hresult() to complete. + Sleep(500); +} - { - auto async = Operation(); +TEST_CASE("disconnected,handler,4") +{ + auto async = Operation(); - async.Completed([](auto&&...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); - } + async.Completed([](auto&&...) + { + throw hresult_error(RPC_E_DISCONNECTED); + }); +} - { - auto async = OperationProgress(); - handle signal{ CreateEventW(nullptr, true, false, nullptr) }; +TEST_CASE("disconnected,handler,5") +{ + auto async = OperationProgress(); + handle signal{ CreateEventW(nullptr, true, false, nullptr) }; - async.Progress([](auto&&...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); + async.Progress([](auto&&...) + { + throw hresult_error(RPC_E_DISCONNECTED); + }); - async.Completed([&](auto&&...) - { - SetEvent(signal.get()); - throw hresult_error(RPC_E_DISCONNECTED); - }); + async.Completed([&](auto&&...) + { + SetEvent(signal.get()); + throw hresult_error(RPC_E_DISCONNECTED); + }); - WaitForSingleObject(signal.get(), INFINITE); - } + WaitForSingleObject(signal.get(), INFINITE); + // Give some time for to_hresult() to complete. + Sleep(500); } // Custom action to simulate an out-of-process server that crashes before it can complete. @@ -139,7 +148,7 @@ struct non_agile_abandoned_action : implements disconnect) : m_disconnect(disconnect) {} - static fire_and_forget final_release(std::unique_ptr self) + static fire_and_forget final_release(std::unique_ptr /*self*/) { // The C++/WinRT m_handler is agile but not context-aware, // so we need to make sure to release it from the context it @@ -165,6 +174,12 @@ struct non_agile_abandoned_action : implements m_disconnect; }; +// Not yet buildable on mingw-w64. +// Missing CLSID_ContextSwitcher, IID_ICallbackWithNoReentrancyToApplicationSTA +// and __uuidof(IContextCallback). Also, the lambda needs to have __stdcall +// specified on it but there is a Clang crash bug blocking this: +// https://github.com/llvm/llvm-project/issues/58366 +#if !defined(__MINGW32__) namespace { template @@ -228,7 +243,12 @@ TEST_CASE("disconnected,action") REQUIRE_THROWS_MATCHES(result.get(), hresult_error, holds_hresult(RPC_E_DISCONNECTED)); } +#if defined(__clang__) && (defined(_M_IX86) || defined(__i386__)) +// FIXME: Test is known to crash with exit code 0xc000070a on x86 when built with Clang. +TEST_CASE("disconnected,double", "[.clang-crash]") +#else TEST_CASE("disconnected,double") +#endif { // The double-disconnect case, where the IAsyncAction disconnects, // and tries to return to the original context, but it too has disconnected! @@ -274,3 +294,4 @@ TEST_CASE("disconnected,double") test.get(); } +#endif diff --git a/test/test/error_info.cpp b/test/test/error_info.cpp index 5b312c451..96e2b2731 100644 --- a/test/test/error_info.cpp +++ b/test/test/error_info.cpp @@ -35,7 +35,7 @@ TEST_CASE("error_info") try { check_hresult(winrt_error_info()); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const& e) { @@ -45,7 +45,7 @@ TEST_CASE("error_info") try { check_hresult(com_error_info()); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const& e) { @@ -55,7 +55,7 @@ TEST_CASE("error_info") try { check_hresult(no_error_info()); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const& e) { @@ -66,7 +66,7 @@ TEST_CASE("error_info") { // This API reports using WinRT error info. Windows::Foundation::Uri(L"bad"); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_invalid_argument const& e) { @@ -78,7 +78,7 @@ TEST_CASE("error_info") // This API reports using COM error info. Windows::Data::Xml::Dom::XmlDocument doc; doc.LoadXml(L"bad"); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_error const& e) { diff --git a/test/test/event_clear.cpp b/test/test/event_clear.cpp index 54db2cef7..54f3d62b7 100644 --- a/test/test/event_clear.cpp +++ b/test/test/event_clear.cpp @@ -16,11 +16,13 @@ TEST_CASE("event_clear") { counter += 1; }); + (void)a; auto b = event.add([&](auto && ...) { counter += 10; }); + (void)b; REQUIRE(counter == 0); event(0, 0); diff --git a/test/test/event_deferral.cpp b/test/test/event_deferral.cpp index 9b83a2602..e5b538ca2 100644 --- a/test/test/event_deferral.cpp +++ b/test/test/event_deferral.cpp @@ -38,7 +38,7 @@ namespace // This exercises the short-circuit logic in deferrable_event_args. auto NoDeferralHandler() { - return [=](Class const& sender, DeferrableEventArgs const& args) + return [this](Class const& sender, DeferrableEventArgs const& args) { REQUIRE(sender == c); args.IncrementCounter(); @@ -50,7 +50,7 @@ namespace // deferrable_event_args. auto PointlessDeferralHandler() { - return [=](Class const& sender, DeferrableEventArgs const& args) + return [this](Class const& sender, DeferrableEventArgs const& args) { REQUIRE(sender == c); auto deferral = args.GetDeferral(); @@ -61,15 +61,19 @@ namespace auto TakeDeferralHandler(int startState, int finishState) { - return [=](Class sender, DeferrableEventArgs args) -> fire_and_forget + return [this, startState, finishState](Class sender, DeferrableEventArgs args) -> fire_and_forget { + // Captures will go out of scope after the first co_await call. Copy anything needed after that point. + const auto startStateCopy = startState; + const auto finishStateCopy = finishState; + REQUIRE(sender == c); auto deferral = args.GetDeferral(); co_await resume_background(); - wait_for_state(startState); + wait_for_state(startStateCopy); args.IncrementCounter(); deferral.Complete(); - go_to_state(finishState); + go_to_state(finishStateCopy); }; } }; diff --git a/test/test/fast_iterator.cpp b/test/test/fast_iterator.cpp index 71ed6a918..f9e02dcec 100644 --- a/test/test/fast_iterator.cpp +++ b/test/test/fast_iterator.cpp @@ -48,7 +48,7 @@ TEST_CASE("fast_iterator") REQUIRE(2 - (vbegin + 4) > vbegin); REQUIRE(vbegin < vbegin + 2); REQUIRE(vbegin + 2 - 2 == vbegin); - REQUIRE(end(v) - begin(v) == v.Size()); + REQUIRE(static_cast(end(v) - begin(v)) == v.Size()); REQUIRE((begin(v) + 3)[-1] == 4); } { diff --git a/test/test/generic_type_names.cpp b/test/test/generic_type_names.cpp index 580d69ac3..5a2d648a2 100644 --- a/test/test/generic_type_names.cpp +++ b/test/test/generic_type_names.cpp @@ -120,6 +120,7 @@ TEST_CASE("generic_type_names") IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); +#if __has_include() REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", @@ -134,6 +135,7 @@ TEST_CASE("generic_type_names") IReference); REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", IReference); +#endif // Enums, structs, IInspectable, classes, and delegates diff --git a/test/test/generic_types.cpp b/test/test/generic_types.cpp index 98ffd12eb..081155cd2 100644 --- a/test/test/generic_types.cpp +++ b/test/test/generic_types.cpp @@ -8,9 +8,5 @@ TEST_CASE("generic_types") REQUIRE_EQUAL_NAME(L"Windows.Foundation.Uri", Uri); REQUIRE_EQUAL_NAME(L"Windows.Foundation.PropertyType", PropertyType); REQUIRE_EQUAL_NAME(L"Windows.Foundation.Point", Point); - - // Clang 9 doesn't think this is a constant expression. -#ifndef __clang__ REQUIRE_EQUAL_NAME(L"Windows.Foundation.IStringable", IStringable); -#endif } diff --git a/test/test/generic_types.h b/test/test/generic_types.h index d96b3bbfe..5ddba76d9 100644 --- a/test/test/generic_types.h +++ b/test/test/generic_types.h @@ -3,7 +3,9 @@ using namespace winrt; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; +#if __has_include() using namespace Windows::Foundation::Numerics; +#endif using namespace std::literals; #define REQUIRE_EQUAL_GUID(left, ...) STATIC_REQUIRE(equal(guid(left), guid_of<__VA_ARGS__>())); @@ -92,6 +94,7 @@ namespace REQUIRE_EQUAL_GUID("84F14C22-A00A-5272-8D3D-82112E66DF00", IReference); REQUIRE_EQUAL_GUID("80423F11-054F-5EAC-AFD3-63B6CE15E77B", IReference); REQUIRE_EQUAL_GUID("61723086-8e53-5276-9f36-2a4bb93e2b75", IReference); +#if __has_include() REQUIRE_EQUAL_GUID("48F6A69E-8465-57AE-9400-9764087F65AD", IReference); REQUIRE_EQUAL_GUID("1EE770FF-C954-59CA-A754-6199A9BE282C", IReference); REQUIRE_EQUAL_GUID("A5E843C9-ED20-5339-8F8D-9FE404CF3654", IReference); @@ -99,6 +102,7 @@ namespace REQUIRE_EQUAL_GUID("DACBFFDC-68EF-5FD0-B657-782D0AC9807E", IReference); REQUIRE_EQUAL_GUID("B27004BB-C014-5DCE-9A21-799C5A3C1461", IReference); REQUIRE_EQUAL_GUID("46D542A1-52F7-58E7-ACFC-9A6D364DA022", IReference); +#endif // Enums, structs, IInspectable, classes, and delegates diff --git a/test/test/guid.cpp b/test/test/guid.cpp index 3dff63088..dc91c7d3c 100644 --- a/test/test/guid.cpp +++ b/test/test/guid.cpp @@ -20,7 +20,9 @@ TEST_CASE("guid") STATIC_REQUIRE_GUID_EQUAL(winrt::guid("00112233-4455-6677-8899-aabbccddeeff"), expected); REQUIRE(winrt::guid("00112233-4455-6677-8899-aabbccddeeff") == expected); - REQUIRE(winrt::guid({ "{00112233-4455-6677-8899-aabbccddeeff}" + 1, 36 }) == expected); + REQUIRE(winrt::guid({ &"{00112233-4455-6677-8899-aabbccddeeff}"[1], 36 }) == expected); + REQUIRE(winrt::guid("{00112233-4455-6677-8899-aabbccddeeff}") == expected); + REQUIRE(winrt::guid("(00112233-4455-6677-8899-aabbccddeeff)") == expected); REQUIRE_THROWS_AS(winrt::guid(""), std::invalid_argument); REQUIRE_THROWS_AS(winrt::guid("not a guid"), std::invalid_argument); @@ -28,9 +30,8 @@ TEST_CASE("guid") REQUIRE_THROWS_AS(winrt::guid("too long string that's also not a guid"), std::invalid_argument); REQUIRE_THROWS_AS(winrt::guid("00112233-4455-6677-8899-aabbccddeeff with extra"), std::invalid_argument); REQUIRE_THROWS_AS(winrt::guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"), std::invalid_argument); - REQUIRE_THROWS_AS(winrt::guid("{00112233-4455-6677-8899-aabbccddeeff}"), std::invalid_argument); // Verify that you can constexpr-construct a guid from a GUID. constexpr winrt::guid from_abi_guid = GUID{ 0x00112233, 0x4455, 0x6677, { 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff } }; STATIC_REQUIRE_GUID_EQUAL(from_abi_guid, expected); -} \ No newline at end of file +} diff --git a/test/test/guid_include.cpp b/test/test/guid_include.cpp index 07a7d4988..212b6b0e5 100644 --- a/test/test/guid_include.cpp +++ b/test/test/guid_include.cpp @@ -1,3 +1,3 @@ #include "winrt/base.h" -#include +#include #include "winrt/Windows.Foundation.h" diff --git a/test/test/hresult_class_not_registered.cpp b/test/test/hresult_class_not_registered.cpp index d1717569a..78223030a 100644 --- a/test/test/hresult_class_not_registered.cpp +++ b/test/test/hresult_class_not_registered.cpp @@ -20,11 +20,11 @@ TEST_CASE("hresult_class_not_registered") try { Async().get(); - FAIL(L"Previous line should throw"); + FAIL("Previous line should throw"); } catch (hresult_class_not_registered const& e) { REQUIRE(e.message() == L"test message"); REQUIRE(e.code() == REGDB_E_CLASSNOTREG); } -} \ No newline at end of file +} diff --git a/test/test/initialize.cpp b/test/test/initialize.cpp new file mode 100644 index 000000000..e5532fe2d --- /dev/null +++ b/test/test/initialize.cpp @@ -0,0 +1,119 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; + +namespace +{ + class some_exception : public std::runtime_error + { + public: + some_exception() noexcept + : runtime_error("some_exception") + { + } + }; + + template + struct InitializeT : implements + { + bool& m_initialize_called; + + InitializeT(bool& initialize_called) : m_initialize_called(initialize_called) + { + } + + ~InitializeT() + { + } + + void InitializeComponent() + { + m_initialize_called = true; + throw some_exception(); + } + + hstring ToString() + { + return {}; + } + }; + + struct Initialize : InitializeT + { + Initialize(bool& initialize_called) : InitializeT(initialize_called) + { + } + }; + + struct ThrowingDerived : InitializeT + { + ThrowingDerived(bool& initialize_called) : InitializeT(initialize_called) + { + throw some_exception(); + } + }; + + struct OverriddenInitialize : InitializeT + { + OverriddenInitialize(bool& initialize_called) : InitializeT(initialize_called) + { + } + + void InitializeComponent() + { + m_initialize_called = true; + } + }; +} + +TEST_CASE("initialize") +{ + // Ensure that failure to initialize is failure to instantiate, with no side effects + { + bool initialize_called{}; + bool exception_caught{}; + try + { + make(initialize_called); + } + catch (some_exception const&) + { + exception_caught = true; + } + REQUIRE(initialize_called); + REQUIRE(exception_caught); + } + + // Ensure that base is never initialized if exception thrown from derived/base constructor + { + bool initialize_called{}; + bool exception_caught{}; + try + { + make(initialize_called); + } + catch (some_exception const&) + { + exception_caught = true; + } + REQUIRE(!initialize_called); + REQUIRE(exception_caught); + } + + // Support for overriding initialization for post-processing (e.g., accessing Xaml properties) + { + bool initialize_called{}; + bool exception_caught{}; + try + { + make(initialize_called); + } + catch (some_exception const&) + { + exception_caught = true; + } + REQUIRE(initialize_called); + REQUIRE(!exception_caught); + } +} diff --git a/test/test/inspectable_interop.cpp b/test/test/inspectable_interop.cpp index d693a6062..6a8db907a 100644 --- a/test/test/inspectable_interop.cpp +++ b/test/test/inspectable_interop.cpp @@ -1,3 +1,4 @@ +#include "mingw_com_support.h" #include #include "winrt/Windows.Foundation.h" #include "catch.hpp" @@ -6,11 +7,25 @@ using namespace winrt; namespace { - struct __declspec(uuid("ed0dd761-c31e-4803-8cf9-22a2cb20ec47")) IBadInterop : ::IInspectable + struct DECLSPEC_UUID("ed0dd761-c31e-4803-8cf9-22a2cb20ec47") IBadInterop : ::IInspectable { virtual int32_t __stdcall JustSayNo() noexcept = 0; }; +} + +#ifdef __CRT_UUID_DECL +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +__CRT_UUID_DECL(IBadInterop, 0xed0dd761, 0xc31e, 0x4803, 0x8c, 0xf9, 0x22, 0xa2, 0xcb, 0x20, 0xec, 0x47) +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#endif +namespace +{ struct Sample : implements { Windows::Foundation::IInspectable ActivateInstance() @@ -18,15 +33,29 @@ namespace throw hresult_not_implemented(); } - hstring GetRuntimeClassName() + hstring GetRuntimeClassName() const { return L"Sample"; } - Windows::Foundation::TrustLevel GetTrustLevel() +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverloaded-virtual" +#endif +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Woverloaded-virtual" +#endif + Windows::Foundation::TrustLevel GetTrustLevel() const noexcept { return Windows::Foundation::TrustLevel::PartialTrust; } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif int32_t __stdcall JustSayNo() noexcept final { diff --git a/test/test/interop.cpp b/test/test/interop.cpp index 9ca4c94ea..ec5476d15 100644 --- a/test/test/interop.cpp +++ b/test/test/interop.cpp @@ -1,18 +1,24 @@ #include "pch.h" #include -struct __declspec(uuid("5040a5f4-796a-42ff-9f06-be89137a518f")) IBase : IUnknown +struct DECLSPEC_UUID("5040a5f4-796a-42ff-9f06-be89137a518f") IBase : IUnknown { }; -struct __declspec(uuid("529fed32-514f-4150-b1ba-15b47df700b7")) IDerived : IBase +struct DECLSPEC_UUID("529fed32-514f-4150-b1ba-15b47df700b7") IDerived : IBase { }; -struct __declspec(uuid("b81fb2a2-eab4-488a-96a7-434873c2c20b")) IMoreDerived : IDerived +struct DECLSPEC_UUID("b81fb2a2-eab4-488a-96a7-434873c2c20b") IMoreDerived : IDerived { }; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IBase, 0x5040a5f4, 0x796a, 0x42ff, 0x9f, 0x06, 0xbe, 0x89, 0x13, 0x7a, 0x51, 0x8f) +__CRT_UUID_DECL(IDerived, 0x529fed32, 0x514f, 0x4150, 0xb1, 0xba, 0x15, 0xb4, 0x7d, 0xf7, 0x00, 0xb7) +__CRT_UUID_DECL(IMoreDerived, 0xb81fb2a2, 0xeab4, 0x488a, 0x96, 0xa7, 0x43, 0x48, 0x73, 0xc2, 0xc2, 0x0b) +#endif + namespace winrt { template<> bool is_guid_of(guid const& id) noexcept diff --git a/test/test/main.cpp b/test/test/main.cpp index 7c55cbbed..1481be4dd 100644 --- a/test/test/main.cpp +++ b/test/test/main.cpp @@ -1,4 +1,9 @@ +#include #define CATCH_CONFIG_RUNNER + +// Force reportFatal to be available on mingw-w64 +#define CATCH_CONFIG_WINDOWS_SEH + #include "catch.hpp" #include "winrt/base.h" @@ -8,6 +13,11 @@ int main(int const argc, char** argv) { init_apartment(); std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + SetThreadUILanguage(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)); return Catch::Session().run(argc, argv); } diff --git a/test/test/missing_required_interfaces.cpp b/test/test/missing_required_interfaces.cpp new file mode 100644 index 000000000..237e4ff41 --- /dev/null +++ b/test/test/missing_required_interfaces.cpp @@ -0,0 +1,25 @@ +#include "pch.h" + +// Unset lean and mean so we can implement a type from the test_component namespace +#undef WINRT_LEAN_AND_MEAN +#include + +namespace +{ + struct LiesAboutInheritance : public winrt::implements + { + LiesAboutInheritance() = default; + void StubMethod() {} + }; +} + +TEST_CASE("missing_required_interfaces") +{ + auto lies = winrt::make_self().as(); + REQUIRE(lies); + REQUIRE_NOTHROW(lies.StubMethod()); + + // The IStringable::ToString method does not exist on this type. In previous versions of cppwinrt + // this line would crash with a nullptr deference. It now throws an exception. + REQUIRE_THROWS_AS(lies.ToString(), winrt::hresult_error); +} diff --git a/test/test/multi_threaded_common.h b/test/test/multi_threaded_common.h index 22a3e6577..3ed687743 100644 --- a/test/test/multi_threaded_common.h +++ b/test/test/multi_threaded_common.h @@ -45,7 +45,7 @@ namespace concurrent_collections // for the first time on the background thread. enum class collection_action { - none, push_back, insert, erase, at, lookup + none, push_back, insert, erase, at, lookup, advance }; // All of our concurrency tests consists of starting an @@ -149,11 +149,10 @@ namespace concurrent_collections container const* owner; concurrency_checked_random_access_iterator() : owner(nullptr) {} - concurrency_checked_random_access_iterator(container const* c, iterator it) : owner(c), iterator(it) {} + concurrency_checked_random_access_iterator(container const* c, iterator it) : iterator(it), owner(c) {} // Implicit conversion from non-const iterator to const iterator. - template>> - concurrency_checked_random_access_iterator(concurrency_checked_random_access_iterator other) : owner(other.owner), iterator(other.inner()) { } + concurrency_checked_random_access_iterator(concurrency_checked_random_access_iterator other) : iterator(other.inner()), owner(other.owner) { } concurrency_checked_random_access_iterator(concurrency_checked_random_access_iterator const&) = default; concurrency_checked_random_access_iterator& operator=(concurrency_checked_random_access_iterator const&) = default; @@ -166,16 +165,23 @@ namespace concurrent_collections return owner->dereference_iterator(inner()); } - // inherited: pointer operator->() const; + pointer operator->() const + { + auto guard = owner->lock_const(); + owner->call_hook(collection_action::at); + return iterator::operator->(); + } concurrency_checked_random_access_iterator& operator++() { + owner->call_hook(collection_action::advance); ++inner(); return *this; } concurrency_checked_random_access_iterator& operator++(int) { + owner->call_hook(collection_action::advance); auto prev = *this; ++inner(); return prev; @@ -183,12 +189,14 @@ namespace concurrent_collections concurrency_checked_random_access_iterator& operator--() { + owner->call_hook(collection_action::advance); --inner(); return *this; } concurrency_checked_random_access_iterator& operator--(int) { + owner->call_hook(collection_action::advance); auto prev = *this; --inner(); return prev; @@ -196,6 +204,7 @@ namespace concurrent_collections concurrency_checked_random_access_iterator& operator+=(difference_type offset) { + owner->call_hook(collection_action::advance); inner() += offset; return *this; } @@ -207,6 +216,7 @@ namespace concurrent_collections concurrency_checked_random_access_iterator& operator-=(difference_type offset) { + owner->call_hook(collection_action::advance); inner() -= offset; return *this; } @@ -257,7 +267,7 @@ namespace concurrent_collections concurrency_guard() = default; concurrency_guard(concurrency_guard const& other) noexcept - : m_lock(0), hook(other.hook) + : hook(other.hook), m_lock(0) { auto guard = other.lock_nonconst(); } diff --git a/test/test/multi_threaded_map.cpp b/test/test/multi_threaded_map.cpp index 2f81d3789..ffa9988ba 100644 --- a/test/test/multi_threaded_map.cpp +++ b/test/test/multi_threaded_map.cpp @@ -63,7 +63,7 @@ namespace } else { - return static_cast>(winrt::make>(std::move(values))); + return static_cast>(winrt::make>(std::move(values))); } } @@ -90,7 +90,7 @@ namespace using const_reverse_iterator = std::reverse_iterator; using node_type = typename inner::node_type; - mapped_type& operator[](const key_type& key) + mapped_type& operator[](const key_type& /*key*/) { auto guard = concurrency_guard::lock_nonconst(); concurrency_guard::call_hook(collection_action::at); @@ -171,7 +171,7 @@ namespace auto hook = raw.hook; // Convert the raw_map into the desired Windows Runtime map interface. - auto m = make_threaded_map(std::move(raw)); + auto m = make_threaded_map(std::move(raw)); auto race = [&](collection_action action, auto&& background, auto&& foreground) { @@ -237,7 +237,7 @@ namespace { // MoveNext vs Remove bool moved = false; - race(collection_action::at, [&] + race(collection_action::advance, [&] { try { @@ -273,7 +273,7 @@ namespace { // MoveNext vs Insert bool moved = false; - race(collection_action::at, [&] + race(collection_action::advance, [&] { try { diff --git a/test/test/multi_threaded_vector.cpp b/test/test/multi_threaded_vector.cpp index 24b27d0bc..3f7408510 100644 --- a/test/test/multi_threaded_vector.cpp +++ b/test/test/multi_threaded_vector.cpp @@ -81,7 +81,7 @@ namespace } else { - return vector.as>(); + return vector.template as>(); } } } diff --git a/test/test/names.cpp b/test/test/names.cpp index 7730fe82e..5d978a825 100644 --- a/test/test/names.cpp +++ b/test/test/names.cpp @@ -16,4 +16,5 @@ TEST_CASE("names") check_terminated(name_of()); check_terminated(name_of>()); check_terminated(name_of>()); + check_terminated(name_of()); } diff --git a/test/test/notify_awaiter.cpp b/test/test/notify_awaiter.cpp deleted file mode 100644 index dd936928a..000000000 --- a/test/test/notify_awaiter.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - using std::experimental::suspend_never; - - // Never suspends. - // Allows copying, but asserts if you try. - struct suspend_never_but_assert_if_copied : suspend_never - { - suspend_never_but_assert_if_copied() = default; - suspend_never_but_assert_if_copied(suspend_never_but_assert_if_copied const&) - { - REQUIRE(false); - } - }; - - // The bad_awaiter asserts if it ever gets used. - // Use it for ambiguous alternatives we don't want to pick. - struct bad_awaiter : suspend_never - { - void await_resume() const noexcept - { - REQUIRE(false); - } - }; - - // If the only awaitable is the member awaitable, then use it. - struct member_awaitable : suspend_never_but_assert_if_copied - { - }; - - // Should pick the free operator co_await over the member awaitable. - struct free_operator_awaitable : bad_awaiter - { - }; - auto operator co_await(free_operator_awaitable) - { - return suspend_never_but_assert_if_copied{}; - } - - // Should pick the member operator co_await over the member awaitable. - struct member_operator_awaitable : bad_awaiter - { - auto operator co_await() - { - return suspend_never_but_assert_if_copied{}; - } - }; - - // Verify that we can await non-copyable objects. - struct no_copy_awaitable : suspend_never - { - no_copy_awaitable() = default; - no_copy_awaitable(no_copy_awaitable const&) = delete; - }; - - // operator co_await takes precedence over member awaitable. - struct ambiguous_awaitable1 : bad_awaiter - { - auto operator co_await() - { - return suspend_never_but_assert_if_copied{}; - } - }; - - // This awaitable supports both member co_await - // and free co_await, and the free co_await is a - // better match if invoked on an lvalue. We don't try - // to support this case. We just declare it as ambiguous. - struct ambiguous_awaitable2 : bad_awaiter - { - auto operator co_await() const - { - return bad_awaiter{}; - } - }; - suspend_never_but_assert_if_copied operator co_await(ambiguous_awaitable2&) - { - return {}; - } - - // We invoke this on an lvalue, so the member co_await is unavailable. - // Verify that the unavailable co_await is ignored. - struct ambiguous_awaitable3 : suspend_never_but_assert_if_copied - { - auto operator co_await()&& - { - return bad_awaiter{}; - } - }; - - IAsyncAction AsyncAction() - { - co_return; - } - IAsyncActionWithProgress AsyncActionWithProgress() - { - co_return; - } - IAsyncOperation AsyncOperation() - { - co_return 0; - } - IAsyncOperationWithProgress AsyncOperationWithProgress() - { - co_return 0; - } - - enum class notification - { - suspend, - resume, - }; - - static std::vector> watcher; - static handle start_racing{ CreateEventW(nullptr, true, false, nullptr) }; - constexpr size_t test_suspension_points = 13; - - IAsyncAction Async() - { - co_await resume_on_signal(start_racing.get()); - co_await resume_background(); - co_await resume_background(); - co_await member_awaitable{}; - co_await free_operator_awaitable{}; - co_await member_operator_awaitable{}; - co_await no_copy_awaitable{}; - co_await ambiguous_awaitable1{}; - // co_await ambiguous_awaitable2{}; // does not compile - ambiguous_awaitable3 awaitable3; - co_await awaitable3; - co_await AsyncAction(); - co_await AsyncActionWithProgress(); - co_await AsyncOperation(); - co_await AsyncOperationWithProgress(); - } -} - -TEST_CASE("notify_awaiter") -{ - // Everything works fine when nobody is watching. - - REQUIRE(!winrt_suspend_handler); - REQUIRE(!winrt_resume_handler); - SetEvent(start_racing.get()); - Async().get(); - ResetEvent(start_racing.get()); - - // Hook up some watchers. - - winrt_suspend_handler = [](void const* token) noexcept - { - watcher.push_back({ token, notification::suspend }); - }; - - winrt_resume_handler = [](void const* token) noexcept - { - auto last = watcher.back(); - REQUIRE(last.first == token); - REQUIRE(last.second == notification::suspend); - watcher.push_back({ token, notification::resume }); - }; - - // Prepare a coroutine. - REQUIRE(watcher.empty()); - auto async = Async(); - - // Give coroutine a moment to get to the starting line. - Sleep(1000); - - // Coroutine should have suspended once. - REQUIRE(watcher.size() == 1); - REQUIRE(watcher.back().second == notification::suspend); - - // And the race is on! - SetEvent(start_racing.get()); - async.get(); - - // Each suspension point should have been recorded plus one for each final_suspend. - REQUIRE(watcher.size() == 2 * test_suspension_points + 5); - - // Remove watchers. - - winrt_suspend_handler = nullptr; - winrt_resume_handler = nullptr; -} diff --git a/test/test/numerics.cpp b/test/test/numerics.cpp index cfc73c0dd..23b2dfb34 100644 --- a/test/test/numerics.cpp +++ b/test/test/numerics.cpp @@ -5,9 +5,11 @@ using namespace Windows::Foundation::Numerics; TEST_CASE("numerics") { +#if __has_include() // Basic smoke test exercising SIMD intrinsics used by numerics. auto one = float4::one(); REQUIRE(one * one == one); +#endif } diff --git a/test/test/out_params.cpp b/test/test/out_params.cpp index 7aafb63ae..7fd2f536e 100644 --- a/test/test/out_params.cpp +++ b/test/test/out_params.cpp @@ -134,7 +134,7 @@ TEST_CASE("out_params") REQUIRE(value[3] == nullptr); } { - std::array value{ {L"First", L"Second"} }; + std::array value{ { { L"First" }, { L"Second"} } }; object.RefStructArray(value); REQUIRE(value[0].First == L"1"); REQUIRE(value[0].Second == L"2"); @@ -260,7 +260,7 @@ TEST_CASE("out_params") REQUIRE(value[3] == nullptr); } { - std::array value{ {L"First", L"Second"} }; + std::array value{ { { L"First" }, { L"Second"} } }; REQUIRE_THROWS_AS(object.RefStructArray(value), hresult_invalid_argument); REQUIRE(value[0].First == L""); REQUIRE(value[0].Second == L""); diff --git a/test/test/pch.h b/test/test/pch.h index 916e8fe8f..24d65c225 100644 --- a/test/test/pch.h +++ b/test/test/pch.h @@ -2,6 +2,8 @@ #pragma warning(4: 4458) // ensure we compile clean with this warning enabled +#include "mingw_com_support.h" + #define WINRT_LEAN_AND_MEAN #include #include "winrt/Windows.Foundation.Collections.h" @@ -45,4 +47,4 @@ using async_return_type = decltype(std::declval().GetResults()); template using async_progress_type = typename async_traits>::progress_type; template -inline constexpr bool has_async_progress = !std::is_same_v>::progress_type>; +inline constexpr bool has_async_progress = !std::is_same_v>::progress_type>; diff --git a/test/test/rational.cpp b/test/test/rational.cpp new file mode 100644 index 000000000..c34dbce38 --- /dev/null +++ b/test/test/rational.cpp @@ -0,0 +1,18 @@ +#include "pch.h" +#include "winrt/test_component.h" +#include "winrt/Windows.Foundation.Numerics.h" + +using namespace winrt; +using namespace test_component; + +TEST_CASE("rational") +{ + Simple simple; + Windows::Foundation::Numerics::Rational rational = simple.ReturnRational(); + REQUIRE(rational.Numerator == 123); + REQUIRE(rational.Denominator == 456); + + Windows::Foundation::Numerics::float2 vector2 = simple.ReturnVector2(); + REQUIRE(vector2.x == 123.0); + REQUIRE(vector2.y == 456.0); +} diff --git a/test/test/reference_boxing.cpp b/test/test/reference_boxing.cpp new file mode 100644 index 000000000..c6e300886 --- /dev/null +++ b/test/test/reference_boxing.cpp @@ -0,0 +1,268 @@ +#include "pch.h" +#include +#include +#include + +using namespace winrt; +using namespace Windows::Foundation; + +// Scalar box_value now produces a local IReference/IPropertyValue instead of hopping to +// combase PropertyValue. These confirm it reports the correct PropertyType, keeps combase-style +// numeric conversion on mismatched getters, and round-trips through unbox_value. +TEST_CASE("reference_boxing") +{ + { + auto boxed = box_value(42); + auto pv = boxed.as(); + REQUIRE(pv.Type() == PropertyType::Int32); + REQUIRE(pv.IsNumericScalar()); + REQUIRE(pv.GetInt32() == 42); + REQUIRE(pv.GetInt16() == 42); + REQUIRE(pv.GetDouble() == 42.0); + // A scalar reference holds no array, so every array getter routes through get_as and throws. + { + com_array ints; + REQUIRE_THROWS_AS(pv.GetInt32Array(ints), hresult_not_implemented); + com_array strings; + REQUIRE_THROWS_AS(pv.GetStringArray(strings), hresult_not_implemented); + } + REQUIRE(unbox_value(boxed) == 42); + } + + { + auto pv = box_value(3.5).as(); + REQUIRE(pv.Type() == PropertyType::Double); + REQUIRE(pv.IsNumericScalar()); + REQUIRE(pv.GetDouble() == 3.5); + REQUIRE(pv.GetSingle() == 3.5f); + } + + { + auto pv = box_value(hstring{ L"hello" }).as(); + REQUIRE(pv.Type() == PropertyType::String); + REQUIRE(!pv.IsNumericScalar()); + REQUIRE(pv.GetString() == L"hello"); + REQUIRE_THROWS_AS(pv.GetInt32(), hresult_not_implemented); + } + + { + auto pv = box_value(true).as(); + REQUIRE(pv.Type() == PropertyType::Boolean); + REQUIRE(!pv.IsNumericScalar()); + REQUIRE(pv.GetBoolean()); + REQUIRE_THROWS_AS(pv.GetInt32(), hresult_not_implemented); + } + + { + guid const g{ 0x11223344, 0x5566, 0x7788, { 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00 } }; + auto pv = box_value(g).as(); + REQUIRE(pv.Type() == PropertyType::Guid); + REQUIRE(!pv.IsNumericScalar()); + REQUIRE(pv.GetGuid() == g); + } + + { + auto pv = box_value(static_cast(7)).as(); + REQUIRE(pv.Type() == PropertyType::UInt8); + REQUIRE(pv.IsNumericScalar()); + REQUIRE(pv.GetUInt8() == 7); + REQUIRE(unbox_value(box_value(static_cast(7))) == 7); + } + + // DateTime, TimeSpan, and Point are also boxed in-process now (they still marshal by value). + { + Point const point{ 3.0f, 4.0f }; + auto pv = box_value(point).as(); + REQUIRE(pv.Type() == PropertyType::Point); + REQUIRE(!pv.IsNumericScalar()); + REQUIRE(pv.GetPoint().X == point.X); + REQUIRE(pv.GetPoint().Y == point.Y); + auto const round_tripped = unbox_value(box_value(point)); + REQUIRE(round_tripped.X == point.X); + REQUIRE(round_tripped.Y == point.Y); + REQUIRE_THROWS_AS(pv.GetInt32(), hresult_not_implemented); + } + + { + TimeSpan const span{ std::chrono::seconds{ 90 } }; + auto pv = box_value(span).as(); + REQUIRE(pv.Type() == PropertyType::TimeSpan); + REQUIRE(!pv.IsNumericScalar()); + REQUIRE(pv.GetTimeSpan() == span); + REQUIRE(unbox_value(box_value(span)) == span); + } + + { + DateTime const when{ TimeSpan{ std::chrono::seconds{ 1000 } } }; + auto pv = box_value(when).as(); + REQUIRE(pv.Type() == PropertyType::DateTime); + REQUIRE(!pv.IsNumericScalar()); + REQUIRE(pv.GetDateTime() == when); + REQUIRE(unbox_value(box_value(when)) == when); + } +} + +// Array boxing produces a local IReferenceArray / IPropertyValue (no combase PropertyValue) for the +// stock element types. Confirm the array PropertyType, round-trips, and the get_as throw behavior. +TEST_CASE("reference_boxing arrays") +{ + { + int32_t values[]{ 0, 42, 1729, -1 }; + auto boxed = box_value(com_array{ std::begin(values), std::end(values) }); + auto pv = boxed.as(); + REQUIRE(pv.Type() == PropertyType::Int32Array); + REQUIRE(!pv.IsNumericScalar()); + + com_array out; + pv.GetInt32Array(out); + REQUIRE(out == array_view{ values }); + + // A scalar getter on an array PV throws, and so does a mismatched-element array getter. + REQUIRE_THROWS_AS(pv.GetInt32(), hresult_not_implemented); + com_array wrong; + REQUIRE_THROWS_AS(pv.GetDoubleArray(wrong), hresult_not_implemented); + + REQUIRE(unbox_value>(boxed) == array_view{ values }); + REQUIRE(boxed.as>().Value() == array_view{ values }); + } + + // guid arrays are local too. + { + guid values[]{ + { 0x11223344, 0x5566, 0x7788, { 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00 } }, + { 0x00112233, 0x4455, 0x6677, { 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF } } }; + auto boxed = box_value(com_array{ std::begin(values), std::end(values) }); + REQUIRE(boxed.as().Type() == PropertyType::GuidArray); + REQUIRE(unbox_value>(boxed) == array_view{ values }); + } +} + +// The local array reference must marshal by value across processes just like the scalar one: its +// IMarshal reports the same unmarshal class as a genuine combase array PropertyValue, and not the +// free-threaded (by-reference) class. +TEST_CASE("reference_boxing array marshal by value") +{ + int32_t values[]{ 1, 2, 3 }; + auto boxed = box_value(com_array{ std::begin(values), std::end(values) }); + REQUIRE(boxed.try_as()); + auto ours = boxed.as(); + + auto genuine = PropertyValue::CreateInt32Array(values); + auto reference = genuine.as(); + + guid our_clsid{}; + guid reference_clsid{}; + check_hresult(ours->GetUnmarshalClass(guid_of(), get_unknown(boxed), + MSHCTX_DIFFERENTMACHINE, nullptr, MSHLFLAGS_NORMAL, &our_clsid)); + check_hresult(reference->GetUnmarshalClass(guid_of(), get_unknown(genuine), + MSHCTX_DIFFERENTMACHINE, nullptr, MSHLFLAGS_NORMAL, &reference_clsid)); + + REQUIRE(our_clsid == reference_clsid); + + guid const free_threaded_marshaler{ 0x0000033A, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; + REQUIRE(our_clsid != free_threaded_marshaler); +} + +// The in-proc reference stays agile but must marshal by value across processes, exactly like a real +// combase PropertyValue. Prove it by confirming our IMarshal reports the SAME unmarshal class as a +// genuine PropertyValue - i.e. we forward marshaling to combase - and specifically NOT the +// free-threaded (marshal-by-reference) class the default agile path would have used. +TEST_CASE("reference_boxing marshal by value") +{ + auto boxed = box_value(42); + REQUIRE(boxed.try_as()); + auto ours = boxed.as(); + + auto genuine = PropertyValue::CreateInt32(42); + auto reference = genuine.as(); + + guid our_clsid{}; + guid reference_clsid{}; + check_hresult(ours->GetUnmarshalClass(guid_of(), get_unknown(boxed), + MSHCTX_DIFFERENTMACHINE, nullptr, MSHLFLAGS_NORMAL, &our_clsid)); + check_hresult(reference->GetUnmarshalClass(guid_of(), get_unknown(genuine), + MSHCTX_DIFFERENTMACHINE, nullptr, MSHLFLAGS_NORMAL, &reference_clsid)); + + REQUIRE(our_clsid == reference_clsid); + + // CLSID_InProcFreeMarshaler - the by-reference class the agile FTM would have produced. + guid const free_threaded_marshaler{ 0x0000033A, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }; + REQUIRE(our_clsid != free_threaded_marshaler); +} + +// The in-proc reference advertises IAgileObject, so handing it between two single-threaded +// apartments in the same process must resolve to the *same* object pointer - no proxy. The Global +// Interface Table returns an agile object's original pointer directly, but hands back a proxy (a +// different identity) for a non-agile object, so pointer equality here confirms the agile fast path. +TEST_CASE("reference_boxing agile in-proc identity across apartments") +{ + auto identity_of = [](::IUnknown* raw) -> void* + { + com_ptr<::IUnknown> identity; + check_hresult(raw->QueryInterface(IID_PPV_ARGS(identity.put()))); + return identity.get(); + }; + + com_ptr git; + check_hresult(CoCreateInstance(CLSID_StdGlobalInterfaceTable, nullptr, + CLSCTX_INPROC_SERVER, IID_PPV_ARGS(git.put()))); + + Windows::Foundation::IInspectable boxed{ nullptr }; + DWORD cookie{}; + void* original_identity{}; + void* marshaled_identity{}; + HRESULT sta1_hr = S_OK; + HRESULT sta2_hr = S_OK; + + handle registered{ check_pointer(CreateEventW(nullptr, true, false, nullptr)) }; + handle fetched{ check_pointer(CreateEventW(nullptr, true, false, nullptr)) }; + + std::thread sta1([&] + { + sta1_hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if (SUCCEEDED(sta1_hr)) + { + boxed = box_value(42); + auto unknown = reinterpret_cast<::IUnknown*>(get_abi(boxed)); + original_identity = identity_of(unknown); + sta1_hr = git->RegisterInterfaceInGlobal(unknown, IID_IUnknown, &cookie); + } + SetEvent(registered.get()); + + WaitForSingleObject(fetched.get(), INFINITE); + if (SUCCEEDED(sta1_hr)) + { + CoUninitialize(); + } + }); + + std::thread sta2([&] + { + WaitForSingleObject(registered.get(), INFINITE); + if (SUCCEEDED(sta1_hr)) + { + sta2_hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + if (SUCCEEDED(sta2_hr)) + { + ::IUnknown* raw{}; + sta2_hr = git->GetInterfaceFromGlobal(cookie, IID_IUnknown, reinterpret_cast(&raw)); + if (SUCCEEDED(sta2_hr)) + { + marshaled_identity = identity_of(raw); + raw->Release(); + } + git->RevokeInterfaceFromGlobal(cookie); + CoUninitialize(); + } + } + SetEvent(fetched.get()); + }); + + sta1.join(); + sta2.join(); + + REQUIRE(SUCCEEDED(sta1_hr)); + REQUIRE(SUCCEEDED(sta2_hr)); + REQUIRE(original_identity != nullptr); + REQUIRE(original_identity == marshaled_identity); +} diff --git a/test/test/return_params_abi.cpp b/test/test/return_params_abi.cpp index 1d4af9a9f..5e7c11cd3 100644 --- a/test/test/return_params_abi.cpp +++ b/test/test/return_params_abi.cpp @@ -12,12 +12,19 @@ using namespace winrt; namespace { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif hstring to_hstring(::IInspectable* raw) { winrt::IInspectable object; copy_from_abi(object, raw); return object.as().ToString(); } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif } TEST_CASE("return_params_abi") diff --git a/test/test/struct_delegate.cpp b/test/test/struct_delegate.cpp index 26fcd9e64..785a0fb0a 100644 --- a/test/test/struct_delegate.cpp +++ b/test/test/struct_delegate.cpp @@ -1,5 +1,5 @@ #include "pch.h" -#include "winrt/test_component.delegates.h" +#include "winrt/test_component.Delegates.h" using namespace winrt; using namespace test_component; diff --git a/test/test/suppress_error_info.cpp b/test/test/suppress_error_info.cpp new file mode 100644 index 000000000..f2d25cac1 --- /dev/null +++ b/test/test/suppress_error_info.cpp @@ -0,0 +1,17 @@ +#include "pch.h" +#include + +TEST_CASE("suppress_error_info") +{ + winrt::check_hresult(RoSetErrorReportingFlags(RO_ERROR_REPORTING_SUPPRESSSETERRORINFO)); + + // Since the error information is suppressed, the best we can hope for is that C++/WinRT + // will provide a generic message for the HRESULT. + REQUIRE(winrt::hresult_error(E_FAIL, L"message").message() == L"Unspecified error"); + + winrt::check_hresult(RoSetErrorReportingFlags(RO_ERROR_REPORTING_USESETERRORINFO)); + + // The default behavior has been restored, so C++/WinRT can faithfully provide error + // information as usual. + REQUIRE(winrt::hresult_error(E_FAIL, L"message").message() == L"message"); +} diff --git a/test/test/tearoff.cpp b/test/test/tearoff.cpp index 9ed622870..ac43140dd 100644 --- a/test/test/tearoff.cpp +++ b/test/test/tearoff.cpp @@ -181,7 +181,7 @@ namespace Closed = true; } - winrt::hstring GetRuntimeClassName() + winrt::hstring GetRuntimeClassName() const { return L"RuntimeClassName"; } diff --git a/test/test/test.vcxproj b/test/test/test.vcxproj index 4c7c58517..f95584d99 100644 --- a/test/test/test.vcxproj +++ b/test/test/test.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,17 +31,12 @@ {D2961EA1-A8CA-4A62-B760-948403DC8494} unittests test - 10.0 - + Application true - - Application - true - Application true @@ -59,11 +46,6 @@ false true - - Application - false - true - Application false @@ -86,18 +68,12 @@ - - - - - - @@ -108,20 +84,6 @@ - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - MaxSpeed @@ -130,6 +92,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -137,7 +101,7 @@ true - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi + $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi @@ -150,30 +114,14 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - Disabled - $(OutputPath);Generated Files;..;..\..\cppwinrt - _MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - Console - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi + $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi @@ -186,12 +134,14 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi + $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi @@ -204,12 +154,14 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi + $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi @@ -224,6 +176,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -231,29 +185,7 @@ true - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..;..\..\cppwinrt - _MBCS;%(PreprocessorDefinitions) - MultiThreaded - - - Console - true - true - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi + $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi @@ -268,6 +200,8 @@ $(OutputPath);Generated Files;..;..\..\cppwinrt _MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -275,7 +209,7 @@ true - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi + $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi @@ -295,19 +229,17 @@ - + NotUsing NotUsing NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing @@ -316,8 +248,6 @@ NotUsing NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing @@ -326,8 +256,6 @@ NotUsing NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing @@ -365,8 +293,6 @@ NotUsing NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing @@ -377,20 +303,17 @@ NotUsing NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing + NotUsing NotUsing NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing @@ -401,14 +324,14 @@ NotUsing + + NotUsing NotUsing NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing @@ -416,7 +339,6 @@ - @@ -428,11 +350,13 @@ Create + + diff --git a/test/test/thread_pool.cpp b/test/test/thread_pool.cpp index ac75dac18..c55cffe1d 100644 --- a/test/test/thread_pool.cpp +++ b/test/test/thread_pool.cpp @@ -53,7 +53,7 @@ TEST_CASE("thread_pool") uint32_t const stable_counter = test(test_iterations, 1, 1); uint32_t const unstable_counter = test(test_iterations, 10, 10); - // This is determinstic since the queue is single-threaded. + // This is deterministic since the queue is single-threaded. REQUIRE(stable_counter == test_iterations); // This is unlikely to fail since the pool is multi-threaded. diff --git a/test/test/variadic_delegate.cpp b/test/test/variadic_delegate.cpp index a4d0c4a80..7291ddbeb 100644 --- a/test/test/variadic_delegate.cpp +++ b/test/test/variadic_delegate.cpp @@ -40,6 +40,20 @@ namespace return L"Object"; } }; + + struct ObjectStd : std::enable_shared_from_this + { + int& m_count; + + ObjectStd(int& count) : m_count(count) + { + } + + void Callback() + { + ++m_count; + } + }; } TEST_CASE("variadic_delegate") @@ -100,6 +114,44 @@ TEST_CASE("variadic_delegate") REQUIRE(count == 2); // Unchanged } + // shared_from_this + { + int count{}; + auto object = std::make_shared(count); + + delegate<> up{ object->shared_from_this(), &ObjectStd::Callback }; + + REQUIRE(count == 0); + up(); + REQUIRE(count == 1); + up(); + REQUIRE(count == 2); + + object = nullptr; + + up(); + REQUIRE(count == 3); + } + + // weak_from_this + { + int count{}; + auto object = std::make_shared(count); + + delegate<> up{ object->weak_from_this(), &ObjectStd::Callback }; + + REQUIRE(count == 0); + up(); + REQUIRE(count == 1); + up(); + REQUIRE(count == 2); + + object = nullptr; + + up(); + REQUIRE(count == 2); // Unchanged + } + // Mixed arguments { int count{}; @@ -150,7 +202,7 @@ TEST_CASE("variadic_delegate") // Exception { - delegate<> d = [] { throw std::exception("what"); }; + delegate<> d = [] { throw std::runtime_error("what"); }; REQUIRE_THROWS_AS(d(), std::exception); } diff --git a/test/test/when.cpp b/test/test/when.cpp index 86edc6c77..0b1151abc 100644 --- a/test/test/when.cpp +++ b/test/test/when.cpp @@ -5,7 +5,7 @@ using namespace concurrency; using namespace winrt; using namespace Windows::Foundation; -struct CommaStruct : std::experimental::suspend_never +struct CommaStruct : std::suspend_never { // If the comma operator is invoked, we will get a build failure. CommaStruct operator,(CommaStruct) = delete; diff --git a/test/test_component/Class.cpp b/test/test_component/Class.cpp index f328a7ddf..3f68d96c3 100644 --- a/test/test_component/Class.cpp +++ b/test/test_component/Class.cpp @@ -515,4 +515,18 @@ namespace winrt::test_component::implementation } return pass; } +} + +namespace +{ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + void ValidateStaticEventAutoRevoke() { + auto x = winrt::test_component::Simple::StaticEvent(winrt::auto_revoke, [](auto&&, auto&&) {}); + } +#ifdef __clang__ +#pragma clang diagnostic pop +#endif } \ No newline at end of file diff --git a/test/test_component/OverloadClass.cpp b/test/test_component/OverloadClass.cpp new file mode 100644 index 000000000..0f78c5a1c --- /dev/null +++ b/test/test_component/OverloadClass.cpp @@ -0,0 +1,23 @@ +#include "pch.h" +#include "OverloadClass.h" +#include "OverloadClass.g.cpp" + +namespace winrt::test_component::implementation +{ + void OverloadClass::Overload() + { + throw hresult_not_implemented(); + } + void OverloadClass::Overload(int /*a*/) + { + throw hresult_not_implemented(); + } + void OverloadClass::Overload(int /*a*/, int /*b*/) + { + throw hresult_not_implemented(); + } + void OverloadClass::Overload(int /*a*/, int /*b*/, int /*c*/) + { + throw hresult_not_implemented(); + } +} diff --git a/test/test_component/OverloadClass.h b/test/test_component/OverloadClass.h new file mode 100644 index 000000000..1b155e801 --- /dev/null +++ b/test/test_component/OverloadClass.h @@ -0,0 +1,21 @@ +#pragma once +#include "OverloadClass.g.h" + +namespace winrt::test_component::implementation +{ + struct OverloadClass : OverloadClassT + { + OverloadClass() = default; + + void Overload(); + void Overload(int a); + void Overload(int a, int b); + void Overload(int a, int b, int c); + }; +} +namespace winrt::test_component::factory_implementation +{ + struct OverloadClass : OverloadClassT + { + }; +} diff --git a/test/test_component/Simple.h b/test/test_component/Simple.h index 0d97f5e1b..854c1235d 100644 --- a/test/test_component/Simple.h +++ b/test/test_component/Simple.h @@ -16,6 +16,16 @@ namespace winrt::test_component::implementation // All we care about static events (for now) is that they build. static event_token StaticEvent(Windows::Foundation::EventHandler const&) { return {}; } static void StaticEvent(event_token) { } + + Windows::Foundation::Numerics::float2 ReturnVector2() + { + return { 123.0, 456.0 }; + } + + Windows::Foundation::Numerics::Rational ReturnRational() + { + return { 123, 456 }; + } }; } namespace winrt::test_component::factory_implementation diff --git a/test/test_component/test_component.idl b/test/test_component/test_component.idl index 252e6d2f8..536a703f5 100644 --- a/test/test_component/test_component.idl +++ b/test/test_component/test_component.idl @@ -56,6 +56,9 @@ namespace test_component Windows.Foundation.IAsyncAction Action(Windows.Foundation.DateTime value); Object Object(Windows.Foundation.DateTime value); static event Windows.Foundation.EventHandler StaticEvent; + + Windows.Foundation.Numerics.Vector2 ReturnVector2(); + Windows.Foundation.Numerics.Rational ReturnRational(); } runtimeclass DeferrableEventArgs @@ -160,6 +163,13 @@ namespace test_component static void StaticMethodWithAsyncReturn(); } + // This class declares that it implements another interface but under the covers it actually does + // not. This allows us to test the behavior when QI's that should not fail, do fail. + runtimeclass LiesAboutInheritance : Windows.Foundation.IStringable + { + void StubMethod(); + } + namespace Structs { struct All @@ -324,4 +334,51 @@ namespace test_component delegate void Delegate(); } + + [exclusiveto(test_component.OverloadClass)] + [version(1), uuid(EF902013-00F3-4549-9032-49E86D536C07)] + interface IOverloadClass : IInspectable + { + HRESULT Overload(); + } + + [exclusiveto(test_component.OverloadClass)] + [version(1), uuid(DFDFFB61-EA72-4977-B1A7-3F0D2C32BB58)] + interface IOverloadClassFactory : IInspectable + { + HRESULT CreateInstance([in] IInspectable* baseInterface, [out] IInspectable** innerInterface, [out][retval] test_component.OverloadClass** value); + } + + [exclusiveto(test_component.OverloadClass)] + [version(1), uuid(32510F72-9229-4C69-95BD-DE7B8189C85C)] + interface IOverloadClassOverrides : IInspectable + { + [overload("Overload")] HRESULT OverloadWithOne(int a); + } + + [exclusiveto(test_component.OverloadClass)] + [version(1), uuid(50205BCE-FAD3-4C66-801F-17AAD007B26C)] + interface IOverloadClassOverrides2 : IInspectable + { + [overload("Overload")] HRESULT OverloadWithTwo(int a, int b); + } + + [exclusiveto(test_component.OverloadClass)] + [version(1), uuid(6EDD1A3F-2616-45B7-9731-F84DA9CCECA1)] + interface IOverloadClassProtected : IInspectable + { + [overload("Overload")] HRESULT OverloadWithThree(int a, int b, int c); + } + + [composable(test_component.IOverloadClassFactory, public, 1)] + [marshaling_behavior(agile)] + [threading(both)] + [version(1)] + runtimeclass OverloadClass + { + [default] interface test_component.IOverloadClass; + [protected] interface test_component.IOverloadClassProtected; + [overridable] interface test_component.IOverloadClassOverrides; + [overridable] interface test_component.IOverloadClassOverrides2; + } } diff --git a/test/test_component/test_component.vcxproj b/test/test_component/test_component.vcxproj index e7b257621..3ffdb8f97 100644 --- a/test/test_component/test_component.vcxproj +++ b/test/test_component/test_component.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,19 +31,13 @@ {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} Component test_component - 10.0 - + DynamicLibrary true x64 - - DynamicLibrary - true - x64 - DynamicLibrary true @@ -63,12 +49,6 @@ true x64 - - DynamicLibrary - false - true - x64 - DynamicLibrary false @@ -94,18 +74,12 @@ - - - - - - @@ -118,39 +92,21 @@ Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ @@ -158,6 +114,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreadedDebug + Level4 + true exports.def @@ -187,80 +145,6 @@ C:\Windows\System32\WinMetadata true - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component.winmd - - - - - Disabled - .;$(OutputPath);Generated Files - /Zc:threadSafeInit- /we4640 %(AdditionalOptions) - MultiThreadedDebug - - - exports.def - - - true - - - $(OutputPath)test_component.winmd - - - - - - - - - - - $(OutputPath)test_component.h - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component.winmd - @@ -268,6 +152,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreadedDebug + Level4 + true exports.def @@ -310,19 +196,6 @@ C:\Windows\System32\WinMetadata true - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component.winmd - @@ -330,6 +203,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreadedDebug + Level4 + true exports.def @@ -359,18 +234,6 @@ C:\Windows\System32\WinMetadata true - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component.winmd - @@ -380,6 +243,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreaded + Level4 + true true @@ -411,84 +276,6 @@ C:\Windows\System32\WinMetadata true - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component.winmd - - - - - MaxSpeed - true - true - .;$(OutputPath);Generated Files - /Zc:threadSafeInit- /we4640 %(AdditionalOptions) - MultiThreaded - - - true - true - exports.def - - - true - - - $(OutputPath)test_component.winmd - - - - - - - - - - - $(OutputPath)test_component.h - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component.winmd - @@ -498,6 +285,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreaded + Level4 + true true @@ -542,19 +331,6 @@ C:\Windows\System32\WinMetadata true - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component.winmd - @@ -564,6 +340,8 @@ .;$(OutputPath);Generated Files /Zc:threadSafeInit- /we4640 %(AdditionalOptions) MultiThreaded + Level4 + true true @@ -595,17 +373,16 @@ C:\Windows\System32\WinMetadata true + + - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component.winmd + + $(CppWinRTDir)cppwinrt -in local -out $(OutputPath) -verbose + $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component.winmd -comp "$(ProjectDir)Generated Files" -out "$(ProjectDir)Generated Files" -include test_component -ref sdk -verbose -prefix -opt -lib test -fastabi -overwrite -name test_component + + Projecting Windows and component metadata into $(OutputPath) + $(OutputPath)\winrt\base.h;Generated Files\module.g.cpp + $(CppWinRTDir)cppwinrt.exe;$(OutputPath)test_component.winmd @@ -613,6 +390,8 @@ + + Create @@ -626,6 +405,7 @@ + diff --git a/test/test_component/test_overload.cpp b/test/test_component/test_overload.cpp new file mode 100644 index 000000000..9c21a06cf --- /dev/null +++ b/test/test_component/test_overload.cpp @@ -0,0 +1,19 @@ +#include "pch.h" +#include "winrt/test_component.h" + +// Simple compile-only test to validate overloads coming from overridable interfaces compile. + +using namespace winrt; +using namespace test_component; + +struct DerivedClass : OverloadClassT +{ + void Foo() + { + // make sure we can actually call the overloads (no ambiguous call errors) + Overload(); + Overload(1); + Overload(1, 2); + Overload(1, 2, 3); + } +}; \ No newline at end of file diff --git a/test/test_component_base/HierarchyA.cpp b/test/test_component_base/HierarchyA.cpp index ab5ff5ea9..45b3e6098 100644 --- a/test/test_component_base/HierarchyA.cpp +++ b/test/test_component_base/HierarchyA.cpp @@ -3,7 +3,11 @@ namespace winrt::test_component_base::implementation { - HierarchyA::HierarchyA(hstring const& name) + HierarchyA::HierarchyA(hstring const& /*name*/) + { + throw hresult_not_implemented(); + } + HierarchyA::HierarchyA(int32_t /*dummy*/, hstring const& /*name*/) { throw hresult_not_implemented(); } @@ -15,4 +19,10 @@ namespace winrt::test_component_base::implementation //test_component_base::IHierarchyA ia = *this; //assert(a); } + int HierarchyA::HierarchyA_Protected() + { + return 42; + } + + static_assert(!std::is_constructible_v); } diff --git a/test/test_component_base/HierarchyA.h b/test/test_component_base/HierarchyA.h index bc574e3cc..ebca21e3a 100644 --- a/test/test_component_base/HierarchyA.h +++ b/test/test_component_base/HierarchyA.h @@ -8,7 +8,9 @@ namespace winrt::test_component_base::implementation HierarchyA() = default; HierarchyA(hstring const& name); + HierarchyA(int32_t dummy, hstring const& name); void HierarchyA_Method(); + int HierarchyA_Protected(); }; } namespace winrt::test_component_base::factory_implementation diff --git a/test/test_component_base/HierarchyB.cpp b/test/test_component_base/HierarchyB.cpp index 062015a5a..b56988f73 100644 --- a/test/test_component_base/HierarchyB.cpp +++ b/test/test_component_base/HierarchyB.cpp @@ -1,9 +1,15 @@ #include "pch.h" #include "HierarchyB.h" +#pragma warning(disable: 4702) + namespace winrt::test_component_base::implementation { - HierarchyB::HierarchyB(hstring const& name) + HierarchyB::HierarchyB(hstring const& /*name*/) + { + throw hresult_not_implemented(); + } + HierarchyB::HierarchyB(int32_t dummy, hstring const& name) : HierarchyB_base(dummy, name) { throw hresult_not_implemented(); } @@ -11,4 +17,8 @@ namespace winrt::test_component_base::implementation { throw hresult_not_implemented(); } + void HierarchyB::HierarchyB_TestInnerProtected() + { + assert(HierarchyA_Protected() == 42); + } } diff --git a/test/test_component_base/HierarchyB.h b/test/test_component_base/HierarchyB.h index 3cce7c2ea..cff644ef8 100644 --- a/test/test_component_base/HierarchyB.h +++ b/test/test_component_base/HierarchyB.h @@ -9,7 +9,9 @@ namespace winrt::test_component_base::implementation HierarchyB() = default; HierarchyB(hstring const& name); + HierarchyB(int32_t dummy, hstring const& name); void HierarchyB_Method(); + void HierarchyB_TestInnerProtected(); }; } namespace winrt::test_component_base::factory_implementation diff --git a/test/test_component_base/pch.h b/test/test_component_base/pch.h index e5c39a869..a6f43eada 100644 --- a/test/test_component_base/pch.h +++ b/test/test_component_base/pch.h @@ -4,6 +4,6 @@ #include "winrt/base.h" // get_module_lock will always return true if WINRT_NO_MODULE_LOCK is defined. -// This ensures that if the DLL unecessarily exports DllCanUnloadNow that it +// This ensures that if the DLL unnecessarily exports DllCanUnloadNow that it // will in turn return S_FALSE. static_assert(winrt::get_module_lock()); diff --git a/test/test_component_base/test_component_base.idl b/test/test_component_base/test_component_base.idl index 5caff8906..9169b28b7 100644 --- a/test/test_component_base/test_component_base.idl +++ b/test/test_component_base/test_component_base.idl @@ -6,15 +6,19 @@ namespace test_component_base { HierarchyA(); HierarchyA(String name); + protected HierarchyA(Int32 dummy, String name); void HierarchyA_Method(); + protected Int32 HierarchyA_Protected(); } unsealed runtimeclass HierarchyB : HierarchyA { HierarchyB(); HierarchyB(String name); + protected HierarchyB(Int32 dummy, String name); void HierarchyB_Method(); + void HierarchyB_TestInnerProtected(); } } diff --git a/test/test_component_base/test_component_base.vcxproj b/test/test_component_base/test_component_base.vcxproj index 43f67d347..90577a2c5 100644 --- a/test/test_component_base/test_component_base.vcxproj +++ b/test/test_component_base/test_component_base.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,19 +31,13 @@ {13333A6F-6A4A-48CD-865C-0F65135EB018} Component test_component_base - 10.0 - + DynamicLibrary true x64 - - DynamicLibrary - true - x64 - DynamicLibrary true @@ -63,12 +49,6 @@ true x64 - - DynamicLibrary - false - true - x64 - DynamicLibrary false @@ -94,18 +74,12 @@ - - - - - - @@ -118,39 +92,21 @@ Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ @@ -158,6 +114,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreadedDebug + Level4 + true exports.def @@ -200,74 +158,14 @@ $(OutputPath)test_component_base.winmd - - - Disabled - $(ProjectDir);$(OutputPath);Generated Files - 4100 - MultiThreadedDebug - - - exports.def - - - true - - - $(OutputPath)test_component_base.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_base.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk -verbose -name test_component_base - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_base.winmd - - Disabled $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreadedDebug + Level4 + true exports.def @@ -330,6 +228,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreadedDebug + Level4 + true exports.def @@ -380,6 +280,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreaded + Level4 + true true @@ -424,72 +326,6 @@ $(OutputPath)test_component_base.winmd - - - MaxSpeed - true - true - $(ProjectDir);$(OutputPath);Generated Files - 4100 - MultiThreaded - - - true - true - exports.def - - - true - - - $(OutputPath)test_component_base.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_base.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk -verbose -name test_component_base - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_base.winmd - - MaxSpeed @@ -498,6 +334,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreaded + Level4 + true true @@ -564,6 +402,8 @@ $(ProjectDir);$(OutputPath);Generated Files 4100 MultiThreaded + Level4 + true true diff --git a/test/test_component_derived/Nested.HierarchyC.cpp b/test/test_component_derived/Nested.HierarchyC.cpp index a9c4fa2e2..f711adbd4 100644 --- a/test/test_component_derived/Nested.HierarchyC.cpp +++ b/test/test_component_derived/Nested.HierarchyC.cpp @@ -3,7 +3,7 @@ namespace winrt::test_component_derived::Nested::implementation { - HierarchyC::HierarchyC(hstring const& name) + HierarchyC::HierarchyC(hstring const& name) : HierarchyC_base(10, name) { throw hresult_not_implemented(); } @@ -11,4 +11,7 @@ namespace winrt::test_component_derived::Nested::implementation { throw hresult_not_implemented(); } + + static_assert(!std::is_convertible_v); + static_assert(!std::is_constructible_v); } diff --git a/test/test_component_derived/Nested.HierarchyD.cpp b/test/test_component_derived/Nested.HierarchyD.cpp index 286af6bbf..8011e73e6 100644 --- a/test/test_component_derived/Nested.HierarchyD.cpp +++ b/test/test_component_derived/Nested.HierarchyD.cpp @@ -3,7 +3,7 @@ namespace winrt::test_component_derived::Nested::implementation { - HierarchyD::HierarchyD(hstring const& name) + HierarchyD::HierarchyD(hstring const& /*name*/) { throw hresult_not_implemented(); } @@ -32,5 +32,8 @@ namespace winrt::test_component_derived::Nested::implementation test_component_base::IHierarchyA ia = *this; assert(ia); + + assert(HierarchyA_Protected() == 42); + HierarchyB_TestInnerProtected(); } } diff --git a/test/test_component_derived/test_component_derived.vcxproj b/test/test_component_derived/test_component_derived.vcxproj index fcb82ee3b..837d8821e 100644 --- a/test/test_component_derived/test_component_derived.vcxproj +++ b/test/test_component_derived/test_component_derived.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,19 +31,13 @@ {0080F6D1-AEC3-4F89-ADE1-3D22A7EBF99E} Component test_component_derived - 10.0 - + DynamicLibrary true x64 - - DynamicLibrary - true - x64 - DynamicLibrary true @@ -63,12 +49,6 @@ true x64 - - DynamicLibrary - false - true - x64 - DynamicLibrary false @@ -94,18 +74,12 @@ - - - - - - @@ -118,44 +92,28 @@ Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Disabled $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -201,73 +159,12 @@ $(OutputPath)test_component_derived.winmd - - - Disabled - $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files - 4100 - MultiThreadedDebug - - - exports.def - - - true - - - $(OutputPath)test_component_derived.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - ..\test_component_base - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_derived.winmd -ref $(OutputPath)test_component_base.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk -verbose -name test_component_derived - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_derived.winmd - - Disabled $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -331,6 +228,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -382,6 +281,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreaded @@ -429,79 +330,14 @@ $(OutputPath)test_component_derived.winmd - - - MaxSpeed - true - true - $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files - 4100 - MultiThreaded - - - true - true - exports.def - - - true - - - $(OutputPath)test_component_derived.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - ..\test_component_base - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_derived.winmd -ref $(OutputPath)test_component_base.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk -verbose -name test_component_derived - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_derived.winmd - - MaxSpeed true true $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreaded @@ -569,6 +405,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files;..\test_component_base\Generated Files + Level4 + true 4100 MultiThreaded diff --git a/test/test_component_fast/Nomadic.cpp b/test/test_component_fast/Nomadic.cpp new file mode 100644 index 000000000..e2d5c8af5 --- /dev/null +++ b/test/test_component_fast/Nomadic.cpp @@ -0,0 +1,35 @@ +#include "pch.h" +#include "Nomadic.h" +#include "Nomadic.g.cpp" + +namespace winrt::test_component_fast::implementation +{ + hstring Nomadic::FirstMethod() + { + return L"FirstMethod"; + } + hstring Nomadic::SecondMethod() + { + return L"SecondMethod"; + } + hstring Nomadic::ThirdMethod() + { + return L"ThirdMethod"; + } + hstring Nomadic::FourthMethod() + { + return L"FourthMethod"; + } + hstring Nomadic::FifthMethod() + { + return L"FifthMethod"; + } + hstring Nomadic::SixthMethod() + { + return L"SixthMethod"; + } + hstring Nomadic::SeventhMethod() + { + return L"SeventhMethod"; + } +} diff --git a/test/test_component_fast/Nomadic.h b/test/test_component_fast/Nomadic.h new file mode 100644 index 000000000..65448b967 --- /dev/null +++ b/test/test_component_fast/Nomadic.h @@ -0,0 +1,24 @@ +#pragma once +#include "Nomadic.g.h" + +namespace winrt::test_component_fast::implementation +{ + struct Nomadic : NomadicT + { + Nomadic() = default; + + hstring FirstMethod(); + hstring SecondMethod(); + hstring ThirdMethod(); + hstring FourthMethod(); + hstring FifthMethod(); + hstring SixthMethod(); + hstring SeventhMethod(); + }; +} +namespace winrt::test_component_fast::factory_implementation +{ + struct Nomadic : NomadicT + { + }; +} diff --git a/test/test_component_fast/test_component_fast.idl b/test/test_component_fast/test_component_fast.idl index ad7f89ce4..915eec49d 100644 --- a/test/test_component_fast/test_component_fast.idl +++ b/test/test_component_fast/test_component_fast.idl @@ -42,6 +42,80 @@ namespace test_component_fast } } + [contractversion(10)] + apicontract FirstContract{}; + + [contractversion(10)] + apicontract SecondContract{}; + + [contractversion(10)] + apicontract ThirdContract{}; + + [contractversion(10)] + apicontract FourthContract{}; + + [fastabi2(ThirdContract, 3)] + [from_contract(FirstContract, range(1, 10), SecondContract)] + [from_contract(SecondContract, range(1, 10), ThirdContract)] + [from_contract(ThirdContract, range(1, 10))] + [contract(FourthContract, 1)] + runtimeclass Nomadic + { + Nomadic(); + + /* NOTE: There seems to be a bug in midlrt where 'INomadicSeventh' and 'INomadicEighth' are both versioned to + 1.0 (when the class was added to the contract) in metadata. The interface impl list has the correct + contract versions, however this trips us up since we only look at the version of the interface + [interface_name("INomadicEighth")] + [contract(FourthContract, 2.1)] + { + String EighthMethod(); + } + */ + + [interface_name("INomadicSeventh")] + [contract(FourthContract, 1.2)] + { + String SeventhMethod(); + } + + [interface_name("INomadicSixth")] + [contract(ThirdContract, 4.3)] + { + String SixthMethod(); + } + + [interface_name("INomadicFifth")] + [contract(ThirdContract, 3.4)] + { + String FifthMethod(); + } + + [interface_name("INomadicFourth")] + [contract(SecondContract, 6.5)] + { + String FourthMethod(); + } + + [interface_name("INomadicThird")] + [contract(SecondContract, 5.6)] + { + String ThirdMethod(); + } + + [interface_name("INomadicSecond")] + [contract(FirstContract, 8.7)] + { + String SecondMethod(); + } + + [interface_name("INomadicFirst")] + [contract(FirstContract, 7.8)] + { + String FirstMethod(); + } + } + namespace Composition { [contractversion(4)] diff --git a/test/test_component_fast/test_component_fast.vcxproj b/test/test_component_fast/test_component_fast.vcxproj index 55d1ed371..ed5a36222 100644 --- a/test/test_component_fast/test_component_fast.vcxproj +++ b/test/test_component_fast/test_component_fast.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -40,19 +32,13 @@ {0E0ACA62-A92F-44CF-BD41-AEB541946DF8} Component test_component_fast - 10.0 - + DynamicLibrary true x64 - - DynamicLibrary - true - x64 - DynamicLibrary true @@ -64,12 +50,6 @@ true x64 - - DynamicLibrary - false - true - x64 - DynamicLibrary false @@ -95,18 +75,12 @@ - - - - - - @@ -119,45 +93,29 @@ Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Disabled $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreadedDebug @@ -202,74 +160,13 @@ $(OutputPath)test_component_fast.winmd - - - Disabled - $(ProjectDir);$(OutputPath);Generated Files - /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) - 4100 - MultiThreadedDebug - - - exports.def - - - true - - - $(OutputPath)test_component_fast.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_fast.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi -prefix -opt -name test_component_fast - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_fast.winmd - - Disabled $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreadedDebug @@ -333,6 +230,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreadedDebug @@ -384,6 +283,8 @@ true $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreaded @@ -430,73 +331,6 @@ $(OutputPath)test_component_fast.winmd - - - MaxSpeed - true - true - $(ProjectDir);$(OutputPath);Generated Files - /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) - 4100 - MultiThreaded - - - true - true - exports.def - - - true - - - $(OutputPath)test_component_fast.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_fast.winmd -comp $(ProjectDir) -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi -prefix -opt -name test_component_fast - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_fast.winmd - - MaxSpeed @@ -504,6 +338,8 @@ true $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreaded @@ -571,6 +407,8 @@ true $(ProjectDir);$(OutputPath);Generated Files /DWINRT_FAST_ABI_SIZE=50 %(AdditionalOptions) + Level4 + true 4100 MultiThreaded @@ -622,6 +460,7 @@ + @@ -633,6 +472,7 @@ + diff --git a/test/test_component_folders/test_component_folders.vcxproj b/test/test_component_folders/test_component_folders.vcxproj index d470ed048..14c12f8f9 100644 --- a/test/test_component_folders/test_component_folders.vcxproj +++ b/test/test_component_folders/test_component_folders.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,19 +31,13 @@ {85695954-3800-4558-9857-966E69E9F9EC} Component test_component_folders - 10.0 - + DynamicLibrary true x64 - - DynamicLibrary - true - x64 - DynamicLibrary true @@ -63,12 +49,6 @@ true x64 - - DynamicLibrary - false - true - x64 - DynamicLibrary false @@ -94,18 +74,12 @@ - - - - - - @@ -118,44 +92,28 @@ Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -200,72 +158,12 @@ $(OutputPath)test_component_folders.winmd - - - Disabled - $(ProjectDir);$(OutputPath);Generated Files - 4100 - MultiThreadedDebug - - - exports.def - - - true - - - $(OutputPath)test_component_folders.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_folders.winmd -comp -out "$(ProjectDir)Generated Files" -ref sdk -verbose -overwrite -name test_component_folders - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_folders.winmd - - Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -328,6 +226,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreadedDebug @@ -378,6 +278,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreaded @@ -424,78 +326,14 @@ $(OutputPath)test_component_folders.winmd - - - MaxSpeed - true - true - $(ProjectDir);$(OutputPath);Generated Files - 4100 - MultiThreaded - - - true - true - exports.def - - - true - - - $(OutputPath)test_component_folders.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_folders.winmd -comp -out "$(ProjectDir)Generated Files" -ref sdk -verbose -overwrite -name test_component_folders - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_folders.winmd - - MaxSpeed true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreaded @@ -562,6 +400,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 MultiThreaded diff --git a/test/test_component_no_pch/test_component_no_pch.vcxproj b/test/test_component_no_pch/test_component_no_pch.vcxproj index e6ca64dc1..117be2d00 100644 --- a/test/test_component_no_pch/test_component_no_pch.vcxproj +++ b/test/test_component_no_pch/test_component_no_pch.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,19 +31,13 @@ {F1C915B3-2C64-4992-AFB7-7F035B1A7607} Component test_component_no_pch - 10.0 - + DynamicLibrary true x64 - - DynamicLibrary - true - x64 - DynamicLibrary true @@ -63,12 +49,6 @@ true x64 - - DynamicLibrary - false - true - x64 - DynamicLibrary false @@ -94,18 +74,12 @@ - - - - - - @@ -118,44 +92,28 @@ Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ - - - Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x86);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH); Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Midl - $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH); - $(OutDir)temp\$(ProjectName)\ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreadedDebug @@ -201,73 +159,12 @@ $(OutputPath)test_component_no_pch.winmd - - - Disabled - $(ProjectDir);$(OutputPath);Generated Files - 4100 - NotUsing - MultiThreadedDebug - - - exports.def - - - true - - - $(OutputPath)test_component_no_pch.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_no_pch.winmd -comp -out "$(ProjectDir)Generated Files" -ref sdk -verbose -overwrite -pch . -name test_component_no_pch - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_no_pch.winmd - - Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreadedDebug @@ -331,6 +228,8 @@ Disabled $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreadedDebug @@ -382,6 +281,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreaded @@ -429,79 +330,14 @@ $(OutputPath)test_component_no_pch.winmd - - - MaxSpeed - true - true - $(ProjectDir);$(OutputPath);Generated Files - 4100 - NotUsing - MultiThreaded - - - true - true - exports.def - - - true - - - $(OutputPath)test_component_no_pch.winmd - - - - - - - - - - - nul - - - - - - - - - - - - - - - - - - - /nomidl %(AdditionalOptions) - C:\Windows\System32\WinMetadata - true - - - $(CppWinRTDir)cppwinrt -input $(OutputPath)test_component_no_pch.winmd -comp -out "$(ProjectDir)Generated Files" -ref sdk -verbose -overwrite -pch . -name test_component_no_pch - - - - - - - Generated Files\module.g.cpp - - - $(OutputPath)test_component_no_pch.winmd - - MaxSpeed true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreaded @@ -569,6 +405,8 @@ true true $(ProjectDir);$(OutputPath);Generated Files + Level4 + true 4100 NotUsing MultiThreaded diff --git a/test/test_cpp20/CMakeLists.txt b/test/test_cpp20/CMakeLists.txt new file mode 100644 index 000000000..cbf1b799d --- /dev/null +++ b/test/test_cpp20/CMakeLists.txt @@ -0,0 +1,46 @@ +set(CMAKE_CXX_STANDARD 20) +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # std::format, std::ranges::is_heap, std::views::reverse, std::ranges::max + # are experimental in libc++ as of Clang 15. + # FIXME: Should probably use compile test instead? + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library") +endif() + +if(ENABLE_TEST_SANITIZERS) + # As of LLVM 15, custom_error.cpp doesn't build with ASAN due to: + # error: cannot make section .ASAN$GL associative with sectionless symbol _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4nposE + set_source_files_properties(custom_error.cpp PROPERTIES COMPILE_OPTIONS "-fno-sanitize=address") + set_source_files_properties(custom_error.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS true) +endif() + +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp") + + +list(APPEND BROKEN_TESTS + # No broken tests. +) + +# Exclude broken tests +foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS) + list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp") +endforeach() + +add_executable(test_cpp20 main.cpp ${TEST_SRCS}) + +target_precompile_headers(test_cpp20 PRIVATE pch.h) +set_source_files_properties( + main.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true +) + +add_dependencies(test_cpp20 build-cppwinrt-projection) + +add_test( + NAME test_cpp20 + COMMAND "$" ${TEST_COLOR_ARG} +) diff --git a/test/test_cpp20/array_span.cpp b/test/test_cpp20/array_span.cpp new file mode 100644 index 000000000..8cebc4a1e --- /dev/null +++ b/test/test_cpp20/array_span.cpp @@ -0,0 +1,189 @@ +#include "pch.h" +#include "catch.hpp" +#include + +using namespace winrt; +using namespace Windows::Foundation; +using namespace Windows::Storage::Streams; +using namespace Windows::Data::Json; + +// +// This is a helper to create a data reader for use in testing arrays. +// +static IAsyncOperation CreateDataReader(std::initializer_list /*values*/) +{ + InMemoryRandomAccessStream stream; + DataWriter writer(stream); + writer.WriteByte(1); + writer.WriteByte(2); + writer.WriteByte(3); + co_await writer.StoreAsync(); + + stream.Seek(0); + DataReader reader(stream); + co_await reader.LoadAsync(3); + co_return reader; +} + +// +// This test illustrates an array_view (non-const) bound to a std::span on a std::array +// +TEST_CASE("array,DataReader,std::span") +{ + auto reader = CreateDataReader({ 1, 2, 3 }).get(); + + std::array a{}; + std::span sp(a); + reader.ReadBytes(sp); // FillArray pattern + + REQUIRE(a.size() == 3); + REQUIRE(a[0] == 1); + REQUIRE(a[1] == 2); + REQUIRE(a[2] == 3); +} + +// +// This test illustrates passing a std::array to a method that takes array_view +// +TEST_CASE("array,DataReader,std::span,direct") +{ + auto reader = CreateDataReader({ 1, 2, 3 }).get(); + + std::array a{}; + reader.ReadBytes(a); // FillArray pattern + + REQUIRE(a.size() == 3); + REQUIRE(a[0] == 1); + REQUIRE(a[1] == 2); + REQUIRE(a[2] == 3); +} + + +TEST_CASE("array_view,span") +{ + { + int v[] = { 1, 2, 3 }; + std::span s(v); + array_view a = s; + REQUIRE(a.data() == v); + REQUIRE(a.size() == 3); + } + + { + int v[] = { 1, 2, 3 }; + std::span s(v); + array_view a = s; + REQUIRE(a.data() == v); + REQUIRE(a.size() == 3); + } + + { + int const v[] = { 1, 2, 3 }; + std::span s(v); + array_view a = s; + REQUIRE(a.data() == v); + REQUIRE(a.size() == 3); + } +} + +// +// Tests com_array support for span construction. +// +TEST_CASE("com_array,span") +{ + { + int v[] = { 1, 2, 3 }; + std::span s(v); + com_array a(s); + REQUIRE(a.size() == 3); + REQUIRE(a[0] == 1); + REQUIRE(a[1] == 2); + REQUIRE(a[2] == 3); + } +} + +// +// Tests array_view support for conversion to span +// +TEST_CASE("array_view,span,as") +{ + { + int v[] = { 1, 2, 3 }; + array_view a = v; + std::span s(a); + REQUIRE(s.data() == v); + REQUIRE(s.size() == 3); + } + + { + int v[] = { 1, 2, 3 }; + array_view a = v; + std::span s(a); + REQUIRE(s.data() == v); + REQUIRE(s.size() == 3); + } + + { + int const v[] = { 1, 2, 3 }; + array_view a = v; + std::span s(a); + REQUIRE(s.data() == v); + REQUIRE(s.size() == 3); + } +} + +// +// Tests com_array support for conversion to span +// +TEST_CASE("com_array,span,as") +{ + { + int v[] = { 1, 2, 3 }; + com_array a(v); + std::span s(a); + REQUIRE(s.size() == 3); + REQUIRE(s[0] == 1); + REQUIRE(s[1] == 2); + REQUIRE(s[2] == 3); + } +} + +// Verify that class template argument deduction works for array_view. +TEST_CASE("array_view,span,ctad") +{ +#define REQUIRE_DEDUCED_AS(T, ...) \ + static_assert(std::is_same_v, decltype(array_view(__VA_ARGS__))>) + + uint8_t a[] = {1, 2, 3}; + std::span sp{ a }; + + REQUIRE_DEDUCED_AS(uint8_t, sp); + + std::span csp{ a }; + REQUIRE_DEDUCED_AS(uint8_t const, csp); + + std::span const cs{ a }; + REQUIRE_DEDUCED_AS(uint8_t const, cs); + +#undef REQUIRE_DEDUCED_AS +} + +// Verify that class template argument deduction works for com_array. +TEST_CASE("com_array,span,ctad") +{ +#define REQUIRE_DEDUCED_AS(T, ...) \ + static_assert(std::is_same_v, decltype(com_array(__VA_ARGS__))>) + + uint8_t a[] = { 1, 2, 3 }; + + std::span sp{ a }; + REQUIRE_DEDUCED_AS(uint8_t, sp); + + std::span csp{ a }; + REQUIRE_DEDUCED_AS(uint8_t, csp); + + std::span const cs{ a }; + REQUIRE_DEDUCED_AS(uint8_t, cs); + +#undef REQUIRE_DEDUCED_AS +} diff --git a/test/test_cpp20/await_completed.cpp b/test/test_cpp20/await_completed.cpp index 2448a3f88..3ae64e25e 100644 --- a/test/test_cpp20/await_completed.cpp +++ b/test/test_cpp20/await_completed.cpp @@ -38,8 +38,22 @@ namespace uintptr_t consumed = initial - approximate_stack_pointer(); REQUIRE(consumed == 0); } + + IAsyncAction TestApartmentContextNop() + { + // co_await the same apartment and confirm that stack does not grow. + winrt::apartment_context same_context; + uintptr_t initial = approximate_stack_pointer(); + co_await same_context; + uintptr_t consumed = initial - approximate_stack_pointer(); + REQUIRE(consumed == 0); + } } TEST_CASE("await_completed_await") { SyncCompletion().get(); +} +TEST_CASE("apartment_context_nop") +{ + TestApartmentContextNop().get(); } \ No newline at end of file diff --git a/test/test_cpp20/clang_only.cpp b/test/test_cpp20/clang_only.cpp new file mode 100644 index 000000000..45aa4b380 --- /dev/null +++ b/test/test_cpp20/clang_only.cpp @@ -0,0 +1,23 @@ +#include "pch.h" +#include + +#ifdef __clang__ + +using namespace winrt; +using namespace Windows::Foundation; +using namespace Windows::Storage::Pickers; + +TEST_CASE("clang_lto_visibility") +{ + // A previous bug report (https://github.com/microsoft/cppwinrt/pull/1482) represented a problem when some linker + // options (-O3 -flto -fwhole-program-vtables) were used with cppwinrt generated code. The lack of public annotation + // caused methods to be removed from the binary, leading to a crash. This test case aims to be a regression test for + // that problem. + FileOpenPicker picker{}; + picker.ViewMode(PickerViewMode::Thumbnail); + picker.FileTypeFilter().Append(L".png"); // This line would trigger the crash. + + REQUIRE(true); +} + +#endif // __clang__ \ No newline at end of file diff --git a/test/test_cpp20/custom_error.cpp b/test/test_cpp20/custom_error.cpp new file mode 100644 index 000000000..b925628d9 --- /dev/null +++ b/test/test_cpp20/custom_error.cpp @@ -0,0 +1,133 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; + +namespace +{ + static bool s_loggerCalled = false; + + void FailOnLine15() + { + // Validate that handler translated exception +#line 15 // Force next line to be reported as line number 15 + REQUIRE_THROWS_AS(check_hresult(0x80000018), hresult_illegal_delegate_assignment); + } + + static struct { + uint32_t lineNumber; + char const* fileName; + char const* functionName; + void* returnAddress; + winrt::hresult result; + } s_loggerArgs{}; + + void __stdcall logger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept + { + s_loggerArgs = { + .lineNumber = lineNumber, + .fileName = fileName, + .functionName = functionName, + .returnAddress = returnAddress, + .result = result, + }; + s_loggerCalled = true; + } +} + +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000 +// not available in libc++ before LLVM 16 +TEST_CASE("custom_error_logger_on_throw", "[!shouldfail]") +#else +TEST_CASE("custom_error_logger_on_throw") +#endif +{ + // Set up global handler + REQUIRE(!s_loggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = logger; + + FailOnLine15(); + REQUIRE(s_loggerCalled); + // In C++20 these fields should be filled in by std::source_location + REQUIRE(s_loggerArgs.lineNumber == 15); + const auto fileNameSv = std::string_view(s_loggerArgs.fileName); + REQUIRE(!fileNameSv.empty()); + REQUIRE(fileNameSv.find("custom_error.cpp") != std::string::npos); +#ifdef _DEBUG + const auto functionNameSv = std::string_view(s_loggerArgs.functionName); + REQUIRE(!functionNameSv.empty()); + // Every compiler has a slightly different naming approach for this function, and even the same + // compiler can change its mind over time. Instead of matching the entire function name just + // match against the part we care about. + REQUIRE((functionNameSv.find("FailOnLine15") != std::string_view::npos)); +#else + REQUIRE(s_loggerArgs.functionName == nullptr); +#endif // _DEBUG + + REQUIRE(s_loggerArgs.returnAddress); + REQUIRE(s_loggerArgs.result == static_cast(0x80000018)); // E_ILLEGAL_DELEGATE_ASSIGNMENT) + + // Remove global handler + winrt_throw_hresult_handler = nullptr; + s_loggerCalled = false; +} +template +void HresultOnLine80(Args... args) +{ + // Validate that handler translated on creating an HRESULT +#line 80 // Force next line to be reported as line number 80 + winrt::hresult_canceled(std::forward(args)...); +} + +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000 +// not available in libc++ before LLVM 16 +TEST_CASE("custom_error_logger_on_originate", "[!shouldfail]") +#else +TEST_CASE("custom_error_logger_on_originate") +#endif +{ + // Set up global handler + REQUIRE(!s_loggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = logger; + + HresultOnLine80(); + REQUIRE(s_loggerCalled); + // In C++20 these fields should be filled in by std::source_location + REQUIRE(s_loggerArgs.lineNumber == 80); + const auto fileNameSv = std::string_view(s_loggerArgs.fileName); + REQUIRE(!fileNameSv.empty()); + REQUIRE(fileNameSv.find("custom_error.cpp") != std::string::npos); +#ifdef _DEBUG + const auto functionNameSv = std::string_view(s_loggerArgs.functionName); + REQUIRE(!functionNameSv.empty()); + // Every compiler has a slightly different naming approach for this function, and even the same + // compiler can change its mind over time. Instead of matching the entire function name just + // match against the part we care about. + REQUIRE((functionNameSv.find("HresultOnLine80") != std::string_view::npos)); +#else + REQUIRE(s_loggerArgs.functionName == nullptr); +#endif // _DEBUG + + REQUIRE(s_loggerArgs.returnAddress); + REQUIRE(s_loggerArgs.result == HRESULT_FROM_WIN32(ERROR_CANCELLED)); // E_ILLEGAL_DELEGATE_ASSIGNMENT) + + s_loggerCalled = false; + s_loggerArgs.lineNumber = 0; + // verify HRESULT with a custom message + HresultOnLine80(L"with custom message"); + REQUIRE(s_loggerCalled); + REQUIRE(s_loggerArgs.lineNumber == 80); + + s_loggerCalled = false; + s_loggerArgs.lineNumber = 0; + // verify that no_originate does _not_ call the logger. + HresultOnLine80(winrt::hresult_error::no_originate); + REQUIRE(!s_loggerCalled); + REQUIRE(s_loggerArgs.lineNumber == 0); + + // Remove global handler + winrt_throw_hresult_handler = nullptr; + s_loggerCalled = false; +} diff --git a/test/test_cpp20/format.cpp b/test/test_cpp20/format.cpp index b3119a77e..d16193328 100644 --- a/test/test_cpp20/format.cpp +++ b/test/test_cpp20/format.cpp @@ -1,4 +1,6 @@ #include "pch.h" + +#ifdef __cpp_lib_format #include struct stringable : winrt::implements @@ -15,14 +17,35 @@ TEST_CASE("format") winrt::hstring str = L"World"; REQUIRE(std::format(L"Hello {}", str) == L"Hello World"); } +} +TEST_CASE("format_make") +{ { winrt::Windows::Foundation::IStringable obj = winrt::make(); REQUIRE(std::format(L"This is {}", obj) == L"This is a stringable object"); } +} +TEST_CASE("format_json") +{ { winrt::Windows::Data::Json::JsonArray jsonArray; REQUIRE(std::format(L"The contents of the array are: {}", jsonArray) == L"The contents of the array are: []"); } } + +TEST_CASE("format_wstring") +{ +#if __cpp_lib_format >= 202207L + { + std::wstring str = L"World"; + REQUIRE(winrt::format(L"Hello {}", str) == L"Hello World"); + } + + { + REQUIRE(winrt::format(L"C++/WinRT #{:d}", 1) == L"C++/WinRT #1"); + } +#endif +} +#endif diff --git a/test/test_cpp20/hstring_literal.cpp b/test/test_cpp20/hstring_literal.cpp new file mode 100644 index 000000000..2ba0f3ad7 --- /dev/null +++ b/test/test_cpp20/hstring_literal.cpp @@ -0,0 +1,68 @@ +#include "pch.h" + +using namespace winrt; +using namespace std::literals; + +#if defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911L + +using namespace winrt::literals; + +namespace +{ + // Exercises the hstring_reference -> param::hstring conversion that projected + // setters rely on, and duplicates into an owning hstring on the way out. + winrt::hstring copy_via_param(winrt::param::hstring const& value) + { + winrt::hstring const& as_hstring = value; + return as_hstring; + } +} + +TEST_CASE("hstring_literal") +{ + // The literal is a genuine constant expression: the fast-pass header is built at + // compile time, so an hstring_reference can be constructed in a constexpr context. + { + constexpr winrt::hstring_reference lit = L"kittens"_hs; + winrt::hstring const& value = lit; + REQUIRE(value == L"kittens"sv); + REQUIRE(value.size() == 7); + } + + // Content and length match the literal. + { + winrt::hstring_reference const lit = L"kittens"_hs; + winrt::hstring const& value = lit; + REQUIRE(value == L"kittens"sv); + REQUIRE(value.size() == 7); + REQUIRE(wcslen(value.c_str()) == 7); + } + + // Built as a fast-pass reference string (no heap allocation). + { + winrt::hstring_reference const lit = L"puppies"_hs; + auto const header = static_cast(winrt::get_abi(lit)); + REQUIRE(header != nullptr); + REQUIRE((header->flags & winrt::impl::hstring_reference_flag) != 0); + REQUIRE(header->length == 7); + } + + // Empty literal projects as the empty (null) HSTRING. + { + winrt::hstring_reference const lit = L""_hs; + winrt::hstring const& value = lit; + REQUIRE(value.empty()); + REQUIRE(value.size() == 0); + REQUIRE(winrt::get_abi(value) == nullptr); + } + + // Binds to a projected setter parameter in a single conversion, and copying + // into an owning hstring duplicates correctly. + { + winrt::hstring const copied = copy_via_param(L"waffles"_hs); + REQUIRE(copied == L"waffles"sv); + REQUIRE(copied.size() == 7); + } +} + +#endif diff --git a/test/test_cpp20/main.cpp b/test/test_cpp20/main.cpp index 7873e4ee7..30687e00c 100644 --- a/test/test_cpp20/main.cpp +++ b/test/test_cpp20/main.cpp @@ -1,4 +1,9 @@ +#include #define CATCH_CONFIG_RUNNER + +// Force reportFatal to be available on mingw-w64 +#define CATCH_CONFIG_WINDOWS_SEH + #include "catch.hpp" #include "winrt/base.h" @@ -7,6 +12,11 @@ using namespace winrt; int main(int const argc, char** argv) { init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); return Catch::Session().run(argc, argv); } diff --git a/test/test_cpp20/pch.h b/test/test_cpp20/pch.h index bd678407c..c1a8f5ff3 100644 --- a/test/test_cpp20/pch.h +++ b/test/test_cpp20/pch.h @@ -8,7 +8,10 @@ #include "winrt/Windows.Foundation.h" #include "winrt/Windows.Foundation.Collections.h" #include "winrt/Windows.Foundation.Numerics.h" +#include "winrt/Windows.Storage.Streams.h" #include #include "catch.hpp" +#include + using namespace std::literals; diff --git a/test/test_cpp20/ranges.cpp b/test/test_cpp20/ranges.cpp index 9bf88a579..9df542696 100644 --- a/test/test_cpp20/ranges.cpp +++ b/test/test_cpp20/ranges.cpp @@ -1,4 +1,6 @@ #include "pch.h" + +#ifdef __cpp_lib_ranges #include #include @@ -46,3 +48,4 @@ TEST_CASE("ranges") REQUIRE((result == std::vector{ 2, 4, 6 })); } } +#endif diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj index 778faa5f0..b13becd23 100644 --- a/test/test_cpp20/test_cpp20.vcxproj +++ b/test/test_cpp20/test_cpp20.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,18 +31,13 @@ {5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA} unittests test_cpp20 - 10.0 - latest + 20 - + Application true - - Application - true - Application true @@ -60,11 +47,6 @@ false true - - Application - false - true - Application false @@ -87,18 +69,12 @@ - - - - - - @@ -109,20 +85,6 @@ - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - MaxSpeed @@ -131,6 +93,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables Console @@ -152,25 +117,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug - - - Console - - - - - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\ - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables Console @@ -190,6 +139,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables Console @@ -209,6 +161,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true + %(AdditionalOptions) -flto -fwhole-program-vtables Console @@ -230,29 +185,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded - - - Console - true - true - - - - - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..\ - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables Console @@ -276,6 +211,9 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true + %(AdditionalOptions) -O3 -flto -fwhole-program-vtables Console @@ -295,9 +233,13 @@ + + + + NotUsing diff --git a/test/test_cpp20_module/collections.cpp b/test/test_cpp20_module/collections.cpp new file mode 100644 index 000000000..b80e123d2 --- /dev/null +++ b/test/test_cpp20_module/collections.cpp @@ -0,0 +1,57 @@ +#include "pch.h" + +import winrt.Windows.Foundation; + +using namespace winrt; +using namespace Windows::Foundation::Collections; + +TEST_CASE("module_vector") +{ + auto vec = single_threaded_vector(); + vec.Append(10); + vec.Append(20); + vec.Append(30); + REQUIRE(vec.Size() == 3); + REQUIRE(vec.GetAt(0) == 10); + REQUIRE(vec.GetAt(2) == 30); + + vec.RemoveAtEnd(); + REQUIRE(vec.Size() == 2); +} + +TEST_CASE("module_map") +{ + auto map = single_threaded_map(); + map.Insert(L"key1", L"value1"); + map.Insert(L"key2", L"value2"); + REQUIRE(map.Size() == 2); + REQUIRE(map.Lookup(L"key1") == L"value1"); + REQUIRE(map.HasKey(L"key2")); + REQUIRE(!map.HasKey(L"key3")); +} + +TEST_CASE("module_observable_vector") +{ + auto vec = single_threaded_observable_vector(); + int change_count = 0; + auto token = vec.VectorChanged([&](auto&&, auto&&) { ++change_count; }); + vec.Append(1); + vec.Append(2); + REQUIRE(change_count == 2); + vec.VectorChanged(token); +} + +TEST_CASE("module_iterable") +{ + auto vec = single_threaded_vector(); + vec.Append(1); + vec.Append(2); + vec.Append(3); + + int sum = 0; + for (auto v : vec) + { + sum += v; + } + REQUIRE(sum == 6); +} diff --git a/test/test_cpp20_module/com_interop.cpp b/test/test_cpp20_module/com_interop.cpp new file mode 100644 index 000000000..3035d2a05 --- /dev/null +++ b/test/test_cpp20_module/com_interop.cpp @@ -0,0 +1,84 @@ +#include "pch.h" +#include +#include + +import std; +import winrt.Windows.Foundation; + +// +// These tests confirm that COM interop — including legacy (non-WinRT) COM types +// from the Windows SDK — works correctly when consumed via modules. +// +// Note: We avoid 'using namespace Windows::Foundation' here because it brings +// IInspectable/IUnknown into scope and collides with the SDK types of the same name. +// + +using namespace winrt; + +TEST_CASE("module_com_ptr_round_trip") +{ + Windows::Foundation::Uri uri(L"https://example.com"); + + // Detach to raw ABI pointer and re-attach + void* abi = detach_abi(uri); + REQUIRE(abi != nullptr); + + Windows::Foundation::Uri uri2{ nullptr }; + attach_abi(uri2, abi); + REQUIRE(uri2.AbsoluteUri() == L"https://example.com/"); +} + +TEST_CASE("module_sdk_iunknown_interop") +{ + // Interop between winrt projected types and the Windows SDK ::IUnknown + Windows::Foundation::Uri uri(L"https://example.com"); + + // Get the SDK IUnknown pointer from a projected type + ::IUnknown* raw = nullptr; + copy_to_abi(uri, *reinterpret_cast(&raw)); + REQUIRE(raw != nullptr); + + // QI for IInspectable through the raw SDK pointer + ::IInspectable* inspectable = nullptr; + REQUIRE(raw->QueryInterface(IID_IInspectable, reinterpret_cast(&inspectable)) == S_OK); + REQUIRE(inspectable != nullptr); + inspectable->Release(); + + // Round-trip back to a projected type + Windows::Foundation::Uri uri2{ nullptr }; + copy_from_abi(uri2, raw); + REQUIRE(uri2.AbsoluteUri() == L"https://example.com/"); + + raw->Release(); +} + +TEST_CASE("module_com_ptr_sdk_type") +{ + // winrt::com_ptr wrapping a Windows SDK ::IUnknown + Windows::Foundation::Uri uri(L"https://example.com"); + + com_ptr<::IUnknown> unknown; + copy_to_abi(uri, *reinterpret_cast(unknown.put())); + REQUIRE(unknown.get() != nullptr); +} + +TEST_CASE("module_iunknown_identity") +{ + Windows::Foundation::Uri uri(L"https://example.com"); + + auto unknown1 = uri.as(); + auto unknown2 = uri.as(); + REQUIRE(unknown1 == unknown2); +} + +TEST_CASE("module_try_as") +{ + Windows::Foundation::Uri uri(L"https://example.com"); + + auto stringable = uri.try_as(); + REQUIRE(stringable != nullptr); + REQUIRE(!stringable.ToString().empty()); + + auto closable = uri.try_as(); + REQUIRE(closable == nullptr); +} diff --git a/test/test_cpp20_module/coroutines.cpp b/test/test_cpp20_module/coroutines.cpp new file mode 100644 index 000000000..1553b1c6d --- /dev/null +++ b/test/test_cpp20_module/coroutines.cpp @@ -0,0 +1,58 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; + +using namespace winrt; +using namespace Windows::Foundation; + +IAsyncAction do_nothing_async() +{ + co_return; +} + +IAsyncOperation return_42_async() +{ + co_return 42; +} + +IAsyncOperation return_string_async() +{ + co_return L"module coroutine"; +} + +IAsyncAction chain_async() +{ + auto result = co_await return_string_async(); + REQUIRE(!result.empty()); +} + +IAsyncOperation slow_operation() +{ + co_await resume_after(std::chrono::hours(1)); + co_return 0; +} + +TEST_CASE("module_async_action") +{ + auto action = do_nothing_async(); + action.get(); + REQUIRE(action.Status() == AsyncStatus::Completed); +} + +TEST_CASE("module_async_operation") +{ + REQUIRE(return_42_async().get() == 42); +} + +TEST_CASE("module_async_chain") +{ + chain_async().get(); +} + +TEST_CASE("module_async_cancel") +{ + auto op = slow_operation(); + op.Cancel(); + REQUIRE(op.Status() == AsyncStatus::Canceled); +} diff --git a/test/test_cpp20_module/format.cpp b/test/test_cpp20_module/format.cpp new file mode 100644 index 000000000..0c4570300 --- /dev/null +++ b/test/test_cpp20_module/format.cpp @@ -0,0 +1,49 @@ +#include "pch.h" + +#ifdef __cpp_lib_format + +import std; +import winrt.Windows.Foundation; + +// +// These tests confirm that std::format and std::formatter specializations work +// correctly when consumed via modules. Mirrors test/test_cpp20/format.cpp. +// + +using namespace winrt; +using namespace Windows::Foundation; + +TEST_CASE("module_format_hstring") +{ + hstring str = L"World"; + REQUIRE(std::format(L"Hello {}", str) == L"Hello World"); +} + +TEST_CASE("module_format_IStringable") +{ + // Uri implements IStringable — exercises the generated + // std::formatter specialization through modules. + Uri uri(L"https://example.com/path"); + IStringable stringable = uri; + REQUIRE(std::format(L"Visit: {}", stringable) == L"Visit: https://example.com/path"); +} + +TEST_CASE("module_format_projected_class") +{ + // Exercises the generated std::formatter specialization + // (inherits from formatter) through modules. + Uri uri(L"https://example.com"); + REQUIRE(std::format(L"URL: {}", uri) == L"URL: https://example.com/"); +} + +#if __cpp_lib_format >= 202207L +TEST_CASE("module_format_winrt_format") +{ + // winrt::format helper (C++23 formattable concept) + std::wstring str = L"World"; + REQUIRE(winrt::format(L"Hello {}", str) == L"Hello World"); + REQUIRE(winrt::format(L"C++/WinRT #{:d}", 1) == L"C++/WinRT #1"); +} +#endif + +#endif // __cpp_lib_format diff --git a/test/test_cpp20_module/foundation.cpp b/test/test_cpp20_module/foundation.cpp new file mode 100644 index 000000000..d26c55244 --- /dev/null +++ b/test/test_cpp20_module/foundation.cpp @@ -0,0 +1,68 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; + +using namespace winrt; +using namespace Windows::Foundation; + +TEST_CASE("module_uri") +{ + Uri uri(L"https://example.com/path?query=1"); + REQUIRE(!uri.AbsoluteUri().empty()); + REQUIRE(uri.Host() == L"example.com"); + REQUIRE(uri.Path() == L"/path"); +} + +TEST_CASE("module_property_value") +{ + auto pv = PropertyValue::CreateInt32(42); + REQUIRE(pv.as().GetInt32() == 42); + + auto pvs = PropertyValue::CreateString(L"hello"); + REQUIRE(pvs.as().GetString() == L"hello"); +} + +TEST_CASE("module_hstring") +{ + hstring text = L"C++/WinRT modules"; + REQUIRE(!text.empty()); + REQUIRE(text.size() == 17); + + hstring empty; + REQUIRE(empty.empty()); + REQUIRE(empty.size() == 0); +} + +TEST_CASE("module_events") +{ + winrt::event> my_event; + int received = 0; + auto token = my_event.add([&](auto&&, int value) { received = value; }); + my_event(nullptr, 42); + REQUIRE(received == 42); + my_event.remove(token); +} + +TEST_CASE("module_foundation_point") +{ + Point p{ 5.0f, 10.0f }; + REQUIRE(p.X == 5.0f); + REQUIRE(p.Y == 10.0f); +} + +TEST_CASE("module_foundation_size") +{ + Size s{ 800.0f, 600.0f }; + REQUIRE(s.Width == 800.0f); + REQUIRE(s.Height == 600.0f); +} + +TEST_CASE("module_foundation_rect") +{ + Point origin{ 0.0f, 0.0f }; + Size extent{ 100.0f, 200.0f }; + Rect r(origin, extent); + REQUIRE(r.X == 0.0f); + REQUIRE(r.Width == 100.0f); +} diff --git a/test/test_cpp20_module/hash.cpp b/test/test_cpp20_module/hash.cpp new file mode 100644 index 000000000..bb7594104 --- /dev/null +++ b/test/test_cpp20_module/hash.cpp @@ -0,0 +1,73 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; + +// +// These tests confirm that std::hash specializations work correctly +// when consumed via modules, enabling use in unordered containers. +// + +using namespace winrt; +using namespace Windows::Foundation; + +TEST_CASE("module_hash_hstring") +{ + std::unordered_set set; + set.insert(L"hello"); + set.insert(L"world"); + set.insert(L"hello"); // duplicate + REQUIRE(set.size() == 2); + REQUIRE(set.contains(L"hello")); + REQUIRE(set.contains(L"world")); +} + +TEST_CASE("module_hash_IUnknown") +{ + Uri uri(L"https://example.com"); + auto unknown = uri.as(); + + std::unordered_set set; + set.insert(unknown); + set.insert(unknown); // duplicate — same identity + REQUIRE(set.size() == 1); + + // A different object should hash differently (almost certainly) + Uri uri2(L"https://other.com"); + set.insert(uri2.as()); + REQUIRE(set.size() == 2); +} + +TEST_CASE("module_hash_projected_type") +{ + // Projected types like Uri should be hashable via the generated + // std::hash specialization (inherits from hash_base). + std::unordered_set set; + Uri u1(L"https://one.com"); + Uri u2(L"https://two.com"); + set.insert(u1); + set.insert(u2); + set.insert(u1); // duplicate + REQUIRE(set.size() == 2); +} + +TEST_CASE("module_hash_guid") +{ + std::unordered_set set; + guid g1{ 0x01020304, 0x0506, 0x0708, { 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 } }; + guid g2{ 0x11121314, 0x1516, 0x1718, { 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20 } }; + set.insert(g1); + set.insert(g2); + set.insert(g1); // duplicate + REQUIRE(set.size() == 2); +} + +TEST_CASE("module_hash_map_with_hstring_key") +{ + std::unordered_map map; + map[L"one"] = 1; + map[L"two"] = 2; + map[L"three"] = 3; + REQUIRE(map.size() == 3); + REQUIRE(map[L"two"] == 2); +} diff --git a/test/test_cpp20_module/main.cpp b/test/test_cpp20_module/main.cpp new file mode 100644 index 000000000..415e26f0f --- /dev/null +++ b/test/test_cpp20_module/main.cpp @@ -0,0 +1,24 @@ +#include +#define CATCH_CONFIG_RUNNER +#define CATCH_CONFIG_WINDOWS_SEH +#include "catch.hpp" + +import winrt_base; + +using namespace winrt; + +int main(int const argc, char** argv) +{ + init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + return Catch::Session().run(argc, argv); +} + +CATCH_TRANSLATE_EXCEPTION(hresult_error const& e) +{ + return to_string(e.message()); +} diff --git a/test/test_cpp20_module/marshal.cpp b/test/test_cpp20_module/marshal.cpp new file mode 100644 index 000000000..d47f8c3cb --- /dev/null +++ b/test/test_cpp20_module/marshal.cpp @@ -0,0 +1,25 @@ +#include "pch.h" +#include +#include + +import std; +import winrt.Windows.Foundation.Collections; + +using namespace winrt; + +struct S : implements +{ + hstring ToString() + { + return L"S"; + } +}; + +// When winrt::impl::get_marshaler was being exported, an MSVC bug caused the marshaler +// object to have a null vtable, which caused a crash when calling any method on the marshaler. +// This test ensures that the marshaler vtable is properly initialized. +TEST_CASE("IMarshal") +{ + auto s = make(); + auto marshal = s.as(); +} diff --git a/test/test_cpp20_module/natvis.cpp b/test/test_cpp20_module/natvis.cpp new file mode 100644 index 000000000..470654d07 --- /dev/null +++ b/test/test_cpp20_module/natvis.cpp @@ -0,0 +1,58 @@ +#include "pch.h" +#include + +import std; +import winrt.Windows.Foundation; + +// +// These tests confirm that the natvis infrastructure (winrt::impl::natvis) +// is reachable through modules, ensuring the debugger visualizer can function. +// natvis is only active in _DEBUG builds. +// + +using namespace winrt; +using namespace Windows::Foundation; + +#ifdef _DEBUG + +TEST_CASE("module_natvis_get_val") +{ + // Verify impl::natvis::get_val is callable through the module. + Uri uri(L"http://example.com/"); + IInspectable inspectable = uri; + + // IStringable IID: {96369F54-8EB6-48F0-ABCE-C1B211E627C3} + // Method index 0 = ToString + auto result = impl::natvis::get_val(&inspectable, L"{96369F54-8EB6-48F0-ABCE-C1B211E627C3}", 0); + + // Compare the natvis result with the direct call + hstring expected = uri.ToString(); + uint32_t expected_len = 0; + auto expected_buf = WindowsGetStringRawBuffer(static_cast(get_abi(expected)), &expected_len); + uint32_t actual_len = 0; + auto actual_buf = WindowsGetStringRawBuffer(static_cast(result.s), &actual_len); + REQUIRE(expected_len == actual_len); + REQUIRE(memcmp(expected_buf, actual_buf, expected_len * sizeof(wchar_t)) == 0); +} + +TEST_CASE("module_natvis_uri_properties") +{ + Uri uri(L"http://moderncpp.com/path"); + IInspectable inspectable = uri; + + // IUriRuntimeClass IID: {9E365E57-48B2-4160-956F-C7385120BBFC} + // Method 5 = Host, Method 7 = Path, Method 11 = SchemeName + auto host_val = impl::natvis::get_val(&inspectable, L"{9E365E57-48B2-4160-956F-C7385120BBFC}", 5); + hstring host_expected = uri.Host(); + REQUIRE(host_expected == hstring{ WindowsGetStringRawBuffer(static_cast(host_val.s), nullptr) }); + + auto path_val = impl::natvis::get_val(&inspectable, L"{9E365E57-48B2-4160-956F-C7385120BBFC}", 7); + hstring path_expected = uri.Path(); + REQUIRE(path_expected == hstring{ WindowsGetStringRawBuffer(static_cast(path_val.s), nullptr) }); + + auto scheme_val = impl::natvis::get_val(&inspectable, L"{9E365E57-48B2-4160-956F-C7385120BBFC}", 11); + hstring scheme_expected = uri.SchemeName(); + REQUIRE(scheme_expected == hstring{ WindowsGetStringRawBuffer(static_cast(scheme_val.s), nullptr) }); +} + +#endif // _DEBUG diff --git a/test/test_cpp20_module/numerics.cpp b/test/test_cpp20_module/numerics.cpp new file mode 100644 index 000000000..0f7dcc7fb --- /dev/null +++ b/test/test_cpp20_module/numerics.cpp @@ -0,0 +1,129 @@ +#include "pch.h" + +#if __has_include() + +import std; +import winrt.Windows.Foundation; +import winrt.Windows.Foundation.Numerics; + +// +// These tests exercise the SDK numerics types (float2, float3, etc.) from +// . These are exported by winrt_numerics and +// transitively available from winrt_base (and thus any namespace module). +// The Point/Size ↔ float2 conversions and name_v/category specializations +// are compiled in winrt_base. +// + +using namespace winrt; +using namespace winrt::Windows::Foundation; +using namespace winrt::Windows::Foundation::Numerics; + +// --- SDK math types (from winrt_numerics, re-exported via winrt_base) --- + +TEST_CASE("module_numerics_float2") +{ + float2 a{ 1.0f, 2.0f }; + float2 b{ 3.0f, 4.0f }; + + auto c = a + b; + REQUIRE(c.x == 4.0f); + REQUIRE(c.y == 6.0f); + + REQUIRE(length(a) > 0.0f); +} + +TEST_CASE("module_numerics_float3") +{ + float3 v{ 1.0f, 0.0f, 0.0f }; + float3 up{ 0.0f, 1.0f, 0.0f }; + + REQUIRE(dot(v, up) == 0.0f); + REQUIRE(cross(v, up).z != 0.0f); +} + +TEST_CASE("module_numerics_float4x4") +{ + auto identity = float4x4::identity(); + REQUIRE(identity.m11 == 1.0f); + REQUIRE(identity.m12 == 0.0f); + + auto t = make_float4x4_translation({ 10.0f, 20.0f, 30.0f }); + REQUIRE(t.m41 == 10.0f); +} + +TEST_CASE("module_numerics_quaternion") +{ + auto identity = quaternion::identity(); + REQUIRE(identity.w == 1.0f); + REQUIRE(length(identity) == 1.0f); +} + +// --- Point/Size ↔ float2 conversions (compiled in winrt_base) --- + +TEST_CASE("module_numerics_point_from_float2") +{ + Point p(float2{ 3.0f, 7.0f }); + REQUIRE(p.X == 3.0f); + REQUIRE(p.Y == 7.0f); +} + +TEST_CASE("module_numerics_point_to_float2") +{ + float2 v = Point{ 10.0f, 20.0f }; + REQUIRE(v.x == 10.0f); + REQUIRE(v.y == 20.0f); +} + +TEST_CASE("module_numerics_size_from_float2") +{ + Size s(float2{ 100.0f, 200.0f }); + REQUIRE(s.Width == 100.0f); + REQUIRE(s.Height == 200.0f); +} + +TEST_CASE("module_numerics_size_to_float2") +{ + float2 v = Size{ 640.0f, 480.0f }; + REQUIRE(v.x == 640.0f); + REQUIRE(v.y == 480.0f); +} + +// --- WinRT projection metadata (name_v/category, compiled in winrt_base) --- +// Verify that the projection machinery produces correct IReference GUIDs +// for numerics types. This exercises name_v, category, and the SHA-1 based +// GUID computation across module boundaries, at compile time. + +namespace +{ + constexpr bool equal(guid const& left, guid const& right) noexcept + { + return left.Data1 == right.Data1 && + left.Data2 == right.Data2 && + left.Data3 == right.Data3 && + left.Data4[0] == right.Data4[0] && + left.Data4[1] == right.Data4[1] && + left.Data4[2] == right.Data4[2] && + left.Data4[3] == right.Data4[3] && + left.Data4[4] == right.Data4[4] && + left.Data4[5] == right.Data4[5] && + left.Data4[6] == right.Data4[6] && + left.Data4[7] == right.Data4[7]; + } +} + +#define REQUIRE_EQUAL_GUID(left, ...) STATIC_REQUIRE(equal(guid(left), guid_of<__VA_ARGS__>())); + +TEST_CASE("module_numerics_ireference_guids") +{ + REQUIRE_EQUAL_GUID("48F6A69E-8465-57AE-9400-9764087F65AD", IReference); + REQUIRE_EQUAL_GUID("1EE770FF-C954-59CA-A754-6199A9BE282C", IReference); + REQUIRE_EQUAL_GUID("A5E843C9-ED20-5339-8F8D-9FE404CF3654", IReference); + REQUIRE_EQUAL_GUID("76358CFD-2CBD-525B-A49E-90EE18247B71", IReference); + REQUIRE_EQUAL_GUID("DACBFFDC-68EF-5FD0-B657-782D0AC9807E", IReference); + REQUIRE_EQUAL_GUID("B27004BB-C014-5DCE-9A21-799C5A3C1461", IReference); + REQUIRE_EQUAL_GUID("46D542A1-52F7-58E7-ACFC-9A6D364DA022", IReference); +} + +#undef REQUIRE_EQUAL_GUID + +#endif // __has_include() diff --git a/test/test_cpp20_module/pch.cpp b/test/test_cpp20_module/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/test_cpp20_module/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/test_cpp20_module/pch.h b/test/test_cpp20_module/pch.h new file mode 100644 index 000000000..d0eb301ac --- /dev/null +++ b/test/test_cpp20_module/pch.h @@ -0,0 +1,3 @@ +#pragma once + +#include "catch.hpp" diff --git a/test/test_cpp20_module/range_for.cpp b/test/test_cpp20_module/range_for.cpp new file mode 100644 index 000000000..962c97179 --- /dev/null +++ b/test/test_cpp20_module/range_for.cpp @@ -0,0 +1,135 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation.Collections; + +// +// These tests confirm that C++/WinRT collections support range-based for loop iteration +// and structured bindings when consumed via modules. +// + +using namespace winrt; +using namespace Windows::Foundation::Collections; + +TEST_CASE("module_range_for_IIterable") +{ + IIterable c = single_threaded_vector({ 1, 2, 3 }); + std::vector result; + + for (int i : c) + { + result.push_back(i); + } + + REQUIRE(result.size() == 3); + REQUIRE(result[0] == 1); + REQUIRE(result[1] == 2); + REQUIRE(result[2] == 3); +} + +TEST_CASE("module_range_for_IVector") +{ + IVector c = single_threaded_vector({ 1, 2, 3 }); + std::vector result; + + for (int i : c) + { + result.push_back(i); + } + + REQUIRE(result.size() == 3); + REQUIRE(result[0] == 1); + REQUIRE(result[1] == 2); + REQUIRE(result[2] == 3); +} + +TEST_CASE("module_range_for_IVectorView") +{ + IVectorView c = single_threaded_vector({ 1, 2, 3 }).GetView(); + std::vector result; + + for (int i : c) + { + result.push_back(i); + } + + REQUIRE(result.size() == 3); + REQUIRE(result[0] == 1); + REQUIRE(result[1] == 2); + REQUIRE(result[2] == 3); +} + +TEST_CASE("module_structured_bindings_IKeyValuePair") +{ + std::map values + { + { 1, L"one"}, + { 2, L"two"}, + { 3, L"three"}, + }; + + IIterable> c = single_threaded_map(std::map(values)); + std::map result; + + for (IKeyValuePair i : c) + { + result[i.Key()] = i.Value(); + + // Structured binding on IKeyValuePair + auto const [key, value] = i; + REQUIRE(key == i.Key()); + REQUIRE(value == i.Value()); + } + + REQUIRE(result == values); + + // Range-for with structured bindings + result.clear(); + + for (auto&& [key, value] : c) + { + result[key] = value; + } + + REQUIRE(result == values); +} + +TEST_CASE("module_range_for_IMap") +{ + std::map values + { + { 1, L"one" }, + { 2, L"two" }, + { 3, L"three" }, + }; + + IMap c = single_threaded_map(std::map(values)); + std::map result; + + for (auto&& [key, value] : c) + { + result[key] = value; + } + + REQUIRE(result == values); +} + +TEST_CASE("module_range_for_IMapView") +{ + std::map values + { + { 1, L"one" }, + { 2, L"two" }, + { 3, L"three" }, + }; + + IMapView c = single_threaded_map(std::map(values)).GetView(); + std::map result; + + for (auto&& [key, value] : c) + { + result[key] = value; + } + + REQUIRE(result == values); +} diff --git a/test/test_cpp20_module/source_location.cpp b/test/test_cpp20_module/source_location.cpp new file mode 100644 index 000000000..ebf5139c3 --- /dev/null +++ b/test/test_cpp20_module/source_location.cpp @@ -0,0 +1,13 @@ +#include "pch.h" + +import std; +import winrt.Windows.Foundation; + +TEST_CASE("module_source_location") +{ + // Verify that slim_source_location works across the module boundary + auto loc = winrt::impl::slim_source_location::current(); + REQUIRE(loc.line() > 0); + std::string_view file(loc.file_name()); + REQUIRE(file.find("source_location.cpp") != std::string_view::npos); +} diff --git a/test/test_cpp20_module/test_cpp20_module.vcxproj b/test/test_cpp20_module/test_cpp20_module.vcxproj new file mode 100644 index 000000000..f5c20a35d --- /dev/null +++ b/test/test_cpp20_module/test_cpp20_module.vcxproj @@ -0,0 +1,114 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {B8E3A5CE-4E91-4F27-9B02-E0CAF7E10D72} + test_cpp20_module + test_cpp20_module + 10.0 + v145 + + + + Application + v145 + + + true + + + false + true + + + + + + + + + $(IntDir)Generated Files\ + + + + Use + pch.h + stdcpplatest + $(CppWinRTGenDir);..\;%(AdditionalIncludeDirectories) + NOMINMAX;%(PreprocessorDefinitions) + Level4 + true + 5311 + /bigobj + true + true + + + Console + ole32.lib;windowsapp.lib;%(AdditionalDependencies) + + + "$(CppWinRTDir)cppwinrt.exe" -in local -out "$(CppWinRTGenDir)." -modules -base -verbose -module_include "Windows.Foundation" -module_exclude "Windows.Foundation.Diagnostics" + + + + + + + CompileAsCppModule + true + NotUsing + + + + + + + + + + Create + + + NotUsing + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/test_cpp20_no_sourcelocation/CMakeLists.txt b/test/test_cpp20_no_sourcelocation/CMakeLists.txt new file mode 100644 index 000000000..1944aece8 --- /dev/null +++ b/test/test_cpp20_no_sourcelocation/CMakeLists.txt @@ -0,0 +1,48 @@ +set(CMAKE_CXX_STANDARD 20) +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # std::format, std::ranges::is_heap, std::views::reverse, std::ranges::max + # are experimental in libc++ as of Clang 15. + # FIXME: Should probably use compile test instead? + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library") +endif() + +if(ENABLE_TEST_SANITIZERS) + # As of LLVM 15, custom_error.cpp doesn't build with ASAN due to: + # error: cannot make section .ASAN$GL associative with sectionless symbol _ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE4nposE + set_source_files_properties(custom_error.cpp PROPERTIES COMPILE_OPTIONS "-fno-sanitize=address") + set_source_files_properties(custom_error.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS true) +endif() + +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp") + + +list(APPEND BROKEN_TESTS + # No broken tests. +) + +# Exclude broken tests +foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS) + list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp") +endforeach() + +add_executable(test_cpp20_no_sourcelocation main.cpp ${TEST_SRCS}) + +target_compile_definitions(test_cpp20_no_sourcelocation PRIVATE WINRT_NO_SOURCE_LOCATION) + +target_precompile_headers(test_cpp20_no_sourcelocation PRIVATE pch.h) +set_source_files_properties( + main.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true +) + +add_dependencies(test_cpp20_no_sourcelocation build-cppwinrt-projection) + +add_test( + NAME test_cpp20_no_sourcelocation + COMMAND "$" ${TEST_COLOR_ARG} +) diff --git a/test/test_cpp20_no_sourcelocation/custom_error.cpp b/test/test_cpp20_no_sourcelocation/custom_error.cpp new file mode 100644 index 000000000..d9905ea04 --- /dev/null +++ b/test/test_cpp20_no_sourcelocation/custom_error.cpp @@ -0,0 +1,61 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; + +namespace +{ + static bool s_loggerCalled = false; + + // Note that we are checking that the source line number matches expectations. If lines above this are changed + // then this value needs to change as well. + void FailOnLine15() + { + // Validate that handler translated exception + REQUIRE_THROWS_AS(check_hresult(0x80000018), hresult_illegal_delegate_assignment); + } + + static struct { + uint32_t lineNumber; + char const* fileName; + char const* functionName; + void* returnAddress; + winrt::hresult result; + } s_loggerArgs{}; + + void __stdcall logger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept + { + s_loggerArgs = { + .lineNumber = lineNumber, + .fileName = fileName, + .functionName = functionName, + .returnAddress = returnAddress, + .result = result, + }; + s_loggerCalled = true; + } +} + +TEST_CASE("custom_error_logger") +{ + // Set up global handler + REQUIRE(!s_loggerCalled); + REQUIRE(!winrt_throw_hresult_handler); + winrt_throw_hresult_handler = logger; + + FailOnLine15(); + REQUIRE(s_loggerCalled); + // In C++20 these fields should be filled in by std::source_location. However, this binary has + // specified WINRT_NO_SOURCE_LOCATION so that support should be removed. As a result these should + // return the same (empty) values as C++17. + REQUIRE(s_loggerArgs.lineNumber == 0); + REQUIRE(s_loggerArgs.fileName == nullptr); + REQUIRE(s_loggerArgs.functionName == nullptr); + + REQUIRE(s_loggerArgs.returnAddress); + REQUIRE(s_loggerArgs.result == static_cast(0x80000018)); // E_ILLEGAL_DELEGATE_ASSIGNMENT) + + // Remove global handler + winrt_throw_hresult_handler = nullptr; + s_loggerCalled = false; +} diff --git a/test/test_cpp20_no_sourcelocation/main.cpp b/test/test_cpp20_no_sourcelocation/main.cpp new file mode 100644 index 000000000..10150c369 --- /dev/null +++ b/test/test_cpp20_no_sourcelocation/main.cpp @@ -0,0 +1,26 @@ +#include +#define CATCH_CONFIG_RUNNER + +// Force reportFatal to be available on mingw-w64 +#define CATCH_CONFIG_WINDOWS_SEH + +#include "catch.hpp" +#include "winrt/base.h" + +using namespace winrt; + +int main(int const argc, char** argv) +{ + init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + return Catch::Session().run(argc, argv); +} + +CATCH_TRANSLATE_EXCEPTION(hresult_error const& e) +{ + return to_string(e.message()); +} diff --git a/test/test_cpp20_no_sourcelocation/pch.cpp b/test/test_cpp20_no_sourcelocation/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/test_cpp20_no_sourcelocation/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/test_cpp20_no_sourcelocation/pch.h b/test/test_cpp20_no_sourcelocation/pch.h new file mode 100644 index 000000000..6565bea1b --- /dev/null +++ b/test/test_cpp20_no_sourcelocation/pch.h @@ -0,0 +1,16 @@ +#pragma once + +#pragma warning(4: 4458) // ensure we compile clean with this warning enabled + +#define WINRT_LEAN_AND_MEAN +#include +#include "winrt/Windows.Data.Json.h" +#include "winrt/Windows.Foundation.h" +#include "winrt/Windows.Foundation.Collections.h" +#include "winrt/Windows.Foundation.Numerics.h" +#include +#include "catch.hpp" + +#include + +using namespace std::literals; diff --git a/test/test_cpp20_no_sourcelocation/test_cpp20_no_sourcelocation.vcxproj b/test/test_cpp20_no_sourcelocation/test_cpp20_no_sourcelocation.vcxproj new file mode 100644 index 000000000..85c3e1532 --- /dev/null +++ b/test/test_cpp20_no_sourcelocation/test_cpp20_no_sourcelocation.vcxproj @@ -0,0 +1,237 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {D4C8F881-84D5-4A7B-8BDE-AB4E34A05374} + unittests + test_cpp20_no_sourcelocation + 20 + + + + Application + true + + + Application + true + + + Application + false + true + + + Application + false + true + + + Application + true + + + Application + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WINRT_NO_SOURCE_LOCATION;%(PreprocessorDefinitions) + Level4 + true + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + + + + + + + + + + + + + + + + + NotUsing + + + Create + + + + + + \ No newline at end of file diff --git a/test/test_fast/Nomadic.cpp b/test/test_fast/Nomadic.cpp new file mode 100644 index 000000000..c29150e17 --- /dev/null +++ b/test/test_fast/Nomadic.cpp @@ -0,0 +1,44 @@ +#include "pch.h" +#include "winrt/test_component_fast.h" +#include + +using namespace winrt; +using namespace test_component_fast; + +hstring invoke_by_interface_vtable_offset(Nomadic const& nomadic, ptrdiff_t offset) +{ + // NOTE: Behavior guaranteed by Windows ABI; see the "C style interface" for WinRT/COM types for more info. Note + // that IInspectable has 6 functions in total (including those inherited from IUnknown) + auto insp = static_cast<::IInspectable*>(get_abi(nomadic)); + auto vtable = *reinterpret_cast(insp); + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmicrosoft-cast" +#endif + auto fn_ptr = static_cast(vtable[6 + offset]); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + HSTRING hstr; + check_hresult(fn_ptr(insp, &hstr)); + + hstring result; + attach_abi(result, hstr); + return result; +} + +TEST_CASE("Nomadic") +{ + impl::get_diagnostics_info().detach(); + + Nomadic n; + REQUIRE(invoke_by_interface_vtable_offset(n, 0) == L"FirstMethod"); + REQUIRE(invoke_by_interface_vtable_offset(n, 1) == L"SecondMethod"); + REQUIRE(invoke_by_interface_vtable_offset(n, 2) == L"ThirdMethod"); + REQUIRE(invoke_by_interface_vtable_offset(n, 3) == L"FourthMethod"); + REQUIRE(invoke_by_interface_vtable_offset(n, 4) == L"FifthMethod"); + REQUIRE(invoke_by_interface_vtable_offset(n, 5) == L"SixthMethod"); + REQUIRE(invoke_by_interface_vtable_offset(n, 6) == L"SeventhMethod"); +} diff --git a/test/test_fast/main.cpp b/test/test_fast/main.cpp index 7873e4ee7..7590df7e1 100644 --- a/test/test_fast/main.cpp +++ b/test/test_fast/main.cpp @@ -1,3 +1,4 @@ +#include #define CATCH_CONFIG_RUNNER #include "catch.hpp" #include "winrt/base.h" @@ -7,6 +8,11 @@ using namespace winrt; int main(int const argc, char** argv) { init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); return Catch::Session().run(argc, argv); } diff --git a/test/test_fast/test_fast.vcxproj b/test/test_fast/test_fast.vcxproj index 567c8f8f2..c01907348 100644 --- a/test/test_fast/test_fast.vcxproj +++ b/test/test_fast/test_fast.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,17 +31,12 @@ {F8A1FE5A-DC8A-49DF-B882-DEF76E38E484} unittests test_fast - 10.0 - + Application true - - Application - true - Application true @@ -59,11 +46,6 @@ false true - - Application - false - true - Application false @@ -86,18 +68,12 @@ - - - - - - @@ -108,20 +84,6 @@ - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - MaxSpeed @@ -130,6 +92,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -151,25 +115,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug - - - Console - false - - - $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component_fast.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\; - WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug + Level4 + true Console @@ -189,6 +136,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -208,6 +157,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -229,29 +180,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded - - - Console - true - true - false - - - $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component_fast.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..\; - WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded + Level4 + true Console @@ -275,6 +205,8 @@ $(OutputPath);Generated Files;..\; WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -298,6 +230,7 @@ NotUsing + Create diff --git a/test/test_fast_fwd/FastForwarderTests.cpp b/test/test_fast_fwd/FastForwarderTests.cpp index 5a10216bf..8a80eaf1c 100644 --- a/test/test_fast_fwd/FastForwarderTests.cpp +++ b/test/test_fast_fwd/FastForwarderTests.cpp @@ -1,8 +1,8 @@ #include "pch.h" #include -#include "winrt\fast_forward.h" -#include "winrt\Windows.Foundation.h" -#include "winrt\FastForwarderTest.h" +#include "winrt/fast_forward.h" +#include "winrt/Windows.Foundation.h" +#include "winrt/FastForwarderTest.h" #include "Class.g.h" using namespace std::literals; diff --git a/test/test_fast_fwd/main.cpp b/test/test_fast_fwd/main.cpp index f9b9c73d2..c5b6040f7 100644 --- a/test/test_fast_fwd/main.cpp +++ b/test/test_fast_fwd/main.cpp @@ -1,3 +1,4 @@ +#include #define CATCH_CONFIG_RUNNER #include "catch.hpp" #include "winrt/base.h" @@ -10,6 +11,11 @@ using namespace winrt; int main(int const argc, char** argv) { init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); return Catch::Session().run(argc, argv); } diff --git a/test/test_fast_fwd/test_fast_fwd.vcxproj b/test/test_fast_fwd/test_fast_fwd.vcxproj index 14b559bcd..6d049b1a9 100644 --- a/test/test_fast_fwd/test_fast_fwd.vcxproj +++ b/test/test_fast_fwd/test_fast_fwd.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -40,9 +32,8 @@ {303CC0FE-7D66-4F9F-B7A1-0AF7F9359074} unittests test_fast_fwd - 10.0 - + Application true @@ -60,7 +51,6 @@ Midl - $(OutDir)temp\$(ProjectName)\ @@ -69,6 +59,8 @@ true $(CppWinRTDir);$(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -96,6 +88,8 @@ pch.h true WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -116,6 +110,8 @@ Disabled $(CppWinRTDir);$(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -128,35 +124,13 @@ - - - Disabled - true - true - $(CppWinRTDir);$(OutputPath);Generated Files;..\ - stdcpp17 - Use - pch.h - true - WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) - - - Console - windowsapp.lib - - - $(CppWinRTDir)cppwinrt -in $(CppWinRTDir)test_component_fast.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - Disabled $(CppWinRTDir);$(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -180,6 +154,8 @@ pch.h true WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -200,6 +176,8 @@ true $(CppWinRTDir);$(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) + Level4 + true Console @@ -214,34 +192,6 @@ - - - MaxSpeed - true - true - true - true - $(CppWinRTDir);$(OutputPath);Generated Files;..\ - stdcpp17 - Use - pch.h - true - WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) - - - Console - true - true - windowsapp.lib - - - $(CppWinRTDir)cppwinrt -in $(CppWinRTDir)test_component_fast.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - @@ -327,18 +277,12 @@ false MultiThreaded - - MultiThreaded - MultiThreaded MultiThreaded - - MultiThreadedDebug - MultiThreadedDebug diff --git a/test/test_module_lock_custom/main.cpp b/test/test_module_lock_custom/main.cpp index 1372f2554..862df57df 100644 --- a/test/test_module_lock_custom/main.cpp +++ b/test/test_module_lock_custom/main.cpp @@ -1,3 +1,4 @@ +#include #define CATCH_CONFIG_RUNNER #include "catch.hpp" @@ -60,5 +61,10 @@ TEST_CASE("module_lock_custom") int main(int const argc, char** argv) { + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); return Catch::Session().run(argc, argv); } diff --git a/test/test_module_lock_custom/test_module_lock_custom.vcxproj b/test/test_module_lock_custom/test_module_lock_custom.vcxproj index fab6a61f6..64da0d8bc 100644 --- a/test/test_module_lock_custom/test_module_lock_custom.vcxproj +++ b/test/test_module_lock_custom/test_module_lock_custom.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,17 +31,12 @@ {08C40663-B6A3-481E-8755-AE32BAD99501} unittests test_module_lock_custom - 10.0 - + Application true - - Application - true - Application true @@ -59,11 +46,6 @@ false true - - Application - false - true - Application false @@ -86,18 +68,12 @@ - - - - - - @@ -108,20 +84,6 @@ - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - MaxSpeed @@ -130,6 +92,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -151,25 +115,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug - - - Console - - - - - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\; - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug + Level4 + true Console @@ -189,6 +136,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -208,6 +157,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -229,29 +180,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded - - - Console - true - true - - - - - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..\; - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded + Level4 + true Console @@ -275,6 +205,8 @@ $(OutputPath);Generated Files;..\; NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console diff --git a/test/test_module_lock_none/main.cpp b/test/test_module_lock_none/main.cpp index 6fb4d379f..9648ad8be 100644 --- a/test/test_module_lock_none/main.cpp +++ b/test/test_module_lock_none/main.cpp @@ -1,3 +1,4 @@ +#include #define CATCH_CONFIG_RUNNER #include "catch.hpp" #include @@ -56,14 +57,31 @@ TEST_CASE("module_lock_none") // Validates that test_component_base is pinned by virtue of it defining WINRT_NO_MODULE_LOCK. +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-function-type-mismatch" +#endif auto can_unload = reinterpret_cast(GetProcAddress(LoadLibraryA("test_component_base.dll"), "DllCanUnloadNow")); REQUIRE(can_unload() == S_FALSE); auto cannot_unload = reinterpret_cast(GetProcAddress(LoadLibraryA("test_component_derived.dll"), "DllCanUnloadNow")); REQUIRE(cannot_unload() == S_OK); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif } int main(int const argc, char** argv) { + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); return Catch::Session().run(argc, argv); } + +CATCH_TRANSLATE_EXCEPTION(winrt::hresult_error const& e) +{ + return to_string(e.message()); +} diff --git a/test/test_module_lock_none/test_module_lock_none.vcxproj b/test/test_module_lock_none/test_module_lock_none.vcxproj index fb64f7d94..d9242a281 100644 --- a/test/test_module_lock_none/test_module_lock_none.vcxproj +++ b/test/test_module_lock_none/test_module_lock_none.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,17 +31,12 @@ {D48A96C2-8512-4CC3-B6E4-7CFF07ED8ED3} unittests test_module_lock_none - 10.0 - + Application true - - Application - true - Application true @@ -59,11 +46,6 @@ false true - - Application - false - true - Application false @@ -86,18 +68,12 @@ - - - - - - @@ -108,20 +84,6 @@ - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - MaxSpeed @@ -130,6 +92,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -151,25 +115,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug - - - Console - - - - - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\ - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug + Level4 + true Console @@ -189,6 +136,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -208,6 +157,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -229,29 +180,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded - - - Console - true - true - - - - - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..\ - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded + Level4 + true Console @@ -275,6 +205,8 @@ $(OutputPath);Generated Files;..\ NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console diff --git a/test/test_nocoro/CMakeLists.txt b/test/test_nocoro/CMakeLists.txt new file mode 100644 index 000000000..ee234f146 --- /dev/null +++ b/test/test_nocoro/CMakeLists.txt @@ -0,0 +1,35 @@ +set(CMAKE_CXX_STANDARD 17) + +file(GLOB TEST_SRCS + LIST_DIRECTORIES false + CONFIGURE_DEPENDS + *.cpp +) +list(FILTER TEST_SRCS EXCLUDE REGEX "/(main|pch)\\.cpp") + + +list(APPEND BROKEN_TESTS + # No broken tests. +) + +# Exclude broken tests +foreach(TEST_SRCS_EXCLUDE_ITEM IN LISTS BROKEN_TESTS) + list(FILTER TEST_SRCS EXCLUDE REGEX "/${TEST_SRCS_EXCLUDE_ITEM}\\.cpp") +endforeach() + +add_executable(test_nocoro main.cpp ${TEST_SRCS}) + +target_compile_definitions(test_nocoro PRIVATE WINRT_NO_SOURCE_LOCATION) + +target_precompile_headers(test_nocoro PRIVATE pch.h) +set_source_files_properties( + main.cpp + PROPERTIES SKIP_PRECOMPILE_HEADERS true +) + +add_dependencies(test_nocoro build-cppwinrt-projection) + +add_test( + NAME test_nocoro + COMMAND "$" ${TEST_COLOR_ARG} +) diff --git a/test/test_nocoro/get.cpp b/test/test_nocoro/get.cpp new file mode 100644 index 000000000..4fd85fe3e --- /dev/null +++ b/test/test_nocoro/get.cpp @@ -0,0 +1,114 @@ +#include "pch.h" + +using namespace winrt; +using namespace Windows::Foundation; +using namespace Windows::Storage; + +template +struct async_completion_source : implements, IAsyncOperation, IAsyncInfo> +{ + void set_result(TResult result) + { + m_result = std::move(result); + m_status = AsyncStatus::Completed; + m_completed(*this, m_status); + } + + void Completed(AsyncOperationCompletedHandler completed) + { + m_completed = completed; + } + + AsyncOperationCompletedHandler Completed() const noexcept + { + return m_completed; + } + + TResult GetResults() + { + return m_result.value(); + } + + uint32_t Id() const + { + return 1; + } + + AsyncStatus Status() const + { + return m_status; + } + + hresult ErrorCode() const + { + return hresult(0); // S_OK + } + + void Cancel() const + { + throw hresult_error(0x80070032); // E_NOT_SUPPORTED + } + + void Close() const + { + } + +private: + AsyncStatus m_status = AsyncStatus::Started; + AsyncOperationCompletedHandler m_completed; + std::optional m_result; +}; + +TEST_CASE("get") +{ + auto acs = winrt::make_self>(); + + std::thread worker([acs] + { + std::this_thread::sleep_for(1s); + acs->set_result(0xDEADBEEF); + }); + + worker.detach(); + + REQUIRE(acs.as>().get() == 0xDEADBEEF); +} + +TEST_CASE("get_unchecked") +{ + // Call a real WinRT async operation from an STA thread. + // This is the scenario the new API is designed for: an STA that is not + // presenting UI, where a synchronous blocking wait is safe. + std::exception_ptr failure{}; + bool content_available = false; + std::thread sta_thread([&failure, &content_available] + { + try + { + winrt::init_apartment(winrt::apartment_type::single_threaded); + struct apartment_guard + { + ~apartment_guard() + { + winrt::uninit_apartment(); + } + } guard; + + auto content = PathIO::ReadTextAsync(L"C:\\Windows\\win.ini").get_unchecked(); + content_available = content.size() > 0; + } + catch (...) + { + failure = std::current_exception(); + } + }); + + sta_thread.join(); + + if (failure) + { + std::rethrow_exception(failure); + } + + REQUIRE(content_available); +} diff --git a/test/test_win7/main.cpp b/test/test_nocoro/main.cpp similarity index 60% rename from test/test_win7/main.cpp rename to test/test_nocoro/main.cpp index 7c55cbbed..7590df7e1 100644 --- a/test/test_win7/main.cpp +++ b/test/test_nocoro/main.cpp @@ -1,3 +1,4 @@ +#include #define CATCH_CONFIG_RUNNER #include "catch.hpp" #include "winrt/base.h" @@ -8,6 +9,10 @@ int main(int const argc, char** argv) { init_apartment(); std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); return Catch::Session().run(argc, argv); } diff --git a/test/test_nocoro/pch.cpp b/test/test_nocoro/pch.cpp new file mode 100644 index 000000000..1d9f38c57 --- /dev/null +++ b/test/test_nocoro/pch.cpp @@ -0,0 +1 @@ +#include "pch.h" diff --git a/test/test_nocoro/pch.h b/test/test_nocoro/pch.h new file mode 100644 index 000000000..30a6d3079 --- /dev/null +++ b/test/test_nocoro/pch.h @@ -0,0 +1,7 @@ +#pragma once + +#include "catch.hpp" +#include "winrt/Windows.Foundation.h" +#include "winrt/Windows.Storage.h" + +using namespace std::literals; diff --git a/test/test_nocoro/test_nocoro.vcxproj b/test/test_nocoro/test_nocoro.vcxproj new file mode 100644 index 000000000..7efc28066 --- /dev/null +++ b/test/test_nocoro/test_nocoro.vcxproj @@ -0,0 +1,241 @@ + + + + + Debug + ARM64 + + + Debug + Win32 + + + Release + ARM64 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + {9E392830-805A-4AAF-932D-C493143EFACA} + unittests + test_nocoro + false + + + + Application + true + + + Application + true + + + Application + false + true + + + Application + false + true + + + Application + true + + + Application + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + + + Console + true + true + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + + + Console + + + + + + + + + + + + + Disabled + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreadedDebug + Level4 + true + + + Console + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + + + Console + true + true + + + + + + + + + + + + + MaxSpeed + true + true + $(OutputPath);Generated Files;..\ + NOMINMAX;_MBCS;%(PreprocessorDefinitions) + MultiThreaded + Level4 + true + + + Console + true + true + + + + + + + + + + + + + + + + + NotUsing + + + Create + + + + + + \ No newline at end of file diff --git a/test/test_slow/main.cpp b/test/test_slow/main.cpp index 7873e4ee7..7590df7e1 100644 --- a/test/test_slow/main.cpp +++ b/test/test_slow/main.cpp @@ -1,3 +1,4 @@ +#include #define CATCH_CONFIG_RUNNER #include "catch.hpp" #include "winrt/base.h" @@ -7,6 +8,11 @@ using namespace winrt; int main(int const argc, char** argv) { init_apartment(); + std::set_terminate([] { reportFatal("Abnormal termination"); ExitProcess(1); }); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + (void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); return Catch::Session().run(argc, argv); } diff --git a/test/test_slow/test_slow.vcxproj b/test/test_slow/test_slow.vcxproj index 492f05848..5b753a17a 100644 --- a/test/test_slow/test_slow.vcxproj +++ b/test/test_slow/test_slow.vcxproj @@ -1,10 +1,6 @@ - - Debug - ARM - Debug ARM64 @@ -13,10 +9,6 @@ Debug Win32 - - Release - ARM - Release ARM64 @@ -39,17 +31,12 @@ {B68C61C6-4699-41E6-A158-EA1BE029E7A0} unittests test_slow - 10.0 - + Application true - - Application - true - Application true @@ -59,11 +46,6 @@ false true - - Application - false - true - Application false @@ -86,18 +68,12 @@ - - - - - - @@ -108,20 +84,6 @@ - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - MaxSpeed @@ -130,6 +92,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console @@ -150,24 +114,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug - - - Console - - - $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component_fast.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose - - - - - - - - - Disabled - $(OutputPath);Generated Files;..\ - WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug + Level4 + true Console @@ -186,6 +134,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -204,6 +154,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreadedDebug + Level4 + true Console @@ -224,28 +176,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded - - - Console - true - true - - - $(CppWinRTDir)cppwinrt -in $(OutputPath)test_component_fast.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..\ - WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded + Level4 + true Console @@ -268,6 +200,8 @@ $(OutputPath);Generated Files;..\ WINRT_DIAGNOSTICS;NOMINMAX;_MBCS;%(PreprocessorDefinitions) MultiThreaded + Level4 + true Console diff --git a/test/test_win7/GetMany.cpp b/test/test_win7/GetMany.cpp deleted file mode 100644 index 23ea63e1e..000000000 --- a/test/test_win7/GetMany.cpp +++ /dev/null @@ -1,378 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation::Collections; - -// -// Now that all of the generics are generated (rather than hand-written), it's far less likely -// that something like GetMany is incorrect. And the "FillArray" pattern used by GetMany is -// tested elsewhere in the out_params and return_params tests. However since C++/WinRT provides -// an implementation of GetMany over and above the projection, these tests validate the this -// implementation is correct. Other tests exist for collections under 'old_tests' but new -// optimizations are coming for GetMany and I want to make sure that GetMany is completely -// covered. -// - -namespace -{ - template - IIterator single_threaded_generator(std::vector&& values = {}) - { - // This iterator may only be advanced once, ensuring the GetMany complexity optimization - // is actually enforced with this test. - - struct generator_container - { - explicit generator_container(IIterator const& first) : m_current(first) - { - if (!m_current.HasCurrent()) - { - m_current = nullptr; - } - } - - IIterator begin() const { return m_current; } - IIterator end() const { return nullptr; } - - private: - IIterator m_current; - }; - - struct generator : implements>, iterable_base - { - explicit generator(IIterator const& first) : m_container(first) - { - } - - auto& get_container() noexcept - { - return m_container; - } - - auto& get_container() const noexcept - { - return m_container; - } - - private: - generator_container m_container; - }; - - auto v = single_threaded_vector(std::move(values)); - return make(v.First()).First(); - } -} - -TEST_CASE("GetMany") -{ - // All - { - auto v = single_threaded_vector({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC, 0xCC }; - REQUIRE(3 == v.GetMany(0, buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - REQUIRE(buffer[2] == 3); - } - { - auto v = single_threaded_vector({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC, 0xCC }; - REQUIRE(3 == v.First().GetMany(buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - REQUIRE(buffer[2] == 3); - } - - // None - { - auto v = single_threaded_vector({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC, 0xCC }; - REQUIRE(0 == v.GetMany(3, buffer)); - REQUIRE(buffer[0] == 0xCC); - REQUIRE(buffer[1] == 0xCC); - REQUIRE(buffer[2] == 0xCC); - } - { - auto v = single_threaded_vector({ 1,2,3,4 }); - auto pos = v.First(); - std::array buffer{ 0xCC, 0xCC, 0xCC }; - REQUIRE(3 == pos.GetMany(buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - REQUIRE(buffer[2] == 3); - buffer = { 0xCC, 0xCC, 0xCC }; - REQUIRE(1 == pos.GetMany(buffer)); - REQUIRE(buffer[0] == 4); - REQUIRE(buffer[1] == 0xCC); - REQUIRE(buffer[2] == 0xCC); - buffer = { 0xCC, 0xCC, 0xCC }; - REQUIRE(0 == pos.GetMany(buffer)); - REQUIRE(buffer[0] == 0xCC); - REQUIRE(buffer[1] == 0xCC); - REQUIRE(buffer[2] == 0xCC); - } - - // Less - { - auto v = single_threaded_vector({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC }; - REQUIRE(2 == v.GetMany(0, buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - } - { - auto v = single_threaded_vector({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC }; - REQUIRE(2 == v.First().GetMany(buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - } - - // More - { - auto v = single_threaded_vector({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC, 0xCC, 0xCC }; - REQUIRE(3 == v.GetMany(0, buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - REQUIRE(buffer[2] == 3); - REQUIRE(buffer[3] == 0xCC); - } - { - auto v = single_threaded_vector({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC, 0xCC, 0xCC }; - REQUIRE(3 == v.First().GetMany(buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - REQUIRE(buffer[2] == 3); - REQUIRE(buffer[3] == 0xCC); - } - - // Offset - { - auto v = single_threaded_vector({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC, 0xCC, 0xCC }; - REQUIRE(2 == v.GetMany(1, buffer)); - REQUIRE(buffer[0] == 2); - REQUIRE(buffer[1] == 3); - REQUIRE(buffer[2] == 0xCC); - REQUIRE(buffer[3] == 0xCC); - } - - // The same tests but with a non-trivially destructible type... - - // All - { - auto v = single_threaded_vector({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old", L"old" }; - REQUIRE(3 == v.GetMany(0, buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - REQUIRE(buffer[2] == L"3"); - } - { - auto v = single_threaded_vector({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old", L"old" }; - REQUIRE(3 == v.First().GetMany(buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - REQUIRE(buffer[2] == L"3"); - } - - // None - { - auto v = single_threaded_vector({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old", L"old" }; - REQUIRE(0 == v.GetMany(3, buffer)); - REQUIRE(buffer[0] == L""); - REQUIRE(buffer[1] == L""); - REQUIRE(buffer[2] == L""); - } - { - auto v = single_threaded_vector({ L"1",L"2",L"3",L"4" }); - auto pos = v.First(); - std::array buffer{ L"old", L"old", L"old" }; - REQUIRE(3 == pos.GetMany(buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - REQUIRE(buffer[2] == L"3"); - buffer = { L"old", L"old", L"old" }; - REQUIRE(1 == pos.GetMany(buffer)); - REQUIRE(buffer[0] == L"4"); - REQUIRE(buffer[1] == L""); - REQUIRE(buffer[2] == L""); - buffer = { L"old", L"old", L"old" }; - REQUIRE(0 == pos.GetMany(buffer)); - REQUIRE(buffer[0] == L""); - REQUIRE(buffer[1] == L""); - REQUIRE(buffer[2] == L""); - } - - // Less - { - auto v = single_threaded_vector({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old" }; - REQUIRE(2 == v.GetMany(0, buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - } - { - auto v = single_threaded_vector({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old" }; - REQUIRE(2 == v.First().GetMany(buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - } - - // More - { - auto v = single_threaded_vector({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old", L"old", L"old" }; - REQUIRE(3 == v.GetMany(0, buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - REQUIRE(buffer[2] == L"3"); - REQUIRE(buffer[3] == L""); - } - { - auto v = single_threaded_vector({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old", L"old", L"old" }; - REQUIRE(3 == v.First().GetMany(buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - REQUIRE(buffer[2] == L"3"); - REQUIRE(buffer[3] == L""); - } - - // Offset - { - auto v = single_threaded_vector({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old", L"old", L"old" }; - REQUIRE(2 == v.GetMany(1, buffer)); - REQUIRE(buffer[0] == L"2"); - REQUIRE(buffer[1] == L"3"); - REQUIRE(buffer[2] == L""); - REQUIRE(buffer[3] == L""); - } - - // Similar tests but with a list to ensure optimal code gen for containers that don't offer random access. - - // All - { - IIterator v = single_threaded_generator({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC, 0xCC }; - REQUIRE(3 == v.GetMany(buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - REQUIRE(buffer[2] == 3); - } - - // None - { - IIterator v = single_threaded_generator({ 1,2,3,4,5 }); - std::array buffer{ 0xCC, 0xCC, 0xCC }; - REQUIRE(3 == v.GetMany(buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - REQUIRE(buffer[2] == 3); - buffer = { 0xCC, 0xCC, 0xCC }; - REQUIRE(2 == v.GetMany(buffer)); - REQUIRE(buffer[0] == 4); - REQUIRE(buffer[1] == 5); - REQUIRE(buffer[2] == 0xCC); - buffer = { 0xCC, 0xCC, 0xCC }; - REQUIRE(0 == v.GetMany(buffer)); - REQUIRE(buffer[0] == 0xCC); - REQUIRE(buffer[1] == 0xCC); - REQUIRE(buffer[2] == 0xCC); - } - - // Less - { - IIterator v = single_threaded_generator({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC }; - REQUIRE(2 == v.GetMany(buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - } - - // More - { - IIterator v = single_threaded_generator({ 1,2,3 }); - std::array buffer{ 0xCC, 0xCC, 0xCC, 0xCC }; - REQUIRE(3 == v.GetMany(buffer)); - REQUIRE(buffer[0] == 1); - REQUIRE(buffer[1] == 2); - REQUIRE(buffer[2] == 3); - REQUIRE(buffer[3] == 0xCC); - } - - // The same tests but with a non-trivially destructible type... - - // All - { - IIterator v = single_threaded_generator({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old", L"old" }; - REQUIRE(3 == v.GetMany(buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - REQUIRE(buffer[2] == L"3"); - } - - // None - { - IIterator v = single_threaded_generator({ L"1",L"2",L"3",L"4" }); - std::array buffer{ L"old", L"old", L"old" }; - REQUIRE(3 == v.GetMany(buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - REQUIRE(buffer[2] == L"3"); - buffer = { L"old", L"old", L"old" }; - REQUIRE(1 == v.GetMany(buffer)); - REQUIRE(buffer[0] == L"4"); - REQUIRE(buffer[1] == L""); - REQUIRE(buffer[2] == L""); - buffer = { L"old", L"old", L"old" }; - REQUIRE(0 == v.GetMany(buffer)); - REQUIRE(buffer[0] == L""); - REQUIRE(buffer[1] == L""); - REQUIRE(buffer[2] == L""); - } - - // Less - { - IIterator v = single_threaded_generator({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old" }; - REQUIRE(2 == v.GetMany(buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - } - - // More - { - IIterator v = single_threaded_generator({ L"1",L"2",L"3" }); - std::array buffer{ L"old", L"old", L"old", L"old" }; - REQUIRE(3 == v.GetMany(buffer)); - REQUIRE(buffer[0] == L"1"); - REQUIRE(buffer[1] == L"2"); - REQUIRE(buffer[2] == L"3"); - REQUIRE(buffer[3] == L""); - } - - // Pair - { - auto m = single_threaded_map(); - m.Insert(1, L"1"); - m.Insert(2, L"2"); - m.Insert(3, L"3"); - m.Insert(4, L"4"); - std::array, 3> buffer; - REQUIRE(3 == m.First().GetMany(buffer)); - REQUIRE(buffer[0].Key() == 1); - REQUIRE(buffer[1].Key() == 2); - REQUIRE(buffer[2].Key() == 3); - REQUIRE(buffer[0].Value() == L"1"); - REQUIRE(buffer[1].Value() == L"2"); - REQUIRE(buffer[2].Value() == L"3"); - } -} diff --git a/test/test_win7/abi_guard.cpp b/test/test_win7/abi_guard.cpp deleted file mode 100644 index c0244a475..000000000 --- a/test/test_win7/abi_guard.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // This implemenetation uses the simplest abi_enter and abi_exit methods - // - struct Simple : implements - { - void Close() - { - } - - hstring ToString() - { - return L""; - } - - void abi_enter() - { - ++m_enter; - } - - void abi_exit() - { - ++m_exit; - } - - int m_enter{}; - int m_exit{}; - }; - - // - // This implemenetation uses the abi_enter but omits the abi_exit method - // - struct OnlyEnter : implements - { - void Close() - { - } - - hstring ToString() - { - return L""; - } - - void abi_enter() - { - ++m_enter; - } - - int m_enter{}; - }; - - // - // This implemenetation throws from the abi_enter method - // - struct Throwing : implements - { - void Close() - { - } - - hstring ToString() - { - return L""; - } - - void abi_enter() - { - throw hresult_wrong_thread(); - } - - void abi_exit() - { - ++m_exit; - } - - int m_exit{}; - }; - - // - // This implemenetation provides a nested abi_guard - // - struct NestedGuard : implements - { - void Close() - { - } - - hstring ToString() - { - return L""; - } - - int m_enter{}; - int m_exit{}; - - struct abi_guard - { - abi_guard(NestedGuard& that) : - m_that(that) - { - ++m_that.m_enter; - } - - ~abi_guard() - { - ++m_that.m_exit; - } - - private: - - NestedGuard& m_that; - }; - }; - - template - struct CountGuard - { - CountGuard(T& that) : - m_that(that) - { - ++m_that.m_enter; - } - - ~CountGuard() - { - ++m_that.m_exit; - } - - private: - - T& m_that; - }; - - // - // This implemenetation use an abi_guard type alias - // - struct GuardAlias : implements - { - void Close() - { - } - - hstring ToString() - { - return L""; - } - - int m_enter{}; - int m_exit{}; - - using abi_guard = CountGuard; - }; - - template - struct ThrowGuard - { - ThrowGuard(T&) - { - throw hresult_wrong_thread(); - } - }; - - // - // This implemenetation use an abi_guard type alias that thows - // - struct ThrowAlias : implements - { - void Close() - { - } - - hstring ToString() - { - return L""; - } - - using abi_guard = ThrowGuard; - }; -} - -TEST_CASE("abi_guard") -{ - { - com_ptr impl = make_self(); - - impl->Close(); - impl->ToString(); - REQUIRE(impl->m_enter == 0); - REQUIRE(impl->m_exit == 0); - - IClosable closable = impl.as(); - closable.Close(); - REQUIRE(impl->m_enter == 1); - REQUIRE(impl->m_exit == 1); - - IStringable stringable = impl.as(); - stringable.ToString(); - REQUIRE(impl->m_enter == 2); - REQUIRE(impl->m_exit == 2); - } - { - com_ptr impl = make_self(); - - impl->Close(); - impl->ToString(); - - REQUIRE(impl->m_enter == 0); - - IClosable closable = impl.as(); - closable.Close(); - - REQUIRE(impl->m_enter == 1); - - IStringable stringable = impl.as(); - stringable.ToString(); - - REQUIRE(impl->m_enter == 2); - } - { - com_ptr impl = make_self(); - - impl->Close(); - impl->ToString(); - - IClosable closable = impl.as(); - REQUIRE_THROWS_AS(closable.Close(), hresult_wrong_thread); - - IStringable stringable = impl.as(); - REQUIRE_THROWS_AS(stringable.ToString(), hresult_wrong_thread); - - REQUIRE(impl->m_exit == 0); - } - { - com_ptr impl = make_self(); - - impl->Close(); - impl->ToString(); - - REQUIRE(impl->m_enter == 0); - REQUIRE(impl->m_exit == 0); - - IClosable closable = impl.as(); - closable.Close(); - - REQUIRE(impl->m_enter == 1); - REQUIRE(impl->m_exit == 1); - - IStringable stringable = impl.as(); - stringable.ToString(); - - REQUIRE(impl->m_enter == 2); - REQUIRE(impl->m_exit == 2); - } - { - com_ptr impl = make_self(); - - impl->Close(); - impl->ToString(); - - REQUIRE(impl->m_enter == 0); - REQUIRE(impl->m_exit == 0); - - IClosable closable = impl.as(); - closable.Close(); - - REQUIRE(impl->m_enter == 1); - REQUIRE(impl->m_exit == 1); - - IStringable stringable = impl.as(); - stringable.ToString(); - - REQUIRE(impl->m_enter == 2); - REQUIRE(impl->m_exit == 2); - } - { - com_ptr impl = make_self(); - - impl->Close(); - impl->ToString(); - - IClosable closable = impl.as(); - REQUIRE_THROWS_AS(closable.Close(), hresult_wrong_thread); - - IStringable stringable = impl.as(); - REQUIRE_THROWS_AS(stringable.ToString(), hresult_wrong_thread); - } -} diff --git a/test/test_win7/agile_ref.cpp b/test/test_win7/agile_ref.cpp deleted file mode 100644 index e0ab43a34..000000000 --- a/test/test_win7/agile_ref.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - struct Object : implements - { - hstring ToString() - { - return L"Object"; - } - }; -} - -TEST_CASE("agile_ref") -{ - agile_ref ref = make(); - - // - // Here we're creating an agile_ref explicitly and using a traditional lambda variable capture - // to pass it to the delegate. - // - - delegate<> a = [ref] - { - IStringable object = ref.get(); - REQUIRE(object.ToString() == L"Object"); - }; - - a(); - - // - // Here's we're using the make_agile helper with generalized lambda capture to produce a - // variable local to the lambda. - // - - delegate<> b = [ref = make_agile(make())] - { - IStringable object = ref.get(); - REQUIRE(object.ToString() == L"Object"); - }; - - b(); - - // - // And it's ok to resolve a nullptr agile_ref. - // - - agile_ref empty; - IStringable object = empty.get(); - REQUIRE(object == nullptr); -} diff --git a/test/test_win7/agility.cpp b/test/test_win7/agility.cpp deleted file mode 100644 index 78fed2fda..000000000 --- a/test/test_win7/agility.cpp +++ /dev/null @@ -1,140 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.Delegates.h" - -// -// These tests confirm the COM identity and other behaviours for agile implementations. -// - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - struct TestAgile : implements - { - bool& m_destroyed; - TestAgile(bool& destroyed) : m_destroyed(destroyed) { m_destroyed = false; } - ~TestAgile() { m_destroyed = true; } - - void Close() {} - }; - - struct TestNonAgile : implements - { - void Close() {} - }; -} - -TEST_CASE("agility") -{ - using Windows::Foundation::IUnknown; - using Windows::Foundation::IInspectable; - - // Test agility - { - bool destroyed = false; - - { - IInspectable object = make(destroyed); - - // Confirm agility - object.as(); - - // Confirm legacy agility - com_ptr marshal = object.as(); - - // Confirm tear-off identity - IUnknown object_identity = object.as(); - IUnknown marshal_identity = marshal.as(); - - REQUIRE(object_identity == marshal_identity); - REQUIRE(!destroyed); - } - - // Confirm tear-off does not leak reference - REQUIRE(destroyed); - } - - // Test non-agility - { - IInspectable object = make(); - - // Does not implement IAgileObject - REQUIRE_THROWS_AS(object.as(), hresult_no_interface); - - // Does not implement IMarshal - REQUIRE_THROWS_AS(object.as(), hresult_no_interface); - } - - // Test IMarshal tearoff lifetime - { - bool destroyed = false; - - IInspectable object = make(destroyed); - com_ptr marshal = object.as(); - object = nullptr; - REQUIRE(!destroyed); - - // Confirm agility (back to object) - marshal.as(); - - // QI on tearoff itself - com_ptr marshal2 = marshal.as(); - REQUIRE(marshal == marshal2); - marshal2 = nullptr; - - // Confirm tear-off does not leak reference - REQUIRE(!destroyed); - marshal = nullptr; - REQUIRE(destroyed); - } - - // Test agile delegate - { - IUnknown object = test_component::Delegates::AgileDelegate([] {}); - com_ptr marshal = object.as(); - object = nullptr; - - // Confirm agility (back to object) - marshal.as(); - - // QI on tearoff itself - com_ptr marshal2 = marshal.as(); - REQUIRE(marshal == marshal2); - } - - // Test agile weak reference - { - bool destroyed = false; - IClosable object = make(destroyed); - com_ptr source = object.as(); - - // Clear object but source keeps object alive - object = nullptr; - source.as(); - - com_ptr ref; - check_hresult(source->GetWeakReference(ref.put())); - - // Drop the source object - REQUIRE(S_OK == ref->Resolve(guid_of(), put_abi(object))); - REQUIRE(object != nullptr); - source = nullptr; - REQUIRE(!destroyed); - object = nullptr; - REQUIRE(destroyed); - REQUIRE(S_OK == ref->Resolve(guid_of(), put_abi(object))); - REQUIRE(object == nullptr); - - // Marshaling support on weak ref - com_ptr marshal = ref.as(); - ref = nullptr; - - // Confirm agility (back to object): - marshal.as(); - - // QI on tearoff itself - com_ptr marshal2 = marshal.as(); - REQUIRE(marshal == marshal2); - } -} diff --git a/test/test_win7/async_auto_cancel.cpp b/test/test_win7/async_auto_cancel.cpp deleted file mode 100644 index 45ff30fcf..000000000 --- a/test/test_win7/async_auto_cancel.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that the coroutine is automatically canceled when reaching a suspension point. - // - - IAsyncAction Action(HANDLE event) - { - co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); - REQUIRE(false); - } - - IAsyncActionWithProgress ActionWithProgress(HANDLE event) - { - co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); - REQUIRE(false); - } - - IAsyncOperation Operation(HANDLE event) - { - co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); - REQUIRE(false); - co_return 1; - } - - IAsyncOperationWithProgress OperationWithProgress(HANDLE event) - { - co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); - REQUIRE(false); - co_return 1; - } - - template - void Check(F make) - { - handle start{ CreateEvent(nullptr, true, false, nullptr) }; - handle completed{ CreateEvent(nullptr, true, false, nullptr) }; - auto async = make(start.get()); - REQUIRE(async.Status() == AsyncStatus::Started); - - async.Completed([&](auto&& sender, AsyncStatus status) - { - REQUIRE(async == sender); - REQUIRE(status == AsyncStatus::Canceled); - SetEvent(completed.get()); - }); - - async.Cancel(); - SetEvent(start.get()); - REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0); - - REQUIRE(async.Status() == AsyncStatus::Canceled); - REQUIRE(async.ErrorCode() == HRESULT_FROM_WIN32(ERROR_CANCELLED)); - REQUIRE_THROWS_AS(async.GetResults(), hresult_canceled); - } -} - -TEST_CASE("async_auto_cancel") -{ - Check(Action); - Check(ActionWithProgress); - Check(Operation); - Check(OperationWithProgress); -} diff --git a/test/test_win7/async_cancel_callback.cpp b/test/test_win7/async_cancel_callback.cpp deleted file mode 100644 index 0ab5b6bb1..000000000 --- a/test/test_win7/async_cancel_callback.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that the cancellation callback is invoked. - // - - IAsyncAction Action(HANDLE event, bool& canceled) - { - auto cancel = co_await get_cancellation_token(); - - cancel.callback([&] - { - REQUIRE(!canceled); - canceled = true; - }); - - co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); - REQUIRE(false); - } - - IAsyncActionWithProgress ActionWithProgress(HANDLE event, bool& canceled) - { - auto cancel = co_await get_cancellation_token(); - - cancel.callback([&] - { - REQUIRE(!canceled); - canceled = true; - }); - - co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); - REQUIRE(false); - } - - IAsyncOperation Operation(HANDLE event, bool& canceled) - { - auto cancel = co_await get_cancellation_token(); - - cancel.callback([&] - { - REQUIRE(!canceled); - canceled = true; - }); - - co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); - REQUIRE(false); - co_return 1; - } - - IAsyncOperationWithProgress OperationWithProgress(HANDLE event, bool& canceled) - { - auto cancel = co_await get_cancellation_token(); - - cancel.callback([&] - { - REQUIRE(!canceled); - canceled = true; - }); - - co_await resume_on_signal(event); - co_await std::experimental::suspend_never(); - REQUIRE(false); - co_return 1; - } - - template - void Check(F make) - { - handle event{ CreateEvent(nullptr, true, false, nullptr) }; - bool canceled = false; - auto async = make(event.get(), canceled); - async.Cancel(); - REQUIRE(canceled); - SetEvent(event.get()); - REQUIRE_THROWS_AS(async.GetResults(), hresult_canceled); - } -} - -TEST_CASE("async_cancel_callback") -{ - Check(Action); - Check(ActionWithProgress); - Check(Operation); - Check(OperationWithProgress); -} diff --git a/test/test_win7/async_check_cancel.cpp b/test/test_win7/async_check_cancel.cpp deleted file mode 100644 index 38d21f48b..000000000 --- a/test/test_win7/async_check_cancel.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that manual cancellation checks work. - // - - IAsyncAction Action(HANDLE event, bool& canceled) - { - co_await resume_on_signal(event); - auto cancel = co_await get_cancellation_token(); - - if (cancel()) - { - REQUIRE(!canceled); - canceled = true; - } - - co_await std::experimental::suspend_never(); - REQUIRE(false); - } - - IAsyncActionWithProgress ActionWithProgress(HANDLE event, bool& canceled) - { - co_await resume_on_signal(event); - auto cancel = co_await get_cancellation_token(); - - if (cancel()) - { - REQUIRE(!canceled); - canceled = true; - } - - co_await std::experimental::suspend_never(); - REQUIRE(false); - } - - IAsyncOperation Operation(HANDLE event, bool& canceled) - { - co_await resume_on_signal(event); - auto cancel = co_await get_cancellation_token(); - - if (cancel()) - { - REQUIRE(!canceled); - canceled = true; - } - - co_await std::experimental::suspend_never(); - REQUIRE(false); - co_return 1; - } - - IAsyncOperationWithProgress OperationWithProgress(HANDLE event, bool& canceled) - { - co_await resume_on_signal(event); - auto cancel = co_await get_cancellation_token(); - - if (cancel()) - { - REQUIRE(!canceled); - canceled = true; - } - - co_await std::experimental::suspend_never(); - REQUIRE(false); - co_return 1; - } - - template - void Check(F make) - { - handle start{ CreateEvent(nullptr, true, false, nullptr) }; - handle completed{ CreateEvent(nullptr, true, false, nullptr) }; - bool canceled = false; - auto async = make(start.get(), canceled); - REQUIRE(async.Status() == AsyncStatus::Started); - - async.Completed([&](auto&& sender, AsyncStatus status) - { - REQUIRE(async == sender); - REQUIRE(status == AsyncStatus::Canceled); - REQUIRE(canceled); - SetEvent(completed.get()); - }); - - async.Cancel(); - SetEvent(start.get()); - REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0); - - REQUIRE(async.Status() == AsyncStatus::Canceled); - REQUIRE(async.ErrorCode() == HRESULT_FROM_WIN32(ERROR_CANCELLED)); - REQUIRE_THROWS_AS(async.GetResults(), hresult_canceled); - } -} - -TEST_CASE("async_check_cancel") -{ - Check(Action); - Check(ActionWithProgress); - Check(Operation); - Check(OperationWithProgress); -} diff --git a/test/test_win7/async_local.cpp b/test/test_win7/async_local.cpp deleted file mode 100644 index fa96dabb5..000000000 --- a/test/test_win7/async_local.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that coroutine locals are destroyed prior to notifying waiters. - // - - struct Local - { - bool& destroyed; - - ~Local() - { - REQUIRE(!destroyed); - destroyed = true; - } - }; - - IAsyncAction Action(HANDLE event, bool& destroyed) - { - co_await resume_on_signal(event); - Local local{ destroyed }; - } - - IAsyncActionWithProgress ActionWithProgress(HANDLE event, bool& destroyed) - { - co_await resume_on_signal(event); - Local local{ destroyed }; - } - - IAsyncOperation Operation(HANDLE event, bool& destroyed) - { - co_await resume_on_signal(event); - Local local{ destroyed }; - co_return 1; - } - - IAsyncOperationWithProgress OperationWithProgress(HANDLE event, bool& destroyed) - { - co_await resume_on_signal(event); - Local local{ destroyed }; - co_return 1; - } - - template - void Check(F make) - { - handle start{ CreateEvent(nullptr, true, false, nullptr) }; - handle completed{ CreateEvent(nullptr, true, false, nullptr) }; - bool destroyed = false; - auto async = make(start.get(), destroyed); - - async.Completed([&](auto&&...) - { - REQUIRE(destroyed); - SetEvent(completed.get()); - }); - - SetEvent(start.get()); - REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0); - } -} - -TEST_CASE("async_local") -{ - Check(Action); - Check(ActionWithProgress); - Check(Operation); - Check(OperationWithProgress); -} diff --git a/test/test_win7/async_no_suspend.cpp b/test/test_win7/async_no_suspend.cpp deleted file mode 100644 index 6888d0b98..000000000 --- a/test/test_win7/async_no_suspend.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that coroutines lacking suspension points work. - // - - IAsyncAction Action() - { - co_return; - } - - IAsyncActionWithProgress ActionWithProgress() - { - co_return; - } - - IAsyncOperation Operation() - { - co_return 1; - } - - IAsyncOperationWithProgress OperationWithProgress() - { - co_return 1; - } - - IAsyncAction Await() - { - co_await Action(); - co_await ActionWithProgress(); - co_await Operation(); - co_await OperationWithProgress(); - } - - template - void Check(T const& async) - { - REQUIRE(async.Status() == AsyncStatus::Completed); - REQUIRE(async.ErrorCode() == 0); - REQUIRE(async.Id() == 1); - - // Should not throw in the Completed state. - async.GetResults(); - - bool completed = false; - - async.Completed([&](auto&& sender, AsyncStatus status) - { - completed = true; - REQUIRE(async == sender); - REQUIRE(status == AsyncStatus::Completed); - }); - - REQUIRE(completed); - - // May only assign Completed handler once. - REQUIRE_THROWS_AS(async.Completed([&](auto && ...) {}), hresult_illegal_delegate_assignment); - - // Close does nothing. - async.Close(); - - // Harmless but too late to cancel. - async.Cancel(); - REQUIRE(async.Status() == AsyncStatus::Completed); - } -} - -TEST_CASE("async_no_suspend") -{ - Action().get(); - ActionWithProgress().get(); - Operation().get(); - OperationWithProgress().get(); - Await().get(); - - Check(Action()); - Check(ActionWithProgress()); - Check(Operation()); - Check(OperationWithProgress()); -} diff --git a/test/test_win7/async_progress.cpp b/test/test_win7/async_progress.cpp deleted file mode 100644 index 0a2790f50..000000000 --- a/test/test_win7/async_progress.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that progress reporting works. - // - - IAsyncActionWithProgress Action(HANDLE event) - { - co_await resume_on_signal(event); - auto progress = co_await get_progress_token(); - progress(123); - } - - IAsyncOperationWithProgress Operation(HANDLE event) - { - co_await resume_on_signal(event); - auto progress = co_await get_progress_token(); - progress(123); - co_return 1; - } - - template - IAsyncAction Check(F make) - { - // Event not set to allow Progress handler to be wired up. - handle start{ CreateEvent(nullptr, true, false, nullptr) }; - - auto async = make(start.get()); - bool progress = false; - - async.Progress([&](auto&& sender, int value) - { - progress = true; - REQUIRE(async == sender); - REQUIRE(value == 123); - }); - - SetEvent(start.get()); - co_await async; - - REQUIRE(progress); - REQUIRE(async.Status() == AsyncStatus::Completed); - REQUIRE(async.ErrorCode() == S_OK); - } - - template - IAsyncAction TooLate(F make) - { - // Event initially set so that coroutine does not suspend. - handle start{ CreateEvent(nullptr, true, true, nullptr) }; - - auto async = make(start.get()); - REQUIRE(async.Status() == AsyncStatus::Completed); - - bool progress = false; - - async.Progress([&](auto&&...) - { - REQUIRE(false); - }); - - co_await async; - - REQUIRE(!progress); - REQUIRE(async.Status() == AsyncStatus::Completed); - REQUIRE(async.ErrorCode() == S_OK); - } -} - -TEST_CASE("async_progress") -{ - Check(Action); - Check(Operation); - - TooLate(Action); - TooLate(Operation); -} diff --git a/test/test_win7/async_result.cpp b/test/test_win7/async_result.cpp deleted file mode 100644 index 9c1accccb..000000000 --- a/test/test_win7/async_result.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that result values are propagated properly. - // - - IAsyncOperation Operation(HANDLE event) - { - co_await resume_on_signal(event); - co_return 123; - } - - IAsyncOperationWithProgress OperationWithProgress(HANDLE event) - { - co_await resume_on_signal(event); - co_return 123; - } - - IAsyncAction Await() - { - // Manual reset so that all waiters will resume and initially set so they won't block. - handle event{ CreateEvent(nullptr, true, true, nullptr) }; - - int a = co_await Operation(event.get()); - int b = co_await OperationWithProgress(event.get()); - - REQUIRE(a == 123); - REQUIRE(b == 123); - } - - template - void Check(F make) - { - handle start{ CreateEvent(nullptr, true, false, nullptr) }; - handle completed{ CreateEvent(nullptr, true, false, nullptr) }; - auto async = make(start.get()); - REQUIRE(async.Status() == AsyncStatus::Started); - if constexpr (has_async_progress) - { - // You're allowed to peek at partial results of IAsyncXxxWithProgress. - REQUIRE_NOTHROW(async.GetResults()); - } - else - { - REQUIRE_THROWS_AS(async.GetResults(), hresult_illegal_method_call); - } - - async.Completed([&](auto&& sender, AsyncStatus status) - { - REQUIRE(async == sender); - REQUIRE(status == AsyncStatus::Completed); - SetEvent(completed.get()); - }); - - // Still in Started state waiting for signal. - Sleep(100); - REQUIRE(WaitForSingleObject(completed.get(), 0) == WAIT_TIMEOUT); - REQUIRE(async.Status() == AsyncStatus::Started); - - // Signal async to run. - SetEvent(start.get()); - - // Wait for async to complete. - REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0); - - REQUIRE(async.Status() == AsyncStatus::Completed); - REQUIRE(async.ErrorCode() == S_OK); - REQUIRE(async.GetResults() == 123); - } -} - -TEST_CASE("async_result") -{ - handle start{ CreateEvent(nullptr, true, true, nullptr) }; - REQUIRE(123 == Operation(start.get()).get()); - REQUIRE(123 == OperationWithProgress(start.get()).get()); - Await().get(); - - Check(Operation); - Check(OperationWithProgress); -} diff --git a/test/test_win7/async_return.cpp b/test/test_win7/async_return.cpp deleted file mode 100644 index 23b1c1eec..000000000 --- a/test/test_win7/async_return.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks that return values support both rvalue and lvalue. - // - - IAsyncOperation Operation(bool rvalue) - { - if (rvalue) - { - hstring value = L"rvalue"; - co_return std::move(value); - } - else - { - hstring value = L"lvalue"; - co_return value; - } - } - - IAsyncOperationWithProgress OperationWithProgress(bool rvalue) - { - if (rvalue) - { - hstring value = L"rvalue"; - co_return std::move(value); - } - else - { - hstring value = L"lvalue"; - co_return value; - } - } - - template - void Check(F make) - { - REQUIRE(make(true).get() == L"rvalue"); - REQUIRE(make(false).get() == L"lvalue"); - } -} - -TEST_CASE("async_return") -{ - Check(Operation); - Check(OperationWithProgress); -} diff --git a/test/test_win7/async_suspend.cpp b/test/test_win7/async_suspend.cpp deleted file mode 100644 index f7beee21d..000000000 --- a/test/test_win7/async_suspend.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // - // Checks basic suspension behavior. - // - - IAsyncAction Action(HANDLE event) - { - co_await resume_on_signal(event); - } - - IAsyncActionWithProgress ActionWithProgress(HANDLE event) - { - co_await resume_on_signal(event); - } - - IAsyncOperation Operation(HANDLE event) - { - co_await resume_on_signal(event); - co_return 1; - } - - IAsyncOperationWithProgress OperationWithProgress(HANDLE event) - { - co_await resume_on_signal(event); - co_return 1; - } - - IAsyncAction Await() - { - // Manual reset so that all waiters will resume and initially set so they won't block. - handle event{ CreateEvent(nullptr, true, true, nullptr) }; - - co_await Action(event.get()); - co_await ActionWithProgress(event.get()); - co_await Operation(event.get()); - co_await OperationWithProgress(event.get()); - } - - template - void Check(F make) - { - handle start{ CreateEvent(nullptr, true, false, nullptr) }; - handle completed{ CreateEvent(nullptr, true, false, nullptr) }; - auto async = make(start.get()); - REQUIRE(async.Status() == AsyncStatus::Started); - if constexpr (has_async_progress) - { - // You're allowed to peek at partial results of IAsyncXxxWithProgress. - REQUIRE_NOTHROW(async.GetResults()); - } - else - { - REQUIRE_THROWS_AS(async.GetResults(), hresult_illegal_method_call); - } - - async.Completed([&](auto&& sender, AsyncStatus status) - { - REQUIRE(async == sender); - REQUIRE(status == AsyncStatus::Completed); - SetEvent(completed.get()); - }); - - // Still in Started state waiting for signal. - Sleep(100); - REQUIRE(WaitForSingleObject(completed.get(), 0) == WAIT_TIMEOUT); - REQUIRE(async.Status() == AsyncStatus::Started); - - // Signal async to run. - SetEvent(start.get()); - - // Wait for async to complete. - REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0); - - REQUIRE(async.Status() == AsyncStatus::Completed); - REQUIRE(async.ErrorCode() == S_OK); - } -} - -TEST_CASE("async_suspend") -{ - handle start{ CreateEvent(nullptr, true, true, nullptr) }; - Action(start.get()).get(); - ActionWithProgress(start.get()).get(); - Operation(start.get()).get(); - OperationWithProgress(start.get()).get(); - Await().get(); - - Check(Action); - Check(ActionWithProgress); - Check(Operation); - Check(OperationWithProgress); -} diff --git a/test/test_win7/async_throw.cpp b/test/test_win7/async_throw.cpp deleted file mode 100644 index 2d50acfd9..000000000 --- a/test/test_win7/async_throw.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; -using namespace std::chrono_literals; - -namespace -{ - // - // Checks that exceptions are correctly captured and propagated. - // - - IAsyncAction Action() - { - co_await 10ms; - throw hresult_invalid_argument(L"Async"); - } - - IAsyncActionWithProgress ActionWithProgress() - { - co_await 10ms; - throw hresult_invalid_argument(L"Async"); - } - - IAsyncOperation Operation() - { - co_await 10ms; - throw hresult_invalid_argument(L"Async"); - co_return 1; - } - - IAsyncOperationWithProgress OperationWithProgress() - { - co_await 10ms; - throw hresult_invalid_argument(L"Async"); - co_return 1; - } - - template - void Check(F make) - { - try - { - make().get(); - REQUIRE(false); - } - catch (hresult_invalid_argument const& e) - { - REQUIRE(e.message() == L"Async"); - } - - handle completed{ CreateEvent(nullptr, true, false, nullptr) }; - auto async = make(); - - async.Completed([&](auto&& sender, AsyncStatus status) - { - REQUIRE(async == sender); - REQUIRE(status == AsyncStatus::Error); - SetEvent(completed.get()); - }); - - REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0); - REQUIRE(async.Status() == AsyncStatus::Error); - - hresult_error e(async.ErrorCode(), take_ownership_from_abi); - REQUIRE(e.message() == L"Async"); - - try - { - async.GetResults(); - REQUIRE(false); - } - catch (hresult_invalid_argument const& e) - { - REQUIRE(e.message() == L"Async"); - } - } -} - -TEST_CASE("async_throw") -{ - Check(Action); - Check(ActionWithProgress); - Check(Operation); - Check(OperationWithProgress); -} diff --git a/test/test_win7/async_wait_for.cpp b/test/test_win7/async_wait_for.cpp deleted file mode 100644 index 2173a5e86..000000000 --- a/test/test_win7/async_wait_for.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "pch.h" - -using namespace std::literals; -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - IAsyncAction Action(TimeSpan delay, AsyncStatus result) - { - co_await resume_after(delay); - - if (result == AsyncStatus::Error) - { - throw hresult_invalid_argument(); - } - - if (result == AsyncStatus::Canceled) - { - throw hresult_canceled(); - } - } - - IAsyncActionWithProgress ActionWithProgress(TimeSpan delay, AsyncStatus result) - { - co_await resume_after(delay); - - if (result == AsyncStatus::Error) - { - throw hresult_invalid_argument(); - } - - if (result == AsyncStatus::Canceled) - { - throw hresult_canceled(); - } - } - - IAsyncOperation Operation(TimeSpan delay, AsyncStatus result) - { - co_await resume_after(delay); - - if (result == AsyncStatus::Error) - { - throw hresult_invalid_argument(); - } - - if (result == AsyncStatus::Canceled) - { - throw hresult_canceled(); - } - - co_return 1; - } - - IAsyncOperationWithProgress OperationWithProgress(TimeSpan delay, AsyncStatus result) - { - co_await resume_after(delay); - - if (result == AsyncStatus::Error) - { - throw hresult_invalid_argument(); - } - - if (result == AsyncStatus::Canceled) - { - throw hresult_canceled(); - } - - co_return 1; - } - - template - void check(T const& no_suspend_ok, T const& no_suspend_fail, T const& delay_ok, T const& delay_fail, T const& no_suspend_cancel, T const& delay_cancel, T const& long_delay) - { - REQUIRE(no_suspend_ok.wait_for(0s) == AsyncStatus::Completed); - no_suspend_ok.get(); - REQUIRE_THROWS_AS(no_suspend_ok.wait_for(0s), hresult_illegal_delegate_assignment); - - REQUIRE(no_suspend_fail.wait_for(0s) == AsyncStatus::Error); - REQUIRE_THROWS_AS(no_suspend_fail.get(), hresult_invalid_argument); - - REQUIRE(delay_ok.wait_for(1s) == AsyncStatus::Completed); - delay_ok.get(); - - REQUIRE(delay_fail.wait_for(1s) == AsyncStatus::Error); - REQUIRE_THROWS_AS(delay_fail.get(), hresult_invalid_argument); - - REQUIRE(no_suspend_cancel.wait_for(0s) == AsyncStatus::Canceled); - REQUIRE_THROWS_AS(no_suspend_cancel.get(), hresult_canceled); - - REQUIRE(delay_cancel.wait_for(1s) == AsyncStatus::Canceled); - REQUIRE_THROWS_AS(delay_cancel.get(), hresult_canceled); - - REQUIRE(long_delay.wait_for(100ms) == AsyncStatus::Started); - } -} - -TEST_CASE("async_wait_for") -{ - check( - Action(0s, AsyncStatus::Completed), - Action(0s, AsyncStatus::Error), - Action(100ms, AsyncStatus::Completed), - Action(100ms, AsyncStatus::Error), - Action(0s, AsyncStatus::Canceled), - Action(100ms, AsyncStatus::Canceled), - Action(1h, AsyncStatus::Completed)); - - check( - ActionWithProgress(0s, AsyncStatus::Completed), - ActionWithProgress(0s, AsyncStatus::Error), - ActionWithProgress(100ms, AsyncStatus::Completed), - ActionWithProgress(100ms, AsyncStatus::Error), - ActionWithProgress(0s, AsyncStatus::Canceled), - ActionWithProgress(100ms, AsyncStatus::Canceled), - ActionWithProgress(1h, AsyncStatus::Completed)); - - check( - Operation(0s, AsyncStatus::Completed), - Operation(0s, AsyncStatus::Error), - Operation(100ms, AsyncStatus::Completed), - Operation(100ms, AsyncStatus::Error), - Operation(0s, AsyncStatus::Canceled), - Operation(100ms, AsyncStatus::Canceled), - Operation(1h, AsyncStatus::Completed)); - - check( - OperationWithProgress(0s, AsyncStatus::Completed), - OperationWithProgress(0s, AsyncStatus::Error), - OperationWithProgress(100ms, AsyncStatus::Completed), - OperationWithProgress(100ms, AsyncStatus::Error), - OperationWithProgress(0s, AsyncStatus::Canceled), - OperationWithProgress(100ms, AsyncStatus::Canceled), - OperationWithProgress(1h, AsyncStatus::Completed)); -} diff --git a/test/test_win7/capture.cpp b/test/test_win7/capture.cpp deleted file mode 100644 index 8c75681b4..000000000 --- a/test/test_win7/capture.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -struct __declspec(uuid("5fb96f8d-409c-42a9-99a7-8a95c1459dbd")) ICapture : ::IUnknown -{ - virtual int32_t __stdcall GetValue() noexcept = 0; - virtual int32_t __stdcall CreateMemberCapture(int32_t value, GUID const& iid, void** object) noexcept = 0; -}; - -struct Capture : implements -{ - int32_t const m_value{}; - - Capture(int32_t value) : - m_value{ value } - { - } - - hstring ToString() - { - return hstring{ std::to_wstring(m_value) }; - } - - int32_t __stdcall GetValue() noexcept override - { - return m_value; - } - - int32_t __stdcall CreateMemberCapture(int32_t value, GUID const& iid, void** object) noexcept override - { - auto capture = make(value); - return capture->QueryInterface(iid, object); - } -}; - -HRESULT __stdcall CreateNonMemberCapture(int value, GUID const& iid, void** object) noexcept -{ - auto capture = make(value); - return capture->QueryInterface(iid, object); -} - -TEST_CASE("capture") -{ - com_ptr a = capture(CreateNonMemberCapture, 10); - REQUIRE(a->GetValue() == 10); - a = nullptr; - a.capture(CreateNonMemberCapture, 20); - REQUIRE(a->GetValue() == 20); - - com_ptr b = capture(a, &ICapture::CreateMemberCapture, 30); - REQUIRE(b->GetValue() == 30); - b = nullptr; - b.capture(a, &ICapture::CreateMemberCapture, 40); - REQUIRE(b->GetValue() == 40); - - IStringable c = capture(CreateNonMemberCapture, 50); - REQUIRE(c.ToString() == L"50"); - c = capture(a, &ICapture::CreateMemberCapture, 60); - REQUIRE(c.ToString() == L"60"); - - com_ptr d; - - REQUIRE_THROWS_AS(capture(CreateNonMemberCapture, 0), hresult_no_interface); - REQUIRE_THROWS_AS(capture(CreateNonMemberCapture, 0), hresult_no_interface); - REQUIRE_THROWS_AS(d.capture(CreateNonMemberCapture, 0), hresult_no_interface); - REQUIRE_THROWS_AS(capture(a, &ICapture::CreateMemberCapture, 0), hresult_no_interface); - REQUIRE_THROWS_AS(capture(a, &ICapture::CreateMemberCapture, 0), hresult_no_interface); - REQUIRE_THROWS_AS(d.capture(a, &ICapture::CreateMemberCapture, 0), hresult_no_interface); -} diff --git a/test/test_win7/cmd_reader.cpp b/test/test_win7/cmd_reader.cpp deleted file mode 100644 index 731922fd8..000000000 --- a/test/test_win7/cmd_reader.cpp +++ /dev/null @@ -1,154 +0,0 @@ -#include "pch.h" -#include "cmd_reader.h" -#include - -using namespace cppwinrt; - -class response_file -{ - const char* resp_file_name = "respfile.txt"; - void write_response_file(const char* input) - { - std::ofstream resp_file(resp_file_name); - if (!resp_file.is_open()) - FAIL("Response file could not be created"); - resp_file << input; - resp_file.close(); - } - - void remove_response_file() - { - std::remove(resp_file_name); - } - -public: - response_file(const char* input) - { - write_response_file(input); - } - - template - reader create_reader(size_t const argc, const char* argv[], const option(&options)[numOptions]) - { - return reader{ argc, argv, options }; - } - - ~response_file() - { - remove_response_file(); - } -}; - -TEST_CASE("cmd_reader") -{ - static constexpr option options[] - { - { "input", 1 }, - { "reference", 0 }, - { "output", 0, 1 }, - { "component", 0, 1 }, - { "filter", 0 }, - { "name", 0, 1 }, - { "verbose", 0, 0 }, - }; - - // input and output - { - const char* argv[] = { "progname", "-in", "example_file.in", "-out", "example_file.out" }; - const size_t argc = 5; - reader args{ argc, argv, options }; - - REQUIRE(args.exists("input")); - REQUIRE(args.value("input") == "example_file.in"); - REQUIRE_FALSE(args.exists("reference")); - REQUIRE(args.exists("output")); - REQUIRE(args.value("output") == "example_file.out"); - REQUIRE_FALSE(args.exists("filter")); - REQUIRE_FALSE(args.exists("name")); - REQUIRE_FALSE(args.exists("verbose")); - } - - // response file #1: filename no quotes - { - const char* argv[] = { "progname", "@respfile.txt" }; - const size_t argc = _countof(argv); - - response_file rf{ R"(-in example_file.in -out example_file.out)" }; - reader args = rf.create_reader(argc, argv, options); - - REQUIRE(args.exists("input")); - REQUIRE(args.value("input") == "example_file.in"); - REQUIRE_FALSE(args.exists("reference")); - REQUIRE(args.exists("output")); - REQUIRE(args.value("output") == "example_file.out"); - REQUIRE_FALSE(args.exists("filter")); - REQUIRE_FALSE(args.exists("name")); - REQUIRE_FALSE(args.exists("verbose")); - } - - // response file #2: filename with quotes - { - const char* argv[] = { "progname", "@respfile.txt" }; - const size_t argc = _countof(argv); - - response_file rf{ R"(-in "example file.in" -out "example file.out")" }; - reader args = rf.create_reader(argc, argv, options); - - REQUIRE(args.exists("input")); - REQUIRE(args.value("input") == "example file.in"); - REQUIRE_FALSE(args.exists("reference")); - REQUIRE(args.exists("output")); - REQUIRE(args.value("output") == "example file.out"); - REQUIRE_FALSE(args.exists("filter")); - REQUIRE_FALSE(args.exists("name")); - REQUIRE_FALSE(args.exists("verbose")); - } - - // response file #3: filename with quote within name - { - const char* argv[] = { "progname", "@respfile.txt" }; - const size_t argc = _countof(argv); - - response_file rf{ R"(-in example\"file.in -out example\"file.out)" }; - reader args = rf.create_reader(argc, argv, options); - - REQUIRE(args.exists("input")); - REQUIRE(args.value("input") == R"(example"file.in)"); - REQUIRE_FALSE(args.exists("reference")); - REQUIRE(args.exists("output")); - REQUIRE(args.value("output") == R"(example"file.out)"); - REQUIRE_FALSE(args.exists("filter")); - REQUIRE_FALSE(args.exists("name")); - REQUIRE_FALSE(args.exists("verbose")); - } - - // response file #4: really really long path - { - const char* argv[] = { "progname", "@respfile.txt" }; - const size_t argc = _countof(argv); - std::string file_name_in(R"(C:\)"); - std::string file_name_out(R"(C:\)"); - std::string input_str("-in "); - - for (int i = 0; i < 500; i++) { - file_name_in.append(R"(dirname\)"); - file_name_out.append(R"(dirname\)"); - } - - file_name_in.append("example_file.in"); - file_name_out.append("example_file.out"); - input_str.append(file_name_in).append(" -out ").append(file_name_out); - - response_file rf{ input_str.data() }; - reader args = rf.create_reader(argc, argv, options); - - REQUIRE(args.exists("input")); - REQUIRE(args.value("input") == file_name_in); - REQUIRE_FALSE(args.exists("reference")); - REQUIRE(args.exists("output")); - REQUIRE(args.value("output") == file_name_out); - REQUIRE_FALSE(args.exists("filter")); - REQUIRE_FALSE(args.exists("name")); - REQUIRE_FALSE(args.exists("verbose")); - } -} diff --git a/test/test_win7/coro_foundation.cpp b/test/test_win7/coro_foundation.cpp deleted file mode 100644 index c2705982a..000000000 --- a/test/test_win7/coro_foundation.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Intentionally not using pch... -#include "catch.hpp" - -// Only need winrt/Windows.Foundation.h for IAsyncXxx coroutine support -#include "winrt/Windows.Foundation.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - IAsyncOperation Async() - { - co_return L"hello"; - } -} - -TEST_CASE("coro_foundation") -{ - REQUIRE(Async().get() == L"hello"); -} diff --git a/test/test_win7/coro_threadpool.cpp b/test/test_win7/coro_threadpool.cpp deleted file mode 100644 index 4c31f8a03..000000000 --- a/test/test_win7/coro_threadpool.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Intentionally not using pch... -#include "catch.hpp" - -// Only need winrt/base.h for coroutine thread pool support. -#include "winrt/base.h" - -using namespace winrt; - -namespace -{ - fire_and_forget Async() - { - co_await resume_background(); - } -} - -TEST_CASE("coro_base") -{ - Async(); -} diff --git a/test/test_win7/custom_error.cpp b/test/test_win7/custom_error.cpp deleted file mode 100644 index b9850845a..000000000 --- a/test/test_win7/custom_error.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - // Some custom exception type unknown to C++/WinRT - struct CustomError - { - }; - - struct Sample : implements - { - hstring ToString() - { - // Throw custom exception inside C++/WinRT projection - throw CustomError(); - } - }; - - // Global handler to translate custom exception - int32_t __stdcall handler(void* address) noexcept - { - REQUIRE(address); - - try - { - throw; - } - catch (CustomError) - { - return 0x80000018; // E_ILLEGAL_DELEGATE_ASSIGNMENT - } - - REQUIRE(false); - return 0; - } -} - -TEST_CASE("custom_error") -{ - // Set up global handler - REQUIRE(!winrt_to_hresult_handler); - winrt_to_hresult_handler = handler; - - // Validate that handler translated exception - REQUIRE_THROWS_AS(make().ToString(), hresult_illegal_delegate_assignment); - - // Remove global handler - winrt_to_hresult_handler = nullptr; -} diff --git a/test/test_win7/delegate.cpp b/test/test_win7/delegate.cpp deleted file mode 100644 index bade55060..000000000 --- a/test/test_win7/delegate.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "pch.h" - -using namespace winrt; - -TEST_CASE("delegate") -{ - // <> - { - bool invoked = false; - delegate<> d = [&] {invoked = true; }; - d(); - REQUIRE(invoked); - } - - // - { - int result = 0; - delegate d = [&](int a) {result = a; }; - d(123); - REQUIRE(result == 123); - } - - // - { - int result = 0; - delegate d = [&](int a, int b) {result = a + b; }; - d(4,5); - REQUIRE(result == 9); - } - - // void() - { - bool invoked = false; - delegate d = [&] {invoked = true; }; - d(); - REQUIRE(invoked); - } - - // void(int) - { - int result = 0; - delegate d = [&](int a) {result = a; }; - d(123); - REQUIRE(result == 123); - } - - // void(int,int) - { - int result = 0; - delegate d = [&](int a, int b) {result = a + b; }; - d(4, 5); - REQUIRE(result == 9); - } - - // int() - { - delegate d = [] { return 123; }; - REQUIRE(d() == 123); - } - - // int(int) - { - delegate d = [](int a) {return a; }; - REQUIRE(d(123) == 123); - } - - // int(int,int) - { - delegate d = [](int a, int b) {return a + b; }; - REQUIRE(d(4, 5) == 9); - } -} diff --git a/test/test_win7/delegates.cpp b/test/test_win7/delegates.cpp deleted file mode 100644 index af2eb6daf..000000000 --- a/test/test_win7/delegates.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.Delegates.h" - -using namespace winrt; -using namespace test_component::Delegates; - -TEST_CASE("delegates") -{ - { - bool run{}; - AgileDelegate d = [&] {run = true; }; - REQUIRE(!run); - d(); - REQUIRE(run); - } - { - hstring value; - InDelegate d = [&](hstring const& in) - { - value = in; - }; - REQUIRE(value.empty()); - d(L"Test"); - REQUIRE(value == L"Test"); - } - { - ReturnStringDelegate d = [] {return L"Test"; }; - REQUIRE(d() == L"Test"); - } - { - ReturnInt32Delegate d = [] {return 123; }; - REQUIRE(d() == 123); - } - { - OutStringDelegate d = [](hstring& value) - { - value = L"Test"; - }; - hstring value; - d(value); - REQUIRE(value == L"Test"); - } - { - OutStringDelegate d = [](hstring&) - { - }; - hstring value = L"old"; - d(value); - REQUIRE(value == L""); - } - { - OutInt32Delegate d = [](int32_t & value) - { - value = 123; - }; - int32_t value{ 0xCC }; - d(value); - REQUIRE(value == 123); - } - { - OutInt32Delegate d = [](int32_t&) - { - }; - int32_t value{ 123 }; - d(value); - REQUIRE(value == 123); - } - { - ReturnStringArrayDelegate d = [] { return com_array{ L"One", L"Two", L"Three" }; }; - com_array value = d(); - REQUIRE(value.size() == 3); - REQUIRE(value[0] == L"One"); - REQUIRE(value[1] == L"Two"); - REQUIRE(value[2] == L"Three"); - } - { - OutStringArrayDelegate d = [](com_array& value) { value = { L"One", L"Two", L"Three" }; }; - - com_array value; - d(value); - - REQUIRE(value.size() == 3); - REQUIRE(value[0] == L"One"); - REQUIRE(value[1] == L"Two"); - REQUIRE(value[2] == L"Three"); - } - { - RefStringArrayDelegate d = [](array_view value) { value[0] = L"One"; value[1] = L"Two"; value[2] = L"Three"; }; - - std::array value{ L"r1", L"r2", L"r3", L"r4" }; - d(value); - - REQUIRE(value[0] == L"One"); - REQUIRE(value[1] == L"Two"); - REQUIRE(value[2] == L"Three"); - REQUIRE(value[3] == L""); - } -} diff --git a/test/test_win7/disconnected.cpp b/test/test_win7/disconnected.cpp deleted file mode 100644 index 583b7df36..000000000 --- a/test/test_win7/disconnected.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "pch.h" - -using namespace std::literals; -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - IAsyncAction Action() - { - co_return; - } - - IAsyncActionWithProgress ActionProgress() - { - co_await 500ms; - auto progress = co_await get_progress_token(); - progress(123); - co_return; - } - - IAsyncOperation Operation() - { - co_return 123; - } - - IAsyncOperationWithProgress OperationProgress() - { - co_await 500ms; - auto progress = co_await get_progress_token(); - progress(123); - co_return 123; - } -} - -TEST_CASE("disconnected") -{ - { - event> source; - - source.add([](auto...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); - - auto token = source.add([](auto...) - { - throw hresult_error(E_INVALIDARG); - }); - - // Should have two delegates - REQUIRE(source); - - // Should lose the disconnected delegate - source(nullptr, 123); - REQUIRE(source); - - // Fire the remaining delegate - source(nullptr, 123); - REQUIRE(source); - - // Remove the final delegate - source.remove(token); - - // No more delegates - REQUIRE(!source); - - source(nullptr, 123); - } - - { - auto async = Action(); - - async.Completed([](auto&&...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); - } - - { - auto async = ActionProgress(); - handle signal{ CreateEventW(nullptr, true, false, nullptr) }; - - async.Progress([](auto&&...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); - - async.Completed([&](auto&&...) - { - SetEvent(signal.get()); - throw hresult_error(RPC_E_DISCONNECTED); - }); - - WaitForSingleObject(signal.get(), INFINITE); - } - - { - auto async = Operation(); - - async.Completed([](auto&&...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); - } - - { - auto async = OperationProgress(); - handle signal{ CreateEventW(nullptr, true, false, nullptr) }; - - async.Progress([](auto&&...) - { - throw hresult_error(RPC_E_DISCONNECTED); - }); - - async.Completed([&](auto&&...) - { - SetEvent(signal.get()); - throw hresult_error(RPC_E_DISCONNECTED); - }); - - WaitForSingleObject(signal.get(), INFINITE); - } -} diff --git a/test/test_win7/enum.cpp b/test/test_win7/enum.cpp deleted file mode 100644 index 48f356a75..000000000 --- a/test/test_win7/enum.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.h" - -using namespace winrt; -using namespace test_component; - -TEST_CASE("enum") -{ - STATIC_REQUIRE(std::is_same_v, int32_t>); - STATIC_REQUIRE(std::is_same_v, uint32_t>); - - STATIC_REQUIRE(name_of() == L"test_component.Signed"sv); - STATIC_REQUIRE(name_of() == L"test_component.Unsigned"sv); - - REQUIRE(((Unsigned::First | Unsigned::Second | Unsigned::Third) & Unsigned::Second) == Unsigned::Second); - - REQUIRE(static_cast(Signed::First) == -1); - REQUIRE(static_cast(Signed::Second) == 0); - REQUIRE(static_cast(Signed::Third) == 1); - - REQUIRE(static_cast(Unsigned::First) == 0); - REQUIRE(static_cast(Unsigned::Second) == 1); - REQUIRE(static_cast(Unsigned::Third) == 2); -} diff --git a/test/test_win7/fast_iterator.cpp b/test/test_win7/fast_iterator.cpp deleted file mode 100644 index 5be28fb3d..000000000 --- a/test/test_win7/fast_iterator.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "pch.h" - -TEST_CASE("fast_iterator") -{ - { - auto v = winrt::single_threaded_vector({ 1, 2, 3 }); - - std::vector result; - - std::copy(begin(v), end(v), std::back_inserter(result)); - - REQUIRE((result == std::vector{ 1, 2, 3 })); - } - { - auto v = winrt::single_threaded_vector({ 1, 2, 3 }); - - std::vector result; - - std::copy(rbegin(v), rend(v), std::back_inserter(result)); - - REQUIRE((result == std::vector{ 3, 2, 1 })); - } -} diff --git a/test/test_win7/final_release.cpp b/test/test_win7/final_release.cpp deleted file mode 100644 index c615499cb..000000000 --- a/test/test_win7/final_release.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - struct Sample : implements - { - hstring ToString() - { - return L"Sample"; - } - - ~Sample() - { - // It's safe to QI/AddRef/Release inside destructor. - IStringable s; - check_hresult(QueryInterface(guid_of(), put_abi(s))); - REQUIRE(s.ToString() == L"Sample"); - - // Weak references are also supported during destruction. - REQUIRE(weak_ref{ s }.get()); - - REQUIRE(released); - REQUIRE(!destroyed); - destroyed = true; - } - - static void final_release(std::unique_ptr ptr) noexcept - { - // It's safe to QI/AddRef/Release inside final_release. - IStringable s; - check_hresult(ptr->QueryInterface(guid_of(), put_abi(s))); - REQUIRE(s.ToString() == L"Sample"); - - // References must be released prior to destroying the unique_ptr. - s = nullptr; - - REQUIRE(!released); - REQUIRE(!destroyed); - released = true; - ptr = nullptr; - REQUIRE(destroyed); - } - - static inline bool released; - static inline bool destroyed; - }; -} - -TEST_CASE("final_release") -{ - { - auto s = make(); - - // Weak references are supported prior to destruction. - REQUIRE(weak_ref{ s }.get()); - - REQUIRE(!Sample::released); - REQUIRE(!Sample::destroyed); - s = nullptr; - REQUIRE(Sample::released); - REQUIRE(Sample::destroyed); - } -} diff --git a/test/test_win7/generic_type_names.cpp b/test/test_win7/generic_type_names.cpp deleted file mode 100644 index 580d69ac3..000000000 --- a/test/test_win7/generic_type_names.cpp +++ /dev/null @@ -1,150 +0,0 @@ -// Windows.Foundation is intentionally *not* included here to ensure that stable names/guids -// are generated with only the xxx.0.h header. This ensures that indirect declarations produce -// stable identity values. -#define WINRT_LEAN_AND_MEAN -#include "winrt/Windows.Storage.h" - -#include "catch.hpp" -#include "generic_types.h" - -TEST_CASE("generic_type_names") -{ - using A = IIterable; - using B = IKeyValuePair>; - - test_guids(); - - // - // Generated Windows.Foundation names - // - - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IStringable", - IStringable); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IAsyncActionWithProgress`1>", - IAsyncActionWithProgress); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IAsyncOperationWithProgress`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - IAsyncOperationWithProgress); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IAsyncOperation`1>", - IAsyncOperation); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReferenceArray`1>", - IReferenceArray); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1>", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.AsyncActionProgressHandler`1>", - AsyncActionProgressHandler); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.AsyncActionWithProgressCompletedHandler`1>", - AsyncActionWithProgressCompletedHandler); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.AsyncOperationCompletedHandler`1>", - AsyncOperationCompletedHandler); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.AsyncOperationProgressHandler`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - AsyncOperationProgressHandler); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.AsyncOperationWithProgressCompletedHandler`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - AsyncOperationWithProgressCompletedHandler); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.EventHandler`1>", - EventHandler); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.TypedEventHandler`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - TypedEventHandler); - - // - // Generated Windows.Foundation.Collections names - // - - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IIterable`1>", - IIterable); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IIterator`1>", - IIterator); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IKeyValuePair`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - IKeyValuePair); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IMapChangedEventArgs`1>", - IMapChangedEventArgs); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IMapView`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - IMapView); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IMap`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - IMap); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IObservableMap`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - IObservableMap); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IObservableVector`1>", - IObservableVector); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IVectorView`1>", - IVectorView); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IVector`1>", - IVector); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.MapChangedEventHandler`2, Windows.Foundation.Collections.IKeyValuePair`2, Single>>>", - MapChangedEventHandler); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.VectorChangedEventHandler`1>", - VectorChangedEventHandler); - - // - // Generated primitive names - // - - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - - // Enums, structs, IInspectable, classes, and delegates - - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IReference`1", - IReference); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IVector`1", - IVector); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IVector`1", - IVector); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Collections.IVector`1", - IVector); -} diff --git a/test/test_win7/generic_types.cpp b/test/test_win7/generic_types.cpp deleted file mode 100644 index 98ffd12eb..000000000 --- a/test/test_win7/generic_types.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "pch.h" -#include "generic_types.h" - -TEST_CASE("generic_types") -{ - test_guids(); - - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Uri", Uri); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.PropertyType", PropertyType); - REQUIRE_EQUAL_NAME(L"Windows.Foundation.Point", Point); - - // Clang 9 doesn't think this is a constant expression. -#ifndef __clang__ - REQUIRE_EQUAL_NAME(L"Windows.Foundation.IStringable", IStringable); -#endif -} diff --git a/test/test_win7/generic_types.h b/test/test_win7/generic_types.h deleted file mode 100644 index d96b3bbfe..000000000 --- a/test/test_win7/generic_types.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -using namespace winrt; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace Windows::Foundation::Numerics; -using namespace std::literals; - -#define REQUIRE_EQUAL_GUID(left, ...) STATIC_REQUIRE(equal(guid(left), guid_of<__VA_ARGS__>())); -#define REQUIRE_EQUAL_NAME(left, ...) STATIC_REQUIRE(left == name_of<__VA_ARGS__>()); - -namespace -{ - constexpr bool equal(guid const& left, guid const& right) noexcept - { - return left.Data1 == right.Data1 && - left.Data2 == right.Data2 && - left.Data3 == right.Data3 && - left.Data4[0] == right.Data4[0] && - left.Data4[1] == right.Data4[1] && - left.Data4[2] == right.Data4[2] && - left.Data4[3] == right.Data4[3] && - left.Data4[4] == right.Data4[4] && - left.Data4[5] == right.Data4[5] && - left.Data4[6] == right.Data4[6] && - left.Data4[7] == right.Data4[7]; - } - - void test_guids() - { - using A = IIterable; - using B = IKeyValuePair>; - - REQUIRE_EQUAL_GUID("96369F54-8EB6-48F0-ABCE-C1B211E627C3"sv, IStringable); - - // - // Generated Windows.Foundation GUIDs - // - - REQUIRE_EQUAL_GUID("DD725452-2DA3-5103-9C7D-22EE9BB14AD3", IAsyncActionWithProgress); - REQUIRE_EQUAL_GUID("94645425-B9E5-5B91-B509-8DA4DF6A8916", IAsyncOperationWithProgress); - REQUIRE_EQUAL_GUID("2BD35EE6-72D9-5C5D-9827-05EBB81487AB", IAsyncOperation); - REQUIRE_EQUAL_GUID("4A33FE03-E8B9-5346-A124-5449913ECA57", IReferenceArray); - REQUIRE_EQUAL_GUID("F9E4006C-6E8C-56DF-811C-61F9990EBFB0", IReference); - REQUIRE_EQUAL_GUID("C261D8D0-71BA-5F38-A239-872342253A18", AsyncActionProgressHandler); - REQUIRE_EQUAL_GUID("9A0D211C-0374-5D23-9E15-EAA3570FAE63", AsyncActionWithProgressCompletedHandler); - REQUIRE_EQUAL_GUID("9D534225-231F-55E7-A6D0-6C938E2D9160", AsyncOperationCompletedHandler); - REQUIRE_EQUAL_GUID("264F1E0C-ABE4-590B-9D37-E1CC118ECC75", AsyncOperationProgressHandler); - REQUIRE_EQUAL_GUID("C2D078D8-AC47-55AB-83E8-123B2BE5BC5A", AsyncOperationWithProgressCompletedHandler); - REQUIRE_EQUAL_GUID("FA0B7D80-7EFA-52DF-9B69-0574CE57ADA4", EventHandler); - REQUIRE_EQUAL_GUID("EDB31843-B4CF-56EB-925A-D4D0CE97A08D", TypedEventHandler); - - // - // Generated Windows.Foundation.Collections GUIDs - // - - REQUIRE_EQUAL_GUID("96565EB9-A692-59C8-BCB5-647CDE4E6C4D", IIterable); - REQUIRE_EQUAL_GUID("3C9B1E27-8357-590B-8828-6E917F172390", IIterator); - REQUIRE_EQUAL_GUID("89336CD9-8B66-50A7-9759-EB88CCB2E1FE", IKeyValuePair); - REQUIRE_EQUAL_GUID("E1AA5138-12BD-51A1-8558-698DFD070ABE", IMapChangedEventArgs); - REQUIRE_EQUAL_GUID("B78F0653-FA89-59CF-BA95-726938AAE666", IMapView); - REQUIRE_EQUAL_GUID("9962CD50-09D5-5C46-B1E1-3C679C1C8FAE", IMap); - REQUIRE_EQUAL_GUID("75F99E2A-137E-537E-A5B1-0B5A6245FC02", IObservableMap); - REQUIRE_EQUAL_GUID("D24C289F-2341-5128-AAA1-292DD0DC1950", IObservableVector); - REQUIRE_EQUAL_GUID("5F07498B-8E14-556E-9D2E-2E98D5615DA9", IVectorView); - REQUIRE_EQUAL_GUID("0E3F106F-A266-50A1-8043-C90FCF3844F6", IVector); - REQUIRE_EQUAL_GUID("19046F0B-CF81-5DEC-BBB2-7CC250DA8B8B", MapChangedEventHandler); - REQUIRE_EQUAL_GUID("A1E9ACD7-E4DF-5A79-AEFA-DE07934AB0FB", VectorChangedEventHandler); - - // - // Generated primitive GUIDs - // - - REQUIRE_EQUAL_GUID("3C00FD60-2950-5939-A21A-2D12C5A01B8A", IReference); - REQUIRE_EQUAL_GUID("95500129-FBF6-5AFC-89DF-70642D741990", IReference); - REQUIRE_EQUAL_GUID("6EC9E41B-6709-5647-9918-A1270110FC4E", IReference); - REQUIRE_EQUAL_GUID("548CEFBD-BC8A-5FA0-8DF2-957440FC8BF4", IReference); - REQUIRE_EQUAL_GUID("4DDA9E24-E69F-5C6A-A0A6-93427365AF2A", IReference); - REQUIRE_EQUAL_GUID("e5198cc8-2873-55f5-b0a1-84ff9e4aad62", IReference); - REQUIRE_EQUAL_GUID("5AB7D2C3-6B62-5E71-A4B6-2D49C4F238FD", IReference); - REQUIRE_EQUAL_GUID("513ef3af-e784-5325-a91e-97c2b8111cf3", IReference); - REQUIRE_EQUAL_GUID("6755e376-53bb-568b-a11d-17239868309e", IReference); - REQUIRE_EQUAL_GUID("719CC2BA-3E76-5DEF-9F1A-38D85A145EA8", IReference); - REQUIRE_EQUAL_GUID("2F2D6C29-5473-5F3E-92E7-96572BB990E2", IReference); - REQUIRE_EQUAL_GUID("FB393EF3-BBAC-5BD5-9144-84F23576F415", IReference); - REQUIRE_EQUAL_GUID("7D50F649-632C-51F9-849A-EE49428933EA", IReference); - REQUIRE_EQUAL_GUID("6FF27A1E-4B6A-59B7-B2C3-D1F2EE474593", IReference); - REQUIRE_EQUAL_GUID("FD416DFB-2A07-52EB-AAE3-DFCE14116C05", IReference); - REQUIRE_EQUAL_GUID("A9B18291-CE2A-5DAE-8A23-B7F7388416DB", IReference); - REQUIRE_EQUAL_GUID("604D0C4C-91DE-5C2A-935F-362F13EAF800", IReference); - REQUIRE_EQUAL_GUID("5541D8A7-497C-5AA4-86FC-7713ADBF2A2C", IReference); - REQUIRE_EQUAL_GUID("84F14C22-A00A-5272-8D3D-82112E66DF00", IReference); - REQUIRE_EQUAL_GUID("80423F11-054F-5EAC-AFD3-63B6CE15E77B", IReference); - REQUIRE_EQUAL_GUID("61723086-8e53-5276-9f36-2a4bb93e2b75", IReference); - REQUIRE_EQUAL_GUID("48F6A69E-8465-57AE-9400-9764087F65AD", IReference); - REQUIRE_EQUAL_GUID("1EE770FF-C954-59CA-A754-6199A9BE282C", IReference); - REQUIRE_EQUAL_GUID("A5E843C9-ED20-5339-8F8D-9FE404CF3654", IReference); - REQUIRE_EQUAL_GUID("76358CFD-2CBD-525B-A49E-90EE18247B71", IReference); - REQUIRE_EQUAL_GUID("DACBFFDC-68EF-5FD0-B657-782D0AC9807E", IReference); - REQUIRE_EQUAL_GUID("B27004BB-C014-5DCE-9A21-799C5A3C1461", IReference); - REQUIRE_EQUAL_GUID("46D542A1-52F7-58E7-ACFC-9A6D364DA022", IReference); - - // Enums, structs, IInspectable, classes, and delegates - - REQUIRE_EQUAL_GUID("ECEBDE54-FAC0-5AEB-9BA9-9E1FE17E31D5", IReference); - REQUIRE_EQUAL_GUID("84F14C22-A00A-5272-8D3D-82112E66DF00", IReference); - REQUIRE_EQUAL_GUID("B32BDCA4-5E52-5B27-BC5D-D66A1A268C2A", IVector); - REQUIRE_EQUAL_GUID("0D82BD8D-FE62-5D67-A7B9-7886DD75BC4E", IVector); - REQUIRE_EQUAL_GUID("5DAFE591-86DC-59AA-BFDA-07F5D59FC708", IVector); - } -} diff --git a/test/test_win7/guid_key.cpp b/test/test_win7/guid_key.cpp deleted file mode 100644 index aaf560e15..000000000 --- a/test/test_win7/guid_key.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -TEST_CASE("guid_key") -{ - auto uri = guid_of(); - auto deferral = guid_of(); - - std::map ordered; - ordered[uri] = "Uri"; - ordered[deferral] = "Deferral"; - REQUIRE(ordered[uri] == "Uri"); - REQUIRE(ordered[deferral] == "Deferral"); - - std::unordered_map unordered; - unordered[uri] = "Uri"; - unordered[deferral] = "Deferral"; - REQUIRE(unordered[uri] == "Uri"); - REQUIRE(unordered[deferral] == "Deferral"); -} diff --git a/test/test_win7/iid_ppv_args.cpp b/test/test_win7/iid_ppv_args.cpp deleted file mode 100644 index 012e1856d..000000000 --- a/test/test_win7/iid_ppv_args.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "pch.h" -#include - -namespace -{ - struct Stringable : winrt::implements - { - winrt::hstring ToString() - { - return L"hello"; - } - }; - - HRESULT GetStringable(GUID const& id, void** object) noexcept - { - *object = nullptr; - - if (id != __uuidof(ABI::Windows::Foundation::IStringable)) - { - return E_NOINTERFACE; - } - - *object = winrt::detach_abi(winrt::make()); - return S_OK; - } -} - -TEST_CASE("iid_ppv_args") -{ - { - winrt::com_ptr ptr; - REQUIRE(S_OK == GetStringable(IID_PPV_ARGS(&ptr))); - REQUIRE(ptr.as().ToString() == L"hello"); - } - { - winrt::com_ptr ptr; - REQUIRE(E_NOINTERFACE == GetStringable(IID_PPV_ARGS(&ptr))); - } -} diff --git a/test/test_win7/in_params.cpp b/test/test_win7/in_params.cpp deleted file mode 100644 index dec896930..000000000 --- a/test/test_win7/in_params.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.h" - -using namespace winrt; -using namespace Windows::Foundation; -using namespace test_component; - -namespace -{ - struct Value : implements - { - Value(int32_t value) : - m_value(value) - { - } - - hstring ToString() - { - return hstring{ std::to_wstring(m_value) }; - } - - private: - - int32_t m_value{}; - }; -} - -TEST_CASE("in_params") -{ - Class object; - - REQUIRE(object.InInt32(123) == L"123"); - REQUIRE(object.InString(L"123") == L"123"); - REQUIRE(object.InObject(make(123)) == L"123"); - REQUIRE(object.InStringable(make(123)) == L"123"); - REQUIRE(object.InStruct({ L"1", L"2" }) == L"12"); - REQUIRE(object.InStructRef({ L"1", L"2" }) == L"12ref"); - REQUIRE(object.InEnum(Signed::First) == L"First"); - - REQUIRE(object.InInt32Array({ 1,2 }) == L"12"); - REQUIRE(object.InStringArray({ L"1", L"2" }) == L"12"); - REQUIRE(object.InObjectArray({ make(1), make(2) }) == L"12"); - REQUIRE(object.InStringableArray({ make(1), make(2) }) == L"12"); - REQUIRE(object.InStructArray({ {L"1",L"2"}, {L"3",L"4"} }) == L"1234"); - REQUIRE(object.InEnumArray({ Signed::First, Signed::Second }) == L"FirstSecond"); - - // Ensure 0-length arrays are passed as non-null pointers to the ABI, - // in order to keep RPC happy. - REQUIRE(object.InInt32Array({ }) == L""); - REQUIRE(object.InStringArray({ }) == L""); - REQUIRE(object.InObjectArray({ }) == L""); - REQUIRE(object.InStringableArray({ }) == L""); - REQUIRE(object.InStructArray({ }) == L""); - REQUIRE(object.InEnumArray({ }) == L""); - - // params::hstring optimizations - REQUIRE(object.InString(L"") == L""); - REQUIRE(object.InString({}) == L""); - wchar_t non_const_string[1] = { L'\0' }; - REQUIRE(object.InString(non_const_string) == L""); -} diff --git a/test/test_win7/inspectable_interop.cpp b/test/test_win7/inspectable_interop.cpp deleted file mode 100644 index d693a6062..000000000 --- a/test/test_win7/inspectable_interop.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include "winrt/Windows.Foundation.h" -#include "catch.hpp" - -using namespace winrt; - -namespace -{ - struct __declspec(uuid("ed0dd761-c31e-4803-8cf9-22a2cb20ec47")) IBadInterop : ::IInspectable - { - virtual int32_t __stdcall JustSayNo() noexcept = 0; - }; - - struct Sample : implements - { - Windows::Foundation::IInspectable ActivateInstance() - { - throw hresult_not_implemented(); - } - - hstring GetRuntimeClassName() - { - return L"Sample"; - } - - Windows::Foundation::TrustLevel GetTrustLevel() - { - return Windows::Foundation::TrustLevel::PartialTrust; - } - - int32_t __stdcall JustSayNo() noexcept final - { - return 123; - } - }; -} - -TEST_CASE("inspectable_interop") -{ - Windows::Foundation::IActivationFactory a = make(); - REQUIRE(a != nullptr); - - Windows::Foundation::IActivationFactory b = a.as(); - REQUIRE(b != nullptr); - - com_ptr c = a.as(); - REQUIRE(c != nullptr); - REQUIRE(c->JustSayNo() == 123); - - Windows::Foundation::IActivationFactory d = c.as(); - REQUIRE(a == d); - - Windows::Foundation::IInspectable f = c.as(); - REQUIRE(f != nullptr); - - Windows::Foundation::IInspectable e(c.detach(), take_ownership_from_abi); - - REQUIRE(winrt::get_class_name(e) == L"Sample"); - REQUIRE(winrt::get_trust_level(e) == Windows::Foundation::TrustLevel::PartialTrust); - - auto interfaces = winrt::get_interfaces(e); - REQUIRE(interfaces.size() == 1); - REQUIRE(interfaces[0] == guid_of()); -} diff --git a/test/test_win7/interop.cpp b/test/test_win7/interop.cpp deleted file mode 100644 index 9ca4c94ea..000000000 --- a/test/test_win7/interop.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "pch.h" -#include - -struct __declspec(uuid("5040a5f4-796a-42ff-9f06-be89137a518f")) IBase : IUnknown -{ -}; - -struct __declspec(uuid("529fed32-514f-4150-b1ba-15b47df700b7")) IDerived : IBase -{ -}; - -struct __declspec(uuid("b81fb2a2-eab4-488a-96a7-434873c2c20b")) IMoreDerived : IDerived -{ -}; - -namespace winrt -{ - template<> bool is_guid_of(guid const& id) noexcept - { - return is_guid_of(id); - } - - template<> bool is_guid_of(guid const& id) noexcept - { - return is_guid_of(id); - } -} - -using namespace winrt; - -struct MyBase : implements -{ -}; - -struct MyDerived : implements -{ -}; - -struct MyMoreDerived : implements -{ -}; - -Windows::Foundation::IAsyncAction Async() -{ - co_return; -} - -TEST_CASE("interop") -{ - { - Windows::Foundation::IAsyncAction a = Async(); - com_ptr<::IInspectable> b = a.as<::IInspectable>(); - Windows::Foundation::IAsyncAction c = b.as(); - REQUIRE(a == c); - } - { - com_ptr a = make(); - REQUIRE(a); - REQUIRE(a.try_as() != nullptr); - REQUIRE(a.try_as() == nullptr); - REQUIRE(a.try_as() == nullptr); - REQUIRE(a.try_as<::IInspectable>() == nullptr); - } - { - com_ptr a = make(); - REQUIRE(a); - REQUIRE(a.try_as() != nullptr); - REQUIRE(a.try_as() != nullptr); - REQUIRE(a.try_as() == nullptr); - REQUIRE(a.try_as<::IInspectable>() == nullptr); - } - { - com_ptr a = make(); - REQUIRE(a); - REQUIRE(a.try_as() != nullptr); - REQUIRE(a.try_as() != nullptr); - REQUIRE(a.try_as() != nullptr); - REQUIRE(a.try_as<::IInspectable>() != nullptr); - } -} diff --git a/test/test_win7/invalid_events.cpp b/test/test_win7/invalid_events.cpp deleted file mode 100644 index a8f6a69bd..000000000 --- a/test/test_win7/invalid_events.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -// -// Checks that invalid tokens may be removed harmlessly. -// - -TEST_CASE("invalid_events") -{ - event> event; - int counter{}; - - auto a = event.add([&](auto && ...) - { - counter += 1; - }); - - auto b = event.add([&](auto && ...) - { - counter += 10; - }); - - REQUIRE(counter == 0); - event(0, 0); - REQUIRE(counter == 11); - - // Remove invalid token (with two valids) - event.remove(event_token {1}); - - counter = 0; - event(0, 0); - REQUIRE(counter == 11); - - // Remove valid token - event.remove(b); - - counter = 0; - event(0, 0); - REQUIRE(counter == 1); - - // Remove invalid token (with one valid) - event.remove(event_token {1}); - - counter = 0; - event(0, 0); - REQUIRE(counter == 1); - - // Remove remaining valid token - event.remove(a); - - counter = 0; - event(0, 0); - REQUIRE(counter == 0); - - // Remove invalid token (with no valids) - event.remove(event_token {1}); - - counter = 0; - event(0, 0); - REQUIRE(counter == 0); -} diff --git a/test/test_win7/module_lock_dll.cpp b/test/test_win7/module_lock_dll.cpp deleted file mode 100644 index 605142126..000000000 --- a/test/test_win7/module_lock_dll.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "catch.hpp" - -// The default behavior (no macro) provides the static winrt::get_module_lock implementation for components/DLLs. - -#include "winrt/Windows.Foundation.h" - -namespace -{ - struct Stringable : winrt::implements - { - winrt::hstring ToString() - { - return L"Stringable"; - } - }; -} - -TEST_CASE("module_lock_dll") -{ - uint32_t const count = winrt::get_module_lock(); - - ++winrt::get_module_lock(); - - REQUIRE(winrt::get_module_lock() == count + 1); - - --winrt::get_module_lock(); - - REQUIRE(winrt::get_module_lock() == count); - - { - auto stringable = winrt::make(); - REQUIRE(winrt::get_module_lock() == count + 1); - } - - REQUIRE(winrt::get_module_lock() == count); - - { - winrt::Windows::Foundation::EventHandler delegate = [](auto&&...) {}; - REQUIRE(winrt::get_module_lock() == count + 1); - } - - REQUIRE(winrt::get_module_lock() == count); - - { - winrt::delegate delegate = [] {}; - REQUIRE(winrt::get_module_lock() == count + 1); - } - - REQUIRE(winrt::get_module_lock() == count); -} diff --git a/test/test_win7/names.cpp b/test/test_win7/names.cpp deleted file mode 100644 index 7730fe82e..000000000 --- a/test/test_win7/names.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -void check_terminated(winrt::param::hstring const&) -{ -} - -TEST_CASE("names") -{ - REQUIRE(name_of() == L"{00000000-0000-0000-c000-000000000046}"sv); - STATIC_REQUIRE(name_of() == L"Object"sv); - - check_terminated(name_of()); - check_terminated(name_of()); - check_terminated(name_of>()); - check_terminated(name_of>()); -} diff --git a/test/test_win7/no_make_detection.cpp b/test/test_win7/no_make_detection.cpp deleted file mode 100644 index f098f3228..000000000 --- a/test/test_win7/no_make_detection.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.h" - -using namespace winrt; -using namespace test_component; - -TEST_CASE("no_make_detection") -{ - REQUIRE(test_component::Class::TestNoMakeDetection()); -} diff --git a/test/test_win7/noexcept.cpp b/test/test_win7/noexcept.cpp deleted file mode 100644 index 1df30689f..000000000 --- a/test/test_win7/noexcept.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.h" - -using namespace winrt; -using namespace test_component; - -TEST_CASE("noexcept") -{ - Class c; - - c.NoexceptVoid(); - int32_t a = c.NoexceptInt32(); - hstring b = c.NoexceptString(); - - REQUIRE(a == 123); - REQUIRE(b == L"123"); -} diff --git a/test/test_win7/numerics.cpp b/test/test_win7/numerics.cpp deleted file mode 100644 index cfc73c0dd..000000000 --- a/test/test_win7/numerics.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation::Numerics; - -TEST_CASE("numerics") -{ - // Basic smoke test exercising SIMD intrinsics used by numerics. - - auto one = float4::one(); - - REQUIRE(one * one == one); -} diff --git a/test/test_win7/out_params.cpp b/test/test_win7/out_params.cpp deleted file mode 100644 index 7aafb63ae..000000000 --- a/test/test_win7/out_params.cpp +++ /dev/null @@ -1,278 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.h" - -using namespace winrt; -using namespace Windows::Foundation; -using namespace test_component; - -namespace -{ - struct Stringable : implements - { - hstring ToString() - { - return L"Stringable"; - } - }; -} - -TEST_CASE("out_params") -{ - Class object; - - { - int value; - object.OutInt32(value); - REQUIRE(value == 123); - } - { - hstring value = L"replace"; - object.OutString(value); - REQUIRE(value == L"123"); - } - { - IInspectable value = make(); - object.OutObject(value); - REQUIRE(value.as().ToString() == L"123"); - } - { - IStringable value = make(); - object.OutStringable(value); - REQUIRE(value.ToString() == L"123"); - } - { - Struct value{ L"First", L"Second" }; - object.OutStruct(value); - REQUIRE(value.First == L"1"); - REQUIRE(value.Second == L"2"); - } - { - Signed value; - object.OutEnum(value); - REQUIRE(value == Signed::First); - } - - { - com_array value(10); - object.OutInt32Array(value); - REQUIRE(value.size() == 3); - REQUIRE(value[0] == 1); - REQUIRE(value[1] == 2); - REQUIRE(value[2] == 3); - } - { - com_array value(10); - object.OutStringArray(value); - REQUIRE(value.size() == 3); - REQUIRE(value[0] == L"1"); - REQUIRE(value[1] == L"2"); - REQUIRE(value[2] == L"3"); - } - { - com_array value(10); - object.OutObjectArray(value); - REQUIRE(value.size() == 3); - REQUIRE(value[0].as().ToString() == L"1"); - REQUIRE(value[1].as().ToString() == L"2"); - REQUIRE(value[2].as().ToString() == L"3"); - } - { - com_array value(10); - object.OutStringableArray(value); - REQUIRE(value.size() == 3); - REQUIRE(value[0].ToString() == L"1"); - REQUIRE(value[1].ToString() == L"2"); - REQUIRE(value[2].ToString() == L"3"); - } - { - com_array value(10); - object.OutStructArray(value); - REQUIRE(value.size() == 2); - REQUIRE(value[0].First == L"1"); - REQUIRE(value[0].Second == L"2"); - REQUIRE(value[1].First == L"10"); - REQUIRE(value[1].Second == L"20"); - } - { - com_array value(10); - object.OutEnumArray(value); - REQUIRE(value.size() == 2); - REQUIRE(value[0] == Signed::First); - REQUIRE(value[1] == Signed::Second); - } - - { - std::array value{ 0xCC, 0xCC, 0xCC, 0xCC }; - object.RefInt32Array(value); - REQUIRE(value[0] == 1); - REQUIRE(value[1] == 2); - REQUIRE(value[2] == 3); - REQUIRE(value[3] == 0xCC); - } - { - std::array value{ L"r1", L"r2", L"r3", L"r4" }; - object.RefStringArray(value); - REQUIRE(value[0] == L"1"); - REQUIRE(value[1] == L"2"); - REQUIRE(value[2] == L"3"); - REQUIRE(value[3] == L""); - } - { - std::array value{ make(), make(), make(), make() }; - object.RefObjectArray(value); - REQUIRE(value[0].as().ToString() == L"1"); - REQUIRE(value[1].as().ToString() == L"2"); - REQUIRE(value[2].as().ToString() == L"3"); - REQUIRE(value[3] == nullptr); - } - { - std::array value{ make(), make(), make(), make() }; - object.RefStringableArray(value); - REQUIRE(value[0].ToString() == L"1"); - REQUIRE(value[1].ToString() == L"2"); - REQUIRE(value[2].ToString() == L"3"); - REQUIRE(value[3] == nullptr); - } - { - std::array value{ {L"First", L"Second"} }; - object.RefStructArray(value); - REQUIRE(value[0].First == L"1"); - REQUIRE(value[0].Second == L"2"); - REQUIRE(value[1].First == L"3"); - REQUIRE(value[1].Second == L"4"); - REQUIRE(value[2].First == L""); - REQUIRE(value[2].Second == L""); - } - { - std::array value{}; - object.RefEnumArray(value); - REQUIRE(value.size() == 3); - REQUIRE(value[0] == Signed::First); - REQUIRE(value[1] == Signed::Second); - REQUIRE(value[2] == static_cast(0)); - } - // Ensure 0-length arrays are passed as non-null pointers to the ABI, - // in order to keep RPC happy. - { - REQUIRE_NOTHROW(object.RefInt32Array({})); - REQUIRE_NOTHROW(object.RefStringArray({})); - REQUIRE_NOTHROW(object.RefObjectArray({})); - REQUIRE_NOTHROW(object.RefStringableArray({})); - REQUIRE_NOTHROW(object.RefStructArray({})); - REQUIRE_NOTHROW(object.RefEnumArray({})); - } - - object.Fail(true); - - { - int value = 0xCC; - REQUIRE_THROWS_AS(object.OutInt32(value), hresult_invalid_argument); - REQUIRE(value == 0xCC); - } - { - hstring value = L"replace"; - REQUIRE_THROWS_AS(object.OutString(value), hresult_invalid_argument); - REQUIRE(value == L""); - } - { - IInspectable value = make(); - REQUIRE_THROWS_AS(object.OutObject(value), hresult_invalid_argument); - REQUIRE(value == nullptr); - } - { - IStringable value = make(); - REQUIRE_THROWS_AS(object.OutStringable(value), hresult_invalid_argument); - REQUIRE(value == nullptr); - } - { - Struct value{ L"First", L"Second" }; - REQUIRE_THROWS_AS(object.OutStruct(value), hresult_invalid_argument); - REQUIRE(value.First == L""); - REQUIRE(value.Second == L""); - } - { - Signed value = static_cast(0xCC); - REQUIRE_THROWS_AS(object.OutEnum(value), hresult_invalid_argument); - REQUIRE(static_cast(value) == 0xCC); - } - - { - com_array value(10); - REQUIRE_THROWS_AS(object.OutInt32Array(value), hresult_invalid_argument); - REQUIRE(value.size() == 0); - } - { - com_array value(10); - REQUIRE_THROWS_AS(object.OutStringArray(value), hresult_invalid_argument); - REQUIRE(value.size() == 0); - } - { - com_array value(10); - REQUIRE_THROWS_AS(object.OutObjectArray(value), hresult_invalid_argument); - REQUIRE(value.size() == 0); - } - { - com_array value(10); - REQUIRE_THROWS_AS(object.OutStringableArray(value), hresult_invalid_argument); - REQUIRE(value.size() == 0); - } - { - com_array value(10); - REQUIRE_THROWS_AS(object.OutStructArray(value), hresult_invalid_argument); - REQUIRE(value.size() == 0); - } - { - com_array value(10); - REQUIRE_THROWS_AS(object.OutEnumArray(value), hresult_invalid_argument); - REQUIRE(value.size() == 0); - } - - { - std::array value{ 0xCC, 0xCC, 0xCC, 0xCC }; - REQUIRE_THROWS_AS(object.RefInt32Array(value), hresult_invalid_argument); - REQUIRE(value[0] == 0xCC); - REQUIRE(value[1] == 0xCC); - REQUIRE(value[2] == 0xCC); - REQUIRE(value[3] == 0xCC); - } - { - std::array value{ L"r1", L"r2", L"r3", L"r4" }; - REQUIRE_THROWS_AS(object.RefStringArray(value), hresult_invalid_argument); - REQUIRE(value[0] == L""); - REQUIRE(value[1] == L""); - REQUIRE(value[2] == L""); - REQUIRE(value[3] == L""); - } - { - std::array value{ make(), make(), make(), make() }; - REQUIRE_THROWS_AS(object.RefObjectArray(value), hresult_invalid_argument); - REQUIRE(value[0] == nullptr); - REQUIRE(value[1] == nullptr); - REQUIRE(value[2] == nullptr); - REQUIRE(value[3] == nullptr); - } - { - std::array value{ make(), make(), make(), make() }; - REQUIRE_THROWS_AS(object.RefStringableArray(value), hresult_invalid_argument); - REQUIRE(value[0] == nullptr); - REQUIRE(value[1] == nullptr); - REQUIRE(value[2] == nullptr); - REQUIRE(value[3] == nullptr); - } - { - std::array value{ {L"First", L"Second"} }; - REQUIRE_THROWS_AS(object.RefStructArray(value), hresult_invalid_argument); - REQUIRE(value[0].First == L""); - REQUIRE(value[0].Second == L""); - REQUIRE(value[1].First == L""); - REQUIRE(value[1].Second == L""); - REQUIRE(value[2].First == L""); - REQUIRE(value[2].Second == L""); - } - { - std::array value{ static_cast(0xCC), static_cast(0xCC) }; - REQUIRE_THROWS_AS(object.RefEnumArray(value), hresult_invalid_argument); - REQUIRE(value[0] == static_cast(0xCC)); - REQUIRE(value[1] == static_cast(0xCC)); - } -} diff --git a/test/test_win7/parent_includes.cpp b/test/test_win7/parent_includes.cpp deleted file mode 100644 index f7dc0d0c8..000000000 --- a/test/test_win7/parent_includes.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.Parent.One.Two.Three.h" - -using namespace winrt::test_component; - -TEST_CASE("parent_includes") -{ - // Including "...Three.h" should include all (available) ancestors, skipping - // any that are empty. In this case, "Three" and "Parent" are not empty while - // the intermediate namespaces are empty. - - Parent::One::Two::Three::ThreeStruct three; - three.Value = 0; - - Parent::ParentStruct parent; - parent.Value = 0; -} diff --git a/test/test_win7/pch.h b/test/test_win7/pch.h deleted file mode 100644 index 84bb40137..000000000 --- a/test/test_win7/pch.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#define WINRT_LEAN_AND_MEAN -#include -#include "winrt/Windows.Foundation.Collections.h" -#include "winrt/Windows.Foundation.Numerics.h" -#include "catch.hpp" - -using namespace std::literals; - -// Extracts return and progress types from IAsyncXxx. - -template -struct async_traits; - -template<> -struct async_traits -{ - using progress_type = void; -}; - -template -struct async_traits> -{ - using progress_type = P; -}; - -template -struct async_traits> -{ - using progress_type = void; -}; - -template -struct async_traits> -{ - using progress_type = P; -}; - -template -using async_return_type = decltype(std::declval().GetResults()); -template -using async_progress_type = typename async_traits>::progress_type; -template -inline constexpr bool has_async_progress = !std::is_same_v>::progress_type>; diff --git a/test/test_win7/return_params.cpp b/test/test_win7/return_params.cpp deleted file mode 100644 index 3ff5026d1..000000000 --- a/test/test_win7/return_params.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.h" - -using namespace winrt; -using namespace Windows::Foundation; -using namespace test_component; - -namespace -{ - struct Stringable : implements - { - hstring ToString() - { - return L"Stringable"; - } - }; -} - -TEST_CASE("return_params") -{ - Class object; - - { - int value = object.ReturnInt32(); - REQUIRE(value == 123); - } - { - hstring value = object.ReturnString(); - REQUIRE(value == L"123"); - } - { - IInspectable value = object.ReturnObject(); - REQUIRE(value.as().ToString() == L"123"); - } - { - IStringable value = object.ReturnStringable(); - REQUIRE(value.ToString() == L"123"); - } - { - Struct value = object.ReturnStruct(); - REQUIRE(value.First == L"1"); - REQUIRE(value.Second == L"2"); - } - { - com_array value = object.ReturnInt32Array(); - REQUIRE(value.size() == 3); - REQUIRE(value[0] == 1); - REQUIRE(value[1] == 2); - REQUIRE(value[2] == 3); - } - { - com_array value = object.ReturnStringArray(); - REQUIRE(value.size() == 3); - REQUIRE(value[0] == L"1"); - REQUIRE(value[1] == L"2"); - REQUIRE(value[2] == L"3"); - } - { - com_array value = object.ReturnObjectArray(); - REQUIRE(value.size() == 3); - REQUIRE(value[0].as().ToString() == L"1"); - REQUIRE(value[1].as().ToString() == L"2"); - REQUIRE(value[2].as().ToString() == L"3"); - } - { - com_array value = object.ReturnStringableArray(); - REQUIRE(value.size() == 3); - REQUIRE(value[0].ToString() == L"1"); - REQUIRE(value[1].ToString() == L"2"); - REQUIRE(value[2].ToString() == L"3"); - } - { - com_array value = object.ReturnStructArray(); - REQUIRE(value.size() == 2); - REQUIRE(value[0].First == L"1"); - REQUIRE(value[0].Second == L"2"); - REQUIRE(value[1].First == L"10"); - REQUIRE(value[1].Second == L"20"); - } -} diff --git a/test/test_win7/structs.cpp b/test/test_win7/structs.cpp deleted file mode 100644 index 3926c06ed..000000000 --- a/test/test_win7/structs.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.Structs.Nested.h" -#include "winrt/test_component_no_pch.Peer2.h" - -using namespace winrt; - -TEST_CASE("structs") -{ - test_component::Structs::Nested::Outer outer{}; - outer.Depends.InnerValue = 1; - outer.OuterValue = 2; - - test_component_no_pch::Peer2::B depends{}; - depends.First.Value = 1; - - test_component::Structs::All all{}; - all.H = {}; -} diff --git a/test/test_win7/test_win7.vcxproj b/test/test_win7/test_win7.vcxproj deleted file mode 100644 index 3d2d0eb18..000000000 --- a/test/test_win7/test_win7.vcxproj +++ /dev/null @@ -1,378 +0,0 @@ - - - - - Debug - ARM - - - Debug - ARM64 - - - Debug - Win32 - - - Release - ARM - - - Release - ARM64 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - {2EF696B9-7F4A-410F-AE5C-5301565C0F08} - unittests - test_win7 - 10.0 - - - - Application - true - - - Application - true - - - Application - true - - - Application - false - true - - - Application - false - true - - - Application - false - true - - - Application - true - - - Application - false - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(OutDir)temp\$(ProjectName)\ - - - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - $(OutDir)temp\$(ProjectName)\ - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..;..\..\cppwinrt - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded - - - Console - true - true - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - Disabled - $(OutputPath);Generated Files;..;..\..\cppwinrt - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - Console - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - Disabled - $(OutputPath);Generated Files;..;..\..\cppwinrt - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - Console - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - Disabled - $(OutputPath);Generated Files;..;..\..\cppwinrt - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - Console - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - Disabled - $(OutputPath);Generated Files;..;..\..\cppwinrt - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreadedDebug - - - Console - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..;..\..\cppwinrt - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded - - - Console - true - true - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..;..\..\cppwinrt - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded - - - Console - true - true - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - MaxSpeed - true - true - $(OutputPath);Generated Files;..;..\..\cppwinrt - NOMINMAX;_MBCS;%(PreprocessorDefinitions) - MultiThreaded - - - Console - true - true - - - $(OutputPath)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NotUsing - - - NotUsing - - - - - - - - - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - - - - Create - - - - - - - - - - - - \ No newline at end of file diff --git a/test/test_win7/thread_pool.cpp b/test/test_win7/thread_pool.cpp deleted file mode 100644 index ac75dac18..000000000 --- a/test/test_win7/thread_pool.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "pch.h" - -using namespace winrt; -using namespace Windows::Foundation; - -namespace -{ - struct AsyncQueue - { - thread_pool m_pool; - - AsyncQueue(uint32_t const high, uint32_t const low) - { - m_pool.thread_limits(high, low); - } - - IAsyncAction Async(delegate<> callback) - { - co_await m_pool; - callback(); - } - }; - - uint32_t test(uint32_t const iterations, uint32_t const high, uint32_t const low) - { - AsyncQueue queue(high, low); - std::vector results; - uint32_t counter{}; - - for (uint32_t i = 0; i < iterations; ++i) - { - results.push_back(queue.Async([&] - { - auto value = counter + 1; - Sleep(10); // Induce thread pool to use more threads if available, also force race condition - counter = value; - })); - } - - for (auto&& async : results) - { - async.get(); - } - - return counter; - } -} - -TEST_CASE("thread_pool") -{ - uint32_t const test_iterations = 100; - - uint32_t const stable_counter = test(test_iterations, 1, 1); - uint32_t const unstable_counter = test(test_iterations, 10, 10); - - // This is determinstic since the queue is single-threaded. - REQUIRE(stable_counter == test_iterations); - - // This is unlikely to fail since the pool is multi-threaded. - REQUIRE(unstable_counter < test_iterations); -} diff --git a/test/test_win7/uniform_in_params.cpp b/test/test_win7/uniform_in_params.cpp deleted file mode 100644 index 50eb3fde3..000000000 --- a/test/test_win7/uniform_in_params.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.h" - -using namespace winrt; -using namespace Windows::Foundation; -using namespace Windows::Foundation::Collections; -using namespace test_component; - -TEST_CASE("uniform_in_params") -{ - Class{ single_threaded_vector({ L"test" }).as>(), 0 }; - Class{ single_threaded_map(std::map{ {L"test", L"test" } }).as>>(), 0, 0 }; - Class{ single_threaded_map(std::map{ {L"test", L"test" } }), 0, 0, 0 }; - Class{ single_threaded_map(std::map{ {L"test", L"test" } }).GetView(), 0, 0, 0, 0 }; - Class{ single_threaded_vector({ L"test" }), 0, 0, 0, 0, 0 }; - Class{ single_threaded_vector({ L"test" }).GetView(), 0, 0, 0, 0, 0, 0 }; - - Class c; - REQUIRE(L"test" == c.InIterable({L"test"})); - REQUIRE(L"test" == c.InIterablePair(single_threaded_map(std::map{ {L"test", L"test" } }))); - REQUIRE(L"test" == c.InAsyncIterable({ L"test" }).get()); - REQUIRE(L"test" == c.InAsyncIterablePair(single_threaded_map(std::map{ {L"test", L"test" } })).get()); - REQUIRE(L"test" == c.InMap(single_threaded_map(std::map{ {L"test", L"test" } }))); - REQUIRE(L"test" == c.InMapView(single_threaded_map(std::map{ {L"test", L"test" } }).GetView())); - REQUIRE(L"test" == c.InAsyncMapView(single_threaded_map(std::map{ {L"test", L"test" } }).GetView()).get()); - REQUIRE(L"test" == c.InVector({ L"test" })); - REQUIRE(L"test" == c.InVectorView({ L"test" })); - REQUIRE(L"test" == c.InAsyncVectorView({ L"test" }).get()); -} diff --git a/test/test_win7/velocity.cpp b/test/test_win7/velocity.cpp deleted file mode 100644 index 11b11c1d7..000000000 --- a/test/test_win7/velocity.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "pch.h" -#include "winrt/test_component.Velocity.h" - -using namespace winrt; -using namespace test_component::Velocity; - -TEST_CASE("velocity") -{ - // This interface is always disabled but shows up in the type system - // if it is present in the winmd. - IInterface1 a; - REQUIRE(a == nullptr); - - // This interface is always enabled and is naturally available in - // the projection. - IInterface2 b; - REQUIRE(b == nullptr); - - // Class1 is always disabled and thus will not activate. - REQUIRE_THROWS_AS(Class1(), hresult_class_not_registered); - - // Class2 is always enabled so should activate just fine. - Class2 c; - c.Class2_Method(); - - // Class3 is always disabled and thus will not activate. - REQUIRE_THROWS_AS(Class3(), hresult_class_not_registered); - - // Class4 is not feature-controlled but uses feature interfaces. - Class4 d; - d.Class4_Method(); - - // The single argument constructor is always disabled. - REQUIRE_THROWS_AS(Class4(1), hresult_class_not_registered); - - // The Class4_Static1 static is always disabled. - REQUIRE_THROWS_AS(Class4::Class4_Static1(), hresult_class_not_registered); - - // The two argument constructor is always enabled. - Class4 e(1, 2); - - // The Class4_Static2 static is always enabled. - Class4::Class4_Static2(); -} diff --git a/test/test_win7/when.cpp b/test/test_win7/when.cpp deleted file mode 100644 index a3b284169..000000000 --- a/test/test_win7/when.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "pch.h" -#include - -using namespace concurrency; -using namespace winrt; -using namespace Windows::Foundation; - -task ppl(bool& done) -{ - co_await resume_background(); - done = true; -} - -IAsyncAction async(bool& done) -{ - co_await resume_background(); - done = true; -} - -IAsyncOperation when_signaled(int value, handle const& event) -{ - co_await resume_on_signal(event.get()); - co_return value; -} - -IAsyncAction done() -{ - co_return; -} - -TEST_CASE("when") -{ - { - bool ppl_done = false; - bool async_done = false; - - // Ensures that different async types can be aggregated. - when_all(ppl(ppl_done), async(async_done)).get(); - - REQUIRE(ppl_done); - REQUIRE(async_done); - } - { - // Works with IAsyncAction (with no return value). - IAsyncAction result = when_any(done(), done()); - result.get(); - } - { - handle first_event{ check_pointer(CreateEventW(nullptr, true, false, nullptr)) }; - handle second_event{ check_pointer(CreateEventW(nullptr, true, false, nullptr)) }; - - IAsyncOperation first = when_signaled(1, first_event); - IAsyncOperation second = when_signaled(2, second_event); - - IAsyncOperation result = when_any(first, second); - - // Make sure we're still waiting. - Sleep(100); - REQUIRE(result.Status() == AsyncStatus::Started); - REQUIRE(first.Status() == AsyncStatus::Started); - REQUIRE(second.Status() == AsyncStatus::Started); - - // Allow only one of the async objects to complete. - SetEvent(second_event.get()); - - // This should now complete. - REQUIRE(2 == result.get()); - - REQUIRE(first.Status() == AsyncStatus::Started); - REQUIRE(second.Status() == AsyncStatus::Completed); - - SetEvent(first_event.get()); - } -} diff --git a/vsix/Dev16/Component/source.extension.vsixmanifest b/vsix/Dev16/Component/source.extension.vsixmanifest index afd96cf1f..a7ab21972 100644 --- a/vsix/Dev16/Component/source.extension.vsixmanifest +++ b/vsix/Dev16/Component/source.extension.vsixmanifest @@ -29,7 +29,7 @@ - + diff --git a/vsix/Dev16/Standalone/source.extension.vsixmanifest b/vsix/Dev16/Standalone/source.extension.vsixmanifest index e3c2ac995..b38c06cf8 100644 --- a/vsix/Dev16/Standalone/source.extension.vsixmanifest +++ b/vsix/Dev16/Standalone/source.extension.vsixmanifest @@ -29,7 +29,7 @@ - + diff --git a/vsix/Dev16/vsix.Dev16.csproj b/vsix/Dev16/vsix.Dev16.csproj index 4b7c01cd2..94a6836c3 100644 --- a/vsix/Dev16/vsix.Dev16.csproj +++ b/vsix/Dev16/vsix.Dev16.csproj @@ -41,8 +41,8 @@ %(Filename)%(Extension) true - - Packages\Microsoft.Windows.CppWinRT.$(CppWinRTVersion).nupkg + + Packages\Microsoft.Windows.CppWinRT.$(NugetPackageVersion).nupkg true @@ -61,7 +61,11 @@ x64\%(Filename)%(Extension) true - + + arm64\%(Filename)%(Extension) + true + + Designer @@ -80,14 +84,15 @@ - 16.10.31321.278 + 16.10.31321.278 compile; build; native; contentfiles; analyzers; buildtransitive - 17.0.1619-preview1 runtime; build; native; contentfiles; analyzers; buildtransitive all + + diff --git a/vsix/Dev17/Component/source.extension.vsixmanifest b/vsix/Dev17/Component/source.extension.vsixmanifest index bcbfa9c8b..063dfcbc7 100644 --- a/vsix/Dev17/Component/source.extension.vsixmanifest +++ b/vsix/Dev17/Component/source.extension.vsixmanifest @@ -35,7 +35,7 @@ - + diff --git a/vsix/Dev17/Standalone/source.extension.vsixmanifest b/vsix/Dev17/Standalone/source.extension.vsixmanifest index 56ea4b86f..89e178c82 100644 --- a/vsix/Dev17/Standalone/source.extension.vsixmanifest +++ b/vsix/Dev17/Standalone/source.extension.vsixmanifest @@ -35,7 +35,7 @@ - + diff --git a/vsix/Dev17/vsix.Dev17.csproj b/vsix/Dev17/vsix.Dev17.csproj index 6e6c35bbf..02f3e0bb8 100644 --- a/vsix/Dev17/vsix.Dev17.csproj +++ b/vsix/Dev17/vsix.Dev17.csproj @@ -44,8 +44,8 @@ %(Filename)%(Extension) true - - Packages\Microsoft.Windows.CppWinRT.$(CppWinRTVersion).nupkg + + Packages\Microsoft.Windows.CppWinRT.$(NugetPackageVersion).nupkg true @@ -64,6 +64,10 @@ x64\%(Filename)%(Extension) true + + arm64\%(Filename)%(Extension) + true + Designer @@ -83,10 +87,10 @@ - + compile; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -164,6 +168,9 @@ + + + diff --git a/vsix/Extension.targets b/vsix/Extension.targets index 7a7b6c2b8..442f03a53 100644 --- a/vsix/Extension.targets +++ b/vsix/Extension.targets @@ -1,8 +1,10 @@ + + @@ -27,7 +29,7 @@ - + diff --git a/vsix/ItemTemplates/BlankPage/BlankPage.cpp b/vsix/ItemTemplates/BlankPage/BlankPage.cpp index 9af284cec..7410a619b 100644 --- a/vsix/ItemTemplates/BlankPage/BlankPage.cpp +++ b/vsix/ItemTemplates/BlankPage/BlankPage.cpp @@ -9,11 +9,6 @@ using namespace Windows::UI::Xaml; namespace winrt::$rootnamespace$::implementation { - $safeitemname$::$safeitemname$() - { - InitializeComponent(); - } - int32_t $safeitemname$::MyProperty() { throw hresult_not_implemented(); diff --git a/vsix/ItemTemplates/BlankPage/BlankPage.h b/vsix/ItemTemplates/BlankPage/BlankPage.h index f1dc903e8..4f7b2b0dd 100644 --- a/vsix/ItemTemplates/BlankPage/BlankPage.h +++ b/vsix/ItemTemplates/BlankPage/BlankPage.h @@ -6,7 +6,12 @@ namespace winrt::$rootnamespace$::implementation { struct $safeitemname$ : $safeitemname$T<$safeitemname$> { - $safeitemname$(); + $safeitemname$() + { + // Xaml objects should not call InitializeComponent during construction. + // If a Xaml object needs to access a Xaml property during initialization, it should override InitializeComponent. + // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent + } int32_t MyProperty(); void MyProperty(int32_t value); diff --git a/vsix/ItemTemplates/BlankPage/cppwinrt_BlankPage.vstemplate b/vsix/ItemTemplates/BlankPage/cppwinrt_BlankPage.vstemplate index 672d43b2f..bf6c43e9e 100644 --- a/vsix/ItemTemplates/BlankPage/cppwinrt_BlankPage.vstemplate +++ b/vsix/ItemTemplates/BlankPage/cppwinrt_BlankPage.vstemplate @@ -4,8 +4,12 @@ VC - 10 + 40 microsoft.Windows.CppWinRT.BlankPage + WinRT-Native-UAP + VisualC + WindowsXaml + 0 + false cppwinrt.ico cppwinrt.png diff --git a/vsix/ItemTemplates/BlankUserControl/BlankUserControl.cpp b/vsix/ItemTemplates/BlankUserControl/BlankUserControl.cpp index 9af284cec..7410a619b 100644 --- a/vsix/ItemTemplates/BlankUserControl/BlankUserControl.cpp +++ b/vsix/ItemTemplates/BlankUserControl/BlankUserControl.cpp @@ -9,11 +9,6 @@ using namespace Windows::UI::Xaml; namespace winrt::$rootnamespace$::implementation { - $safeitemname$::$safeitemname$() - { - InitializeComponent(); - } - int32_t $safeitemname$::MyProperty() { throw hresult_not_implemented(); diff --git a/vsix/ItemTemplates/BlankUserControl/BlankUserControl.h b/vsix/ItemTemplates/BlankUserControl/BlankUserControl.h index 7b994b1df..210b99659 100644 --- a/vsix/ItemTemplates/BlankUserControl/BlankUserControl.h +++ b/vsix/ItemTemplates/BlankUserControl/BlankUserControl.h @@ -10,7 +10,12 @@ namespace winrt::$rootnamespace$::implementation { struct $safeitemname$ : $safeitemname$T<$safeitemname$> { - $safeitemname$(); + $safeitemname$() + { + // Xaml objects should not call InitializeComponent during construction. + // If a Xaml object needs to access a Xaml property during initialization, it should override InitializeComponent. + // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent + } int32_t MyProperty(); void MyProperty(int32_t value); diff --git a/vsix/ItemTemplates/BlankUserControl/cppwinrt_BlankUserControl.vstemplate b/vsix/ItemTemplates/BlankUserControl/cppwinrt_BlankUserControl.vstemplate index e872ae3e0..f457df025 100644 --- a/vsix/ItemTemplates/BlankUserControl/cppwinrt_BlankUserControl.vstemplate +++ b/vsix/ItemTemplates/BlankUserControl/cppwinrt_BlankUserControl.vstemplate @@ -4,8 +4,12 @@ VC - 10 + 41 microsoft.Windows.CppWinRT.BlankUserControl + WinRT-Native-UAP + VisualC + WindowsXaml + 0 + false cppwinrt.ico cppwinrt.png diff --git a/vsix/ItemTemplates/ViewModel/cppwinrt_ViewModel.vstemplate b/vsix/ItemTemplates/ViewModel/cppwinrt_ViewModel.vstemplate index 5e5a5dbdd..20d2bcd90 100644 --- a/vsix/ItemTemplates/ViewModel/cppwinrt_ViewModel.vstemplate +++ b/vsix/ItemTemplates/ViewModel/cppwinrt_ViewModel.vstemplate @@ -4,8 +4,12 @@ VC - 10 + 42 microsoft.Windows.CppWinRT.ViewModel + WinRT-Native-UAP + VisualC + WindowsXaml + 0 + false cppwinrt.ico cppwinrt.png diff --git a/vsix/ProjectTemplates/VC/Windows Desktop/ConsoleApplication/ConsoleApplication.vcxproj b/vsix/ProjectTemplates/VC/Windows Desktop/ConsoleApplication/ConsoleApplication.vcxproj index ad52af212..f205306b8 100644 --- a/vsix/ProjectTemplates/VC/Windows Desktop/ConsoleApplication/ConsoleApplication.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Desktop/ConsoleApplication/ConsoleApplication.vcxproj @@ -10,7 +10,7 @@ Win32Proj $safeprojectname$ $targetplatformversion$ - 10.0.17134.0 + 10.0.18362.0 @@ -67,6 +67,7 @@ $(IntDir)pch.pch _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) Level4 + true %(AdditionalOptions) /permissive- /bigobj diff --git a/vsix/ProjectTemplates/VC/Windows Desktop/WindowsApplication/WindowsApplication.vcxproj b/vsix/ProjectTemplates/VC/Windows Desktop/WindowsApplication/WindowsApplication.vcxproj index 8b8cb03ce..e4a05cdc7 100644 --- a/vsix/ProjectTemplates/VC/Windows Desktop/WindowsApplication/WindowsApplication.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Desktop/WindowsApplication/WindowsApplication.vcxproj @@ -67,6 +67,7 @@ $(IntDir)pch.pch _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) Level4 + true %(AdditionalOptions) /permissive- /bigobj diff --git a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/App.cpp b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/App.cpp index 8806e25cb..2f3132d65 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/App.cpp +++ b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/App.cpp @@ -14,12 +14,11 @@ using namespace $safeprojectname$; using namespace $safeprojectname$::implementation; /// -/// Initializes the singleton application object. This is the first line of authored code +/// Creates the singleton application object. This is the first line of authored code /// executed, and as such is the logical equivalent of main() or WinMain(). /// App::App() { - InitializeComponent(); Suspending({ this, &App::OnSuspending }); #if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION diff --git a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/App.h b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/App.h index 8208308c8..b7fe65ef7 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/App.h +++ b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/App.h @@ -6,7 +6,6 @@ namespace winrt::$safeprojectname$::implementation struct App : AppT { App(); - void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs const&); void OnSuspending(IInspectable const&, Windows::ApplicationModel::SuspendingEventArgs const&); void OnNavigationFailed(IInspectable const&, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs const&); diff --git a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/BlankApp.vcxproj b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/BlankApp.vcxproj index af2b41932..ae3d074f2 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/BlankApp.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/BlankApp.vcxproj @@ -14,14 +14,10 @@ Windows Store 10.0 $targetplatformversion$ - 10.0.17134.0 + 10.0.18362.0 - - Debug - ARM - Debug ARM64 @@ -34,10 +30,6 @@ Debug x64 - - Release - ARM - Release ARM64 @@ -84,6 +76,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) diff --git a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/MainPage.cpp b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/MainPage.cpp index 5caaa46e6..af94324c3 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/MainPage.cpp +++ b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/MainPage.cpp @@ -7,11 +7,6 @@ using namespace Windows::UI::Xaml; namespace winrt::$safeprojectname$::implementation { - MainPage::MainPage() - { - InitializeComponent(); - } - int32_t MainPage::MyProperty() { throw hresult_not_implemented(); diff --git a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/MainPage.h b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/MainPage.h index 96c433917..366ef6614 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/MainPage.h +++ b/vsix/ProjectTemplates/VC/Windows Universal/BlankApp/MainPage.h @@ -6,7 +6,12 @@ namespace winrt::$safeprojectname$::implementation { struct MainPage : MainPageT { - MainPage(); + MainPage() + { + // Xaml objects should not call InitializeComponent during construction. + // If a Xaml object needs to access a Xaml property during initialization, it should override InitializeComponent. + // See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent + } int32_t MyProperty(); void MyProperty(int32_t value); diff --git a/vsix/ProjectTemplates/VC/Windows Universal/CoreApp/CoreApp.vcxproj b/vsix/ProjectTemplates/VC/Windows Universal/CoreApp/CoreApp.vcxproj index d2f2b002a..2d891ef11 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/CoreApp/CoreApp.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Universal/CoreApp/CoreApp.vcxproj @@ -13,14 +13,10 @@ Windows Store 10.0 $targetplatformversion$ - 10.0.17134.0 + 10.0.18362.0 - - Debug - ARM - Debug ARM64 @@ -33,10 +29,6 @@ Debug x64 - - Release - ARM - Release ARM64 @@ -83,6 +75,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) diff --git a/vsix/ProjectTemplates/VC/Windows Universal/StaticLibrary/StaticLibrary.vcxproj b/vsix/ProjectTemplates/VC/Windows Universal/StaticLibrary/StaticLibrary.vcxproj index 77cc1e005..2afea1c00 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/StaticLibrary/StaticLibrary.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Universal/StaticLibrary/StaticLibrary.vcxproj @@ -15,14 +15,10 @@ Windows Store 10.0 $targetplatformversion$ - 10.0.17134.0 + 10.0.18362.0 - - Debug - ARM - Debug ARM64 @@ -35,10 +31,6 @@ Debug x64 - - Release - ARM - Release ARM64 @@ -89,6 +81,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories) diff --git a/vsix/ProjectTemplates/VC/Windows Universal/WindowsRuntimeComponent/WindowsRuntimeComponent.vcxproj b/vsix/ProjectTemplates/VC/Windows Universal/WindowsRuntimeComponent/WindowsRuntimeComponent.vcxproj index 55a39d0dd..da87bf2fb 100644 --- a/vsix/ProjectTemplates/VC/Windows Universal/WindowsRuntimeComponent/WindowsRuntimeComponent.vcxproj +++ b/vsix/ProjectTemplates/VC/Windows Universal/WindowsRuntimeComponent/WindowsRuntimeComponent.vcxproj @@ -14,14 +14,10 @@ Windows Store 10.0 $targetplatformversion$ - 10.0.17134.0 + 10.0.18362.0 - - Debug - ARM - Debug ARM64 @@ -34,10 +30,6 @@ Debug x64 - - Release - ARM - Release ARM64 @@ -88,6 +80,7 @@ pch.h $(IntDir)pch.pch Level4 + true %(AdditionalOptions) /bigobj _WINRT_DLL;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions) $(WindowsSDK_WindowsMetadata);$(AdditionalUsingDirectories)