├── .azuredevops └── dependabot.yml ├── .config └── dotnet-tools.json ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .editorconfig ├── .gitattributes ├── .github ├── .editorconfig ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── actions │ └── publish-artifacts │ │ └── action.yaml ├── renovate.json └── workflows │ ├── docs.yml │ ├── docs_validate.yml │ ├── libtemplate-update.yml │ └── release.yml ├── .gitignore ├── .prettierrc.yaml ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── COPYRIGHT ├── Directory.Build.props ├── Directory.Build.rsp ├── Directory.Build.targets ├── Directory.Packages.Analyzers.props ├── Directory.Packages.props ├── LICENSE ├── Microsoft.Windows.CsWin32.sln ├── NOTICE.txt ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── azure-pipelines.yml ├── azure-pipelines ├── Archive-SourceCode.ps1 ├── BuildStageVariables.yml ├── Get-InsertionPRId.ps1 ├── GlobalVariables.yml ├── Install-NuGetPackage.ps1 ├── Merge-CodeCoverage.ps1 ├── NuGetSbom.targets ├── OptProf.yml ├── OptProf_part2.yml ├── PoliCheckExclusions.xml ├── PostPRMessage.ps1 ├── TSAOptions.json ├── WIFtoPATauth.yml ├── apiscan.yml ├── archive-sourcecode.yml ├── build.yml ├── dotnet.yml ├── falsepositives.gdnsuppress ├── install-dependencies.yml ├── integration-test.yml ├── libtemplate-update.yml ├── microbuild.after.yml ├── microbuild.before.yml ├── no_authenticode.txt ├── no_strongname.txt ├── official.yml ├── prepare-insertion-stages.yml ├── publish-codecoverage.yml ├── publish-symbols.yml ├── publish_artifacts.ps1 ├── release-deployment-prep.yml ├── release.yml ├── schedule-only-steps.yml ├── unofficial.yml ├── vs-insertion.yml └── vs-validation.yml ├── azurepipelines-coverage.yml ├── docfx ├── .gitignore ├── docfx.json ├── docs │ ├── 3rdPartyMetadata.md │ ├── ArchSpecificAPIs.md │ ├── features.md │ ├── getting-started.md │ └── toc.yml ├── images │ ├── ConfigurationManager_x64.png │ ├── StandardToolbarPlatformSwitcher.png │ └── demo.gif ├── index.md └── toc.yml ├── global.json ├── init.cmd ├── init.ps1 ├── integration-tests ├── Directory.Build.props ├── Directory.Build.targets ├── nonsdk │ ├── App.config │ ├── NativeMethods.json │ ├── NativeMethods.txt │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── nonsdk.csproj ├── nuget.config └── sdk │ ├── NativeMethods.json │ ├── NativeMethods.txt │ ├── Program.cs │ └── sdk.csproj ├── nuget.config ├── settings.VisualStudio.json ├── src ├── .editorconfig ├── AssemblyInfo.cs ├── AssemblyInfo.vb ├── Directory.Build.props ├── Directory.Build.targets ├── Microsoft.Windows.CsWin32 │ ├── AnalyzerReleases.Shipped.md │ ├── AnalyzerReleases.Unshipped.md │ ├── ArrayTypeHandleInfo.cs │ ├── BannedSymbols.txt │ ├── BindingRedirects.cs │ ├── CustomAttributeTypeProvider.cs │ ├── Docs.cs │ ├── FastSyntaxFactory.cs │ ├── GenerationFailedException.cs │ ├── Generator.ApiDocs.cs │ ├── Generator.Com.cs │ ├── Generator.Constant.cs │ ├── Generator.Delegate.cs │ ├── Generator.Enum.cs │ ├── Generator.Extern.cs │ ├── Generator.Features.cs │ ├── Generator.FriendlyOverloads.cs │ ├── Generator.GeneratedCode.cs │ ├── Generator.Handle.cs │ ├── Generator.InlineArrays.cs │ ├── Generator.Invariants.cs │ ├── Generator.MetadataHelpers.cs │ ├── Generator.Struct.cs │ ├── Generator.Templates.cs │ ├── Generator.TypeDef.cs │ ├── Generator.WhitespaceRewriter.cs │ ├── Generator.cs │ ├── GeneratorExtensions.cs │ ├── GeneratorOptions.cs │ ├── GlobalUsings.cs │ ├── HandleTypeHandleInfo.cs │ ├── IGenerator.cs │ ├── ITypeHandleContainer.cs │ ├── MetadataCache.cs │ ├── MetadataFile.cs │ ├── MetadataIndex.cs │ ├── MetadataQualifiedTokens.cs │ ├── MetadataUtilities.cs │ ├── Microsoft.Windows.CsWin32.csproj │ ├── Microsoft.Windows.CsWin32.nuspec │ ├── Microsoft.Windows.CsWin32.targets │ ├── ModuleInitializerAttribute.cs │ ├── NamespaceMetadata.cs │ ├── PlatformIncompatibleException.cs │ ├── PointerTypeHandleInfo.cs │ ├── PrimitiveTypeHandleInfo.cs │ ├── README.md │ ├── Rental.cs │ ├── SignatureHandleProvider.cs │ ├── SimpleSyntaxFactory.cs │ ├── SourceGenerator.cs │ ├── SuperGenerator.cs │ ├── TypeHandleInfo.cs │ ├── TypeSyntaxAndMarshaling.cs │ ├── TypeSyntaxSettings.cs │ ├── build │ │ ├── Microsoft.Windows.CsWin32.props │ │ ├── net20 │ │ │ └── Microsoft.Windows.CsWin32.props │ │ └── netstandard1.0 │ │ │ └── Microsoft.Windows.CsWin32.props │ ├── readme.txt │ ├── settings.schema.json │ ├── templates │ │ ├── .editorconfig │ │ ├── BOOL.cs │ │ ├── BOOLEAN.cs │ │ ├── BSTR.cs │ │ ├── ComHelpers.cs │ │ ├── DECIMAL.cs │ │ ├── HRESULT.cs │ │ ├── IUnknownHelperMethods.cs │ │ ├── IVTable.cs │ │ ├── IVTable`2.cs │ │ ├── NTSTATUS.cs │ │ ├── OverloadResolutionPriorityAttribute.cs │ │ ├── PCSTR.cs │ │ ├── PCWSTR.cs │ │ ├── PCZZSTR.cs │ │ ├── PCZZWSTR.cs │ │ ├── PInvokeClassHelperMethods.cs │ │ ├── PInvokeClassMacros.cs │ │ ├── PSTR.cs │ │ ├── PWSTR.cs │ │ ├── PZZSTR.cs │ │ ├── PZZWSTR.cs │ │ ├── RECT.cs │ │ ├── SIZE.cs │ │ ├── SYSTEMTIME.cs │ │ ├── VARIANT_BOOL.cs │ │ ├── VariableLengthInlineArray`1.cs │ │ ├── VariableLengthInlineArray`2.cs │ │ ├── WinRTCustomMarshaler.cs │ │ ├── marshaling │ │ │ └── CoCreateInstance.cs │ │ └── no_marshaling │ │ │ └── CoCreateInstance.cs │ ├── tools │ │ ├── install.ps1 │ │ └── uninstall.ps1 │ └── version.json ├── OptProf.targets └── VSInsertionMetadata │ ├── Library.VSInsertionMetadata.proj │ ├── ProfilingInputs.props │ └── VSInsertionMetadata.targets ├── stylecop.json ├── test ├── .editorconfig ├── CsWin32User.props ├── Directory.Build.props ├── Directory.Build.targets ├── GenerationSandbox.Tests │ ├── BasicTests.cs │ ├── BitFieldTests.cs │ ├── BoolTests.cs │ ├── BooleanTests.cs │ ├── ComRuntimeTests.cs │ ├── FILE_CREATE_FLAGS.cs │ ├── FlexibleArrayTests.cs │ ├── GeneratedForm.cs │ ├── GenerationSandbox.Tests.csproj │ ├── MacroTests.cs │ ├── NativeMethods.json │ ├── NativeMethods.txt │ ├── StringTests.cs │ ├── SystemDrawingStructTests.cs │ ├── TestUtils.cs │ ├── VARIANT_BOOLTests.cs │ └── xunit.runner.json ├── GenerationSandbox.Unmarshalled.Tests │ ├── COMTests.cs │ ├── ComHelpers.cs │ ├── GeneratedForm.cs │ ├── GenerationSandbox.Unmarshalled.Tests.csproj │ ├── NativeMethods.json │ └── NativeMethods.txt ├── GenerationSandbox.props ├── Microsoft.Windows.CsWin32.Tests │ ├── COMTests.cs │ ├── CSharpSourceGeneratorVerifier.cs │ ├── ConstantsTests.cs │ ├── DelegateTests.cs │ ├── EnumTests.cs │ ├── ExternMethodTests.cs │ ├── ExternalMetadata │ │ ├── NOTICE.md │ │ └── ServiceFabric.winmd │ ├── FriendlyOverloadTests.cs │ ├── FullGenerationTests.cs │ ├── GeneratorConfiguration.cs │ ├── GeneratorOptionsTests.cs │ ├── GeneratorTestBase.cs │ ├── GeneratorTests.cs │ ├── GlobalUsings.cs │ ├── HandleTests.cs │ ├── InlineArrayTests.cs │ ├── MacrosTests.cs │ ├── Microsoft.Windows.CsWin32.Tests.csproj │ ├── MultiMetadataTests.cs │ ├── MyReferenceAssemblies.cs │ ├── NumberedLineWriter.cs │ ├── SourceGeneratorTests.cs │ ├── StructTests.cs │ ├── TestUtils.cs │ └── xunit.runner.json ├── SpellChecker │ ├── NativeMethods.json │ ├── NativeMethods.txt │ ├── Program.cs │ └── SpellChecker.csproj └── WinRTInteropTest │ ├── CompositionHost.cs │ ├── NativeMethods.txt │ ├── Program.cs │ └── WinRTInteropTest.csproj ├── tools ├── Check-DotNetRuntime.ps1 ├── Check-DotNetSdk.ps1 ├── Convert-PDB.ps1 ├── Get-ArtifactsStagingDirectory.ps1 ├── Get-CodeCovTool.ps1 ├── Get-LibTemplateBasis.ps1 ├── Get-NuGetTool.ps1 ├── Get-ProcDump.ps1 ├── Get-SymbolFiles.ps1 ├── Get-TempToolsPath.ps1 ├── Install-DotNetSdk.ps1 ├── Install-NuGetCredProvider.ps1 ├── MergeFrom-Template.ps1 ├── Prepare-Legacy-Symbols.ps1 ├── Set-EnvVars.ps1 ├── artifacts │ ├── APIScanInputs.ps1 │ ├── LocBin.ps1 │ ├── VSInsertion.ps1 │ ├── Variables.ps1 │ ├── _all.ps1 │ ├── _stage_all.ps1 │ ├── build_logs.ps1 │ ├── coverageResults.ps1 │ ├── deployables.ps1 │ ├── projectAssetsJson.ps1 │ ├── symbols.ps1 │ ├── testResults.ps1 │ └── test_symbols.ps1 ├── dotnet-test-cloud.ps1 ├── publish-CodeCov.ps1 ├── test.runsettings └── variables │ ├── BusinessGroupName.ps1 │ ├── DotNetSdkVersion.ps1 │ ├── InsertJsonValues.ps1 │ ├── InsertPropsValues.ps1 │ ├── InsertTargetBranch.ps1 │ ├── InsertVersionsValues.ps1 │ ├── IsSigned.ps1 │ ├── LocLanguages.ps1 │ ├── ProfilingInputsDropName.ps1 │ ├── SymbolsFeatureName.ps1 │ ├── VstsDropNames.ps1 │ ├── _all.ps1 │ └── _define.ps1 └── version.json /.azuredevops/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://eng.ms/docs/products/dependabot/configuration/version_updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: nuget 7 | directory: / 8 | schedule: 9 | interval: monthly 10 | -------------------------------------------------------------------------------- /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "powershell": { 6 | "version": "7.5.0", 7 | "commands": [ 8 | "pwsh" 9 | ], 10 | "rollForward": false 11 | }, 12 | "dotnet-coverage": { 13 | "version": "17.14.2", 14 | "commands": [ 15 | "dotnet-coverage" 16 | ], 17 | "rollForward": false 18 | }, 19 | "nbgv": { 20 | "version": "3.7.115", 21 | "commands": [ 22 | "nbgv" 23 | ], 24 | "rollForward": false 25 | }, 26 | "docfx": { 27 | "version": "2.78.3", 28 | "commands": [ 29 | "docfx" 30 | ], 31 | "rollForward": false 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Refer to https://hub.docker.com/_/microsoft-dotnet-sdk for available versions 2 | FROM mcr.microsoft.com/dotnet/sdk:9.0.200-noble 3 | 4 | # Installing mono makes `dotnet test` work without errors even for net472. 5 | # But installing it takes a long time, so it's excluded by default. 6 | #RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF 7 | #RUN echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | tee /etc/apt/sources.list.d/mono-official-stable.list 8 | #RUN apt-get update 9 | #RUN DEBIAN_FRONTEND=noninteractive apt-get install -y mono-devel 10 | 11 | # Clear the NUGET_XMLDOC_MODE env var so xml api doc files get unpacked, allowing a rich experience in Intellisense. 12 | # See https://github.com/dotnet/dotnet-docker/issues/2790 for a discussion on this, where the prioritized use case 13 | # was *not* devcontainers, sadly. 14 | ENV NUGET_XMLDOC_MODE= 15 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Dev space", 3 | "dockerFile": "Dockerfile", 4 | "customizations": { 5 | "vscode": { 6 | "settings": { 7 | "terminal.integrated.shell.linux": "/usr/bin/pwsh" 8 | }, 9 | "extensions": [ 10 | "ms-azure-devops.azure-pipelines", 11 | "ms-dotnettools.csharp", 12 | "k--kato.docomment", 13 | "editorconfig.editorconfig", 14 | "esbenp.prettier-vscode", 15 | "pflannery.vscode-versionlens", 16 | "davidanson.vscode-markdownlint", 17 | "dotjoshjohnson.xml", 18 | "ms-vscode-remote.remote-containers", 19 | "ms-azuretools.vscode-docker", 20 | "tintoy.msbuild-project-tools" 21 | ] 22 | } 23 | }, 24 | "postCreateCommand": "./init.ps1 -InstallLocality machine" 25 | } 26 | -------------------------------------------------------------------------------- /.github/.editorconfig: -------------------------------------------------------------------------------- 1 | [renovate.json*] 2 | indent_style = tab 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Actual behavior 11 | 12 | [A clear and concise description of what the bug is.] 13 | 14 | ## Expected behavior 15 | 16 | A clear and concise description of what you expected to happen. 17 | 18 | ## Repro steps 19 | 20 | 1. `NativeMethods.txt` content: 21 | ``` 22 | 23 | ``` 24 | 25 | 2. `NativeMethods.json` content (if present): 26 | ```json 27 | ``` 28 | 29 | 3. Any of your own code that should be shared? 30 | 31 | ### Context 32 | 33 | - CsWin32 version: [e.g. `0.4.422-beta`] 34 | - Win32Metadata version (if explicitly set by project): 35 | - Target Framework: [e.g. `netstandard2.0`] 36 | - `LangVersion` (if explicitly set by project): [e.g. `9`] 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/actions/publish-artifacts/action.yaml: -------------------------------------------------------------------------------- 1 | name: Publish artifacts 2 | description: Publish artifacts 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: 📥 Collect artifacts 8 | run: tools/artifacts/_stage_all.ps1 9 | shell: pwsh 10 | if: always() 11 | 12 | # TODO: replace this hard-coded list with a loop that utilizes the NPM package at 13 | # https://github.com/actions/toolkit/tree/main/packages/artifact (or similar) to push the artifacts. 14 | 15 | - name: 📢 Upload project.assets.json files 16 | if: always() 17 | uses: actions/upload-artifact@v4 18 | with: 19 | name: projectAssetsJson-${{ runner.os }} 20 | path: ${{ runner.temp }}/_artifacts/projectAssetsJson 21 | continue-on-error: true 22 | - name: 📢 Upload variables 23 | uses: actions/upload-artifact@v4 24 | with: 25 | name: variables-${{ runner.os }} 26 | path: ${{ runner.temp }}/_artifacts/Variables 27 | continue-on-error: true 28 | - name: 📢 Upload build_logs 29 | if: always() 30 | uses: actions/upload-artifact@v4 31 | with: 32 | name: build_logs-${{ runner.os }} 33 | path: ${{ runner.temp }}/_artifacts/build_logs 34 | continue-on-error: true 35 | - name: 📢 Upload testResults 36 | if: always() 37 | uses: actions/upload-artifact@v4 38 | with: 39 | name: testResults-${{ runner.os }} 40 | path: ${{ runner.temp }}/_artifacts/testResults 41 | continue-on-error: true 42 | - name: 📢 Upload coverageResults 43 | if: always() 44 | uses: actions/upload-artifact@v4 45 | with: 46 | name: coverageResults-${{ runner.os }} 47 | path: ${{ runner.temp }}/_artifacts/coverageResults 48 | continue-on-error: true 49 | - name: 📢 Upload symbols 50 | uses: actions/upload-artifact@v4 51 | with: 52 | name: symbols-${{ runner.os }} 53 | path: ${{ runner.temp }}/_artifacts/symbols 54 | continue-on-error: true 55 | - name: 📢 Upload deployables 56 | uses: actions/upload-artifact@v4 57 | with: 58 | name: deployables-${{ runner.os }} 59 | path: ${{ runner.temp }}/_artifacts/deployables 60 | if: always() 61 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>microsoft/vs-renovate-presets:microbuild", 5 | "github>microsoft/vs-renovate-presets:vs_main_dependencies" 6 | ], 7 | "packageRules": [ 8 | { 9 | "matchPackageNames": ["MessagePack", "MessagePackAnalyzer"], 10 | "enabled": false 11 | }, 12 | { 13 | "matchFileNames": ["Directory.Packages.Analyzers.props"], 14 | "enabled": false 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: 📚 Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 9 | permissions: 10 | actions: read 11 | pages: write 12 | id-token: write 13 | contents: read 14 | 15 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 16 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 17 | concurrency: 18 | group: pages 19 | cancel-in-progress: false 20 | 21 | jobs: 22 | publish-docs: 23 | environment: 24 | name: github-pages 25 | url: ${{ steps.deployment.outputs.page_url }} 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work. 31 | - name: ⚙ Install prerequisites 32 | run: ./init.ps1 -UpgradePrerequisites 33 | 34 | - run: dotnet docfx docfx/docfx.json 35 | name: 📚 Generate documentation 36 | 37 | - name: Upload artifact 38 | uses: actions/upload-pages-artifact@v3 39 | with: 40 | path: docfx/_site 41 | 42 | - name: Deploy to GitHub Pages 43 | id: deployment 44 | uses: actions/deploy-pages@v4 45 | -------------------------------------------------------------------------------- /.github/workflows/docs_validate.yml: -------------------------------------------------------------------------------- 1 | name: 📃 Docfx Validate 2 | 3 | on: 4 | pull_request: 5 | workflow_dispatch: 6 | push: 7 | branches: 8 | - main 9 | - microbuild 10 | 11 | jobs: 12 | build: 13 | name: 📚 Doc validation 14 | runs-on: ubuntu-24.04 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work. 19 | - name: 🔗 Markup Link Checker (mlc) 20 | uses: becheran/mlc@v0.21.0 21 | with: 22 | args: --do-not-warn-for-redirect-to https://learn.microsoft.com*,https://dotnet.microsoft.com/*,https://dev.azure.com/*,https://app.codecov.io/* -p docfx -i https://aka.ms/onboardsupport,https://aka.ms/spot,https://msrc.microsoft.com/*,https://www.microsoft.com/msrc*,https://microsoft.com/msrc* 23 | - name: ⚙ Install prerequisites 24 | run: | 25 | ./init.ps1 -UpgradePrerequisites 26 | dotnet --info 27 | shell: pwsh 28 | - name: 📚 Verify docfx build 29 | run: dotnet docfx docfx/docfx.json --warningsAsErrors --disableGitFeatures 30 | if: runner.os == 'Linux' 31 | -------------------------------------------------------------------------------- /.prettierrc.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CsWin32/10ff614acb54f6d5a5dbb77c59bd8786e5c99097/.prettierrc.yaml -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | // List of extensions which should be recommended for users of this workspace. 5 | "recommendations": [ 6 | "ms-azure-devops.azure-pipelines", 7 | "ms-dotnettools.csharp", 8 | "k--kato.docomment", 9 | "editorconfig.editorconfig", 10 | "esbenp.prettier-vscode", 11 | "pflannery.vscode-versionlens", 12 | "davidanson.vscode-markdownlint", 13 | "dotjoshjohnson.xml", 14 | "ms-vscode-remote.remote-containers", 15 | "ms-azuretools.vscode-docker", 16 | "tintoy.msbuild-project-tools" 17 | ], 18 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 19 | "unwantedRecommendations": [] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Attach", 9 | "type": "coreclr", 10 | "request": "attach", 11 | "processId": "${command:pickProcess}" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.trimTrailingWhitespace": true, 3 | "files.insertFinalNewline": true, 4 | "files.trimFinalNewlines": true, 5 | "azure-pipelines.1ESPipelineTemplatesSchemaFile": true, 6 | "omnisharp.enableEditorConfigSupport": true, 7 | "omnisharp.enableRoslynAnalyzers": true, 8 | "dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true, 9 | "editor.formatOnSave": true, 10 | "[xml]": { 11 | "editor.wordWrap": "off" 12 | }, 13 | // Treat these files as Azure Pipelines files 14 | "files.associations": { 15 | "**/azure-pipelines/**/*.yml": "azure-pipelines", 16 | "azure-pipelines.yml": "azure-pipelines" 17 | }, 18 | // Use Prettier as the default formatter for Azure Pipelines files. 19 | // Needs to be explicitly configured: https://github.com/Microsoft/azure-pipelines-vscode#document-formatting 20 | "[azure-pipelines]": { 21 | "editor.defaultFormatter": "esbenp.prettier-vscode", 22 | "editor.formatOnSave": false // enable this when they conform 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright (c) Microsoft Corporation. All rights reserved. 2 | Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | -------------------------------------------------------------------------------- /Directory.Build.rsp: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # This file contains command-line options that MSBuild will process as part of 3 | # every build, unless the "/noautoresponse" switch is specified. 4 | # 5 | # MSBuild processes the options in this file first, before processing the 6 | # options on the command line. As a result, options on the command line can 7 | # override the options in this file. However, depending on the options being 8 | # set, the overriding can also result in conflicts. 9 | # 10 | # NOTE: The "/noautoresponse" switch cannot be specified in this file, nor in 11 | # any response file that is referenced by this file. 12 | #------------------------------------------------------------------------------ 13 | /nr:false 14 | /m 15 | /verbosity:minimal 16 | /clp:Summary;ForceNoAlign 17 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 5 | 16.9 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Directory.Packages.Analyzers.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 3.11.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C#/Win32 P/Invoke Source Generator 2 | 3 | ***A source generator to add a user-defined set of Win32 P/Invoke methods and supporting types to a C# project.*** 4 | 5 | [![NuGet (prerelease)](https://img.shields.io/nuget/v/Microsoft.Windows.CsWin32)](https://www.nuget.org/packages/Microsoft.Windows.CsWin32) 6 | [![NuGet (daily)](https://img.shields.io/badge/nuget-daily-red)](https://dev.azure.com/azure-public/winsdk/_packaging?_a=package&feed=CI%40Local&package=Microsoft.Windows.CsWin32&protocolType=NuGet) 7 | 8 | [![Build Status](https://dev.azure.com/azure-public/winsdk/_apis/build/status/microsoft.CsWin32?branchName=main)](https://dev.azure.com/azure-public/winsdk/_build/latest?definitionId=47&branchName=main) 9 | 10 | ## Features 11 | 12 | * Rapidly add P/Invoke methods and supporting types to your C# project. 13 | * No bulky assemblies to ship alongside your application. 14 | * `SafeHandle`-types automatically generated. 15 | * Generates xml documentation based on and links back to docs.microsoft.com 16 | 17 | ![Animation demonstrating p/invoke code generation](docfx/images/demo.gif) 18 | 19 | ## Usage 20 | 21 | [Check out our product documentation](https://microsoft.github.io/CsWin32/docs/getting-started.html). 22 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 6 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 7 | feature request as a new Issue. 8 | 9 | For help and questions about using this project, please file a GitHub issue. 10 | 11 | ## Microsoft Support Policy 12 | 13 | Support for this C# projection generator is limited to the resources listed above. 14 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | batch: true 3 | branches: 4 | include: 5 | - main 6 | - 'v*.*' 7 | - 'validate/*' 8 | paths: 9 | exclude: 10 | - doc/ 11 | - '*.md' 12 | - .vscode/ 13 | - .github/ 14 | - azure-pipelines/release.yml 15 | 16 | parameters: 17 | - name: EnableMacOSBuild 18 | displayName: Build on macOS 19 | type: boolean 20 | default: false # macOS is often bogged down in Azure Pipelines 21 | - name: RunTests 22 | displayName: Run tests 23 | type: boolean 24 | default: true 25 | 26 | variables: 27 | - template: /azure-pipelines/BuildStageVariables.yml@self 28 | 29 | jobs: 30 | - template: azure-pipelines/build.yml 31 | parameters: 32 | Is1ESPT: false 33 | EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }} 34 | RunTests: ${{ parameters.RunTests }} 35 | -------------------------------------------------------------------------------- /azure-pipelines/BuildStageVariables.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 3 | BuildConfiguration: Release 4 | NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/ 5 | # codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ 6 | -------------------------------------------------------------------------------- /azure-pipelines/Get-InsertionPRId.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Look up the pull request URL of the insertion PR. 4 | #> 5 | $stagingFolder = $env:BUILD_STAGINGDIRECTORY 6 | if (!$stagingFolder) { 7 | $stagingFolder = $env:SYSTEM_DEFAULTWORKINGDIRECTORY 8 | if (!$stagingFolder) { 9 | Write-Error "This script must be run in an Azure Pipeline." 10 | exit 1 11 | } 12 | } 13 | $markdownFolder = Join-Path $stagingFolder (Join-Path 'MicroBuild' 'Output') 14 | $markdownFile = Join-Path $markdownFolder 'PullRequestUrl.md' 15 | if (!(Test-Path $markdownFile)) { 16 | Write-Error "This script should be run after the MicroBuildInsertVsPayload task." 17 | exit 2 18 | } 19 | 20 | $insertionPRUrl = Get-Content $markdownFile 21 | if (!($insertionPRUrl -match 'https:.+?/pullrequest/(\d+)')) { 22 | Write-Error "Failed to parse pull request URL: $insertionPRUrl" 23 | exit 3 24 | } 25 | 26 | $Matches[1] 27 | -------------------------------------------------------------------------------- /azure-pipelines/GlobalVariables.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | # These variables are required for MicroBuild tasks 3 | TeamName: VS IDE 4 | TeamEmail: vsidemicrobuild@microsoft.com 5 | # These variables influence insertion pipelines 6 | ContainsVsix: false # This should be true when the repo builds a VSIX that should be inserted to VS. 7 | -------------------------------------------------------------------------------- /azure-pipelines/Install-NuGetPackage.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs a NuGet package. 4 | .PARAMETER PackageID 5 | The Package ID to install. 6 | .PARAMETER Version 7 | The version of the package to install. If unspecified, the latest stable release is installed. 8 | .PARAMETER Source 9 | The package source feed to find the package to install from. 10 | .PARAMETER PackagesDir 11 | The directory to install the package to. By default, it uses the Packages folder at the root of the repo. 12 | .PARAMETER ConfigFile 13 | The nuget.config file to use. By default, it uses :/nuget.config. 14 | .OUTPUTS 15 | System.String. The path to the installed package. 16 | #> 17 | [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Low')] 18 | Param( 19 | [Parameter(Position=1,Mandatory=$true)] 20 | [string]$PackageId, 21 | [Parameter()] 22 | [string]$Version, 23 | [Parameter()] 24 | [string]$Source, 25 | [Parameter()] 26 | [switch]$Prerelease, 27 | [Parameter()] 28 | [string]$PackagesDir="$PSScriptRoot\..\packages", 29 | [Parameter()] 30 | [string]$ConfigFile="$PSScriptRoot\..\nuget.config", 31 | [Parameter()] 32 | [ValidateSet('Quiet','Normal','Detailed')] 33 | [string]$Verbosity='normal' 34 | ) 35 | 36 | $nugetPath = & "$PSScriptRoot\..\tools\Get-NuGetTool.ps1" 37 | 38 | try { 39 | Write-Verbose "Installing $PackageId..." 40 | $nugetArgs = "Install",$PackageId,"-OutputDirectory",$PackagesDir,'-ConfigFile',$ConfigFile 41 | if ($Version) { $nugetArgs += "-Version",$Version } 42 | if ($Source) { $nugetArgs += "-FallbackSource",$Source } 43 | if ($Prerelease) { $nugetArgs += "-Prerelease" } 44 | $nugetArgs += '-Verbosity',$Verbosity 45 | 46 | if ($PSCmdlet.ShouldProcess($PackageId, 'nuget install')) { 47 | $p = Start-Process $nugetPath $nugetArgs -NoNewWindow -Wait -PassThru 48 | if ($null -ne $p.ExitCode -and $p.ExitCode -ne 0) { throw } 49 | } 50 | 51 | # Provide the path to the installed package directory to our caller. 52 | Write-Output (Get-ChildItem "$PackagesDir\$PackageId.*")[0].FullName 53 | } finally { 54 | Pop-Location 55 | } 56 | -------------------------------------------------------------------------------- /azure-pipelines/Merge-CodeCoverage.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | <# 4 | .SYNOPSIS 5 | Merges code coverage reports. 6 | .PARAMETER Path 7 | The path(s) to search for Cobertura code coverage reports. 8 | .PARAMETER Format 9 | The format for the merged result. The default is Cobertura 10 | .PARAMETER OutputDir 11 | The directory the merged result will be written to. The default is `coveragereport` in the root of this repo. 12 | #> 13 | [CmdletBinding()] 14 | Param( 15 | [Parameter(Mandatory=$true)] 16 | [string[]]$Path, 17 | [ValidateSet('Badges', 'Clover', 'Cobertura', 'CsvSummary', 'Html', 'Html_Dark', 'Html_Light', 'HtmlChart', 'HtmlInline', 'HtmlInline_AzurePipelines', 'HtmlInline_AzurePipelines_Dark', 'HtmlInline_AzurePipelines_Light', 'HtmlSummary', 'JsonSummary', 'Latex', 'LatexSummary', 'lcov', 'MarkdownSummary', 'MHtml', 'PngChart', 'SonarQube', 'TeamCitySummary', 'TextSummary', 'Xml', 'XmlSummary')] 18 | [string]$Format='Cobertura', 19 | [string]$OutputFile=("$PSScriptRoot/../coveragereport/merged.cobertura.xml") 20 | ) 21 | 22 | $RepoRoot = [string](Resolve-Path $PSScriptRoot/..) 23 | Push-Location $RepoRoot 24 | try { 25 | Write-Verbose "Searching $Path for *.cobertura.xml files" 26 | $reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml 27 | 28 | if ($reports) { 29 | $reports |% { $_.FullName } |% { 30 | # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. 31 | $xml = [xml](Get-Content -LiteralPath $_) 32 | $xml.coverage.packages.package.classes.class |? { $_.filename} |% { 33 | $_.filename = $_.filename.Replace('{reporoot}', $RepoRoot).Replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) 34 | } 35 | 36 | $xml.Save($_) 37 | } 38 | 39 | $Inputs = $reports |% { Resolve-Path -relative $_.FullName } 40 | 41 | if ((Split-Path $OutputFile) -and -not (Test-Path (Split-Path $OutputFile))) { 42 | New-Item -Type Directory -Path (Split-Path $OutputFile) | Out-Null 43 | } 44 | 45 | & dotnet dotnet-coverage merge $Inputs -o $OutputFile -f cobertura 46 | } else { 47 | Write-Error "No reports found to merge." 48 | } 49 | } finally { 50 | Pop-Location 51 | } 52 | -------------------------------------------------------------------------------- /azure-pipelines/NuGetSbom.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | $(TargetsForTfmSpecificBuildOutput);IncludeSbomInNupkg 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /azure-pipelines/PoliCheckExclusions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | NODE_MODULES|.STORE 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /azure-pipelines/PostPRMessage.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(SupportsShouldProcess = $true)] 2 | param( 3 | [Parameter(Mandatory=$true)] 4 | $AccessToken, 5 | [Parameter(Mandatory=$true)] 6 | $Markdown, 7 | [ValidateSet('Active','ByDesign','Closed','Fixed','Pending','Unknown','WontFix')] 8 | $CommentState='Active' 9 | ) 10 | 11 | # See https://docs.microsoft.com/en-us/dotnet/api/microsoft.teamfoundation.sourcecontrol.webapi.commentthreadstatus?view=azure-devops-dotnet 12 | if ($CommentState -eq 'Active') { 13 | $StatusCode = 1 14 | } elseif ($CommentState -eq 'ByDesign') { 15 | $StatusCode = 5 16 | } elseif ($CommentState -eq 'Closed') { 17 | $StatusCode = 4 18 | } elseif ($CommentState -eq 'Fixed') { 19 | $StatusCode = 2 20 | } elseif ($CommentState -eq 'Pending') { 21 | $StatusCode = 6 22 | } elseif ($CommentState -eq 'Unknown') { 23 | $StatusCode = 0 24 | } elseif ($CommentState -eq 'WontFix') { 25 | $StatusCode = 3 26 | } 27 | 28 | # Build the JSON body up 29 | $body = ConvertTo-Json @{ 30 | comments = @(@{ 31 | parentCommentId = 0 32 | content = $Markdown 33 | commentType = 1 34 | }) 35 | status = $StatusCode 36 | } 37 | 38 | Write-Verbose "Posting JSON payload: `n$Body" 39 | 40 | # Post the message to the Pull Request 41 | # https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20threads?view=azure-devops-rest-5.1 42 | $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/git/repositories/$($env:BUILD_REPOSITORY_NAME)/pullRequests/$($env:SYSTEM_PULLREQUEST_PULLREQUESTID)/threads?api-version=5.1" 43 | if ($PSCmdlet.ShouldProcess($url, 'Post comment via REST call')) { 44 | try { 45 | if (!$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI) { 46 | Write-Error "Posting to the pull request requires that the script is running in an Azure Pipelines context." 47 | exit 1 48 | } 49 | Write-Host "Posting PR comment to: $url" 50 | Invoke-RestMethod -Uri $url -Method POST -Headers @{Authorization = "Bearer $AccessToken"} -Body $Body -ContentType application/json 51 | } 52 | catch { 53 | Write-Error $_ 54 | Write-Error $_.Exception.Message 55 | exit 2 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /azure-pipelines/TSAOptions.json: -------------------------------------------------------------------------------- 1 | { 2 | "tsaVersion": "TsaV2", 3 | "codebase": "NewOrUpdate", 4 | "codebaseName": "LibraryName", 5 | "tsaStamp": "DevDiv", 6 | "tsaEnvironment": "PROD", 7 | "notificationAliases": [ 8 | "vsidemicrobuild@microsoft.com" 9 | ], 10 | "codebaseAdmins": [ 11 | "REDMOND\\andarno" 12 | ], 13 | "instanceUrl": "https://devdiv.visualstudio.com", 14 | "projectName": "DevDiv", 15 | "areaPath": "DevDiv\\VS Core", 16 | "iterationPath": "DevDiv", 17 | "alltools": true, 18 | "repositoryName": "Library.Template" 19 | } 20 | -------------------------------------------------------------------------------- /azure-pipelines/WIFtoPATauth.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: deadPATServiceConnectionId # The GUID of the PAT-based service connection whose access token must be replaced. 3 | type: string 4 | - name: wifServiceConnectionName # The name of the WIF service connection to use to get the access token. 5 | type: string 6 | - name: resource # The scope for which the access token is requested. 7 | type: string 8 | default: 499b84ac-1321-427f-aa17-267ca6975798 # Azure Artifact feeds (any of them) 9 | 10 | steps: 11 | - task: AzureCLI@2 12 | displayName: 🔏 Authenticate with WIF service connection 13 | inputs: 14 | azureSubscription: ${{ parameters.wifServiceConnectionName }} 15 | scriptType: pscore 16 | scriptLocation: inlineScript 17 | inlineScript: | 18 | $accessToken = az account get-access-token --query accessToken --resource '${{ parameters.resource }}' -o tsv 19 | # Set the access token as a secret, so it doesn't get leaked in the logs 20 | Write-Host "##vso[task.setsecret]$accessToken" 21 | # Override the apitoken of the nuget service connection, for the duration of this stage 22 | Write-Host "##vso[task.setendpoint id=${{ parameters.deadPATServiceConnectionId }};field=authParameter;key=apitoken]$accessToken" 23 | -------------------------------------------------------------------------------- /azure-pipelines/apiscan.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: windowsPool 3 | type: object 4 | - name: RealSign 5 | type: boolean 6 | 7 | jobs: 8 | - job: apiscan 9 | displayName: APIScan 10 | dependsOn: Windows 11 | pool: ${{ parameters.windowsPool }} 12 | timeoutInMinutes: 120 13 | templateContext: 14 | ${{ if not(parameters.RealSign) }}: 15 | mb: 16 | signing: # if the build is test-signed, install the signing plugin so that CSVTestSignPolicy.xml is available 17 | enabled: true 18 | zipSources: false 19 | signType: test 20 | outputs: 21 | - output: pipelineArtifact 22 | displayName: 📢 collect apiscan artifact 23 | targetPath: $(Pipeline.Workspace)/.gdn/.r/apiscan/001/Logs 24 | artifactName: apiscan-logs 25 | condition: succeededOrFailed() 26 | variables: 27 | - name: SymbolsFeatureName 28 | value: $[ dependencies.Windows.outputs['SetPipelineVariables.SymbolsFeatureName'] ] 29 | - name: NBGV_MajorMinorVersion 30 | value: $[ dependencies.Windows.outputs['nbgv.NBGV_MajorMinorVersion'] ] 31 | - ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}: 32 | # https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/25351/APIScan-step-by-step-guide-to-setting-up-a-Pipeline 33 | - group: VSEng sponsored APIScan # Expected to provide ApiScanClientId 34 | steps: 35 | # We need TSAOptions.json 36 | - checkout: self 37 | fetchDepth: 1 38 | 39 | - download: current 40 | artifact: APIScanInputs 41 | displayName: 🔻 Download APIScanInputs artifact 42 | 43 | - task: APIScan@2 44 | displayName: 🔍 Run APIScan 45 | inputs: 46 | softwareFolder: $(Pipeline.Workspace)/APIScanInputs 47 | softwareName: $(SymbolsFeatureName) 48 | softwareVersionNum: $(NBGV_MajorMinorVersion) 49 | isLargeApp: false 50 | toolVersion: Latest 51 | preserveLogsFolder: true 52 | env: 53 | AzureServicesAuthConnectionString: runAs=App;AppId=$(ApiScanClientId) 54 | 55 | # File bugs when APIScan finds issues 56 | - task: TSAUpload@2 57 | displayName: 🪳 TSA upload 58 | inputs: 59 | GdnPublishTsaOnboard: True 60 | GdnPublishTsaConfigFile: $(Build.SourcesDirectory)\azure-pipelines\TSAOptions.json 61 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) 62 | -------------------------------------------------------------------------------- /azure-pipelines/dotnet.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: RunTests 3 | - name: IsOptProf 4 | type: boolean 5 | default: false 6 | - name: Is1ESPT 7 | type: boolean 8 | 9 | steps: 10 | 11 | - script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) -warnAsError -warnNotAsError:NU1901,NU1902,NU1903,NU1904 /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" 12 | displayName: 🛠 dotnet build 13 | 14 | - ${{ if not(parameters.IsOptProf) }}: 15 | - powershell: tools/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults 16 | displayName: 🧪 dotnet test 17 | condition: and(succeeded(), ${{ parameters.RunTests }}) 18 | 19 | - ${{ if parameters.IsOptProf }}: 20 | - script: dotnet pack src\VSInsertionMetadata -c $(BuildConfiguration) -warnaserror /bl:"$(Build.ArtifactStagingDirectory)/build_logs/VSInsertion-Pack.binlog" 21 | displayName: 🔧 dotnet pack VSInsertionMetadata 22 | 23 | - powershell: tools/variables/_define.ps1 24 | failOnStderr: true 25 | displayName: ⚙ Update pipeline variables based on build outputs 26 | condition: succeededOrFailed() 27 | 28 | - ${{ if parameters.Is1ESPT }}: 29 | - powershell: azure-pipelines/publish_artifacts.ps1 -StageOnly -AvoidSymbolicLinks -ArtifactNameSuffix "-$(Agent.JobName)" -Verbose 30 | failOnStderr: true 31 | displayName: 📢 Stage artifacts 32 | condition: succeededOrFailed() 33 | - ${{ else }}: 34 | - powershell: azure-pipelines/publish_artifacts.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" -Verbose 35 | failOnStderr: true 36 | displayName: 📢 Publish artifacts 37 | condition: succeededOrFailed() 38 | 39 | - ${{ if and(ne(variables['codecov_token'], ''), parameters.RunTests) }}: 40 | - powershell: | 41 | $ArtifactStagingFolder = & "tools/Get-ArtifactsStagingDirectory.ps1" 42 | $CoverageResultsFolder = Join-Path $ArtifactStagingFolder "coverageResults-$(Agent.JobName)" 43 | tools/publish-CodeCov.ps1 -CodeCovToken "$(codecov_token)" -PathToCodeCoverage "$CoverageResultsFolder" -Name "$(Agent.JobName) Coverage Results" -Flags "$(Agent.JobName)" 44 | displayName: 📢 Publish code coverage results to codecov.io 45 | timeoutInMinutes: 3 46 | continueOnError: true 47 | -------------------------------------------------------------------------------- /azure-pipelines/falsepositives.gdnsuppress: -------------------------------------------------------------------------------- 1 | { 2 | "version": "latest", 3 | "suppressionSets": { 4 | "falsepositives": { 5 | "name": "falsepositives", 6 | "createdDate": "2021-12-03 00:23:08Z", 7 | "lastUpdatedDate": "2021-12-03 00:23:08Z" 8 | } 9 | }, 10 | "results": { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /azure-pipelines/install-dependencies.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: initArgs 3 | type: string 4 | default: '' 5 | - name: needsAzurePublicFeeds 6 | type: boolean 7 | default: true # If nuget.config pulls from the azure-public account, we need to authenticate when building on the devdiv account. 8 | 9 | steps: 10 | - ${{ if and(parameters.needsAzurePublicFeeds, eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9')) }}: 11 | - template: WIFtoPATauth.yml 12 | parameters: 13 | wifServiceConnectionName: azure-public/vside package pull 14 | deadPATServiceConnectionId: 0ae39abc-4d06-4436-a7b5-865833df49db # azure-public/msft_consumption 15 | 16 | - task: NuGetAuthenticate@1 17 | displayName: 🔏 Authenticate NuGet feeds 18 | inputs: 19 | ${{ if and(parameters.needsAzurePublicFeeds, eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9')) }}: 20 | nuGetServiceConnections: azure-public/msft_consumption 21 | 22 | - powershell: | 23 | $AccessToken = '$(System.AccessToken)' # Avoid specifying the access token directly on the init.ps1 command line to avoid it showing up in errors 24 | .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites -NoNuGetCredProvider 25 | dotnet --info 26 | 27 | # Print mono version if it is present. 28 | if (Get-Command mono -ErrorAction SilentlyContinue) { 29 | mono --version 30 | } 31 | displayName: ⚙ Install prerequisites 32 | 33 | - powershell: tools/variables/_define.ps1 34 | failOnStderr: true 35 | displayName: ⚙ Set pipeline variables based on source 36 | name: SetPipelineVariables 37 | -------------------------------------------------------------------------------- /azure-pipelines/integration-test.yml: -------------------------------------------------------------------------------- 1 | jobs: 2 | # Matrix over VS 2019 and VS 2022 3 | 4 | - job: integrationtest 5 | displayName: 🧪 Integration tests 6 | strategy: 7 | matrix: 8 | vs2019: 9 | vmImage: windows-2019 10 | currentSdk: false 11 | vs2022: 12 | vmImage: windows-2022 13 | currentSdk: true 14 | pool: 15 | vmImage: $[ variables['vmImage'] ] 16 | dependsOn: Windows 17 | steps: 18 | - checkout: self 19 | fetchDepth: 1 # no need for git history here 20 | clean: true 21 | - task: CopyFiles@2 22 | inputs: 23 | SourceFolder: integration-tests 24 | Contents: '**' 25 | TargetFolder: $(Pipeline.Workspace)/integration-tests 26 | Overwrite: true 27 | displayName: 🔧 Copy integration tests out of the repo 28 | - download: current 29 | artifact: deployables-Windows 30 | displayName: 🔻 Download nupkg 31 | - pwsh: | 32 | $nupkg = (Get-ChildItem -Path $(Pipeline.Workspace)/deployables-Windows/NuGet -Filter *.nupkg)[0].Name 33 | if ($nupkg -match 'Microsoft\.Windows\.CsWin32\.(.+)\.nupkg') { 34 | $version = $Matches[1] 35 | Write-Host "Will consume Microsoft.Windows.CsWin32 $version" 36 | Write-Host "##vso[task.setvariable variable=NuGetPackageVersion]$version" 37 | } 38 | displayName: 🔧 Consume nupkg 39 | - task: MSBuild@1 40 | displayName: 🧪 MSBuild non-sdk style 41 | inputs: 42 | solution: $(Pipeline.Workspace)\integration-tests\nonsdk\nonsdk.csproj 43 | msbuildArguments: /r 44 | - task: MSBuild@1 45 | displayName: 🧪 MSBuild sdk-style 46 | inputs: 47 | solution: $(Pipeline.Workspace)\integration-tests\sdk\sdk.csproj 48 | msbuildArguments: /r 49 | condition: eq(variables.currentSdk, 'true') 50 | - pwsh: dotnet build 51 | displayName: 🧪 dotnet build 52 | workingDirectory: $(Pipeline.Workspace)\integration-tests\sdk 53 | condition: eq(variables.currentSdk, 'true') 54 | -------------------------------------------------------------------------------- /azure-pipelines/microbuild.after.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: EnableOptProf 3 | type: boolean 4 | default: false 5 | - name: IsOptProf 6 | type: boolean 7 | default: false 8 | - name: SkipCodesignVerify 9 | type: boolean 10 | 11 | steps: 12 | - ${{ if not(parameters.SkipCodesignVerify) }}: # skip CodesignVerify on validation builds because we don't even test-sign nupkg's. 13 | - task: MicroBuildCodesignVerify@3 14 | displayName: 🔍 Verify Signed Files 15 | inputs: 16 | ApprovalListPathForSigs: $(Build.SourcesDirectory)\azure-pipelines\no_strongname.txt 17 | ApprovalListPathForCerts: $(Build.SourcesDirectory)\azure-pipelines\no_authenticode.txt 18 | TargetFolders: | 19 | $(Build.SourcesDirectory)/bin/Packages/$(BuildConfiguration) 20 | condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) 21 | 22 | - ${{ if parameters.IsOptProf }}: 23 | - task: ms-vscs-artifact.build-tasks.artifactDropTask-1.artifactDropTask@0 24 | inputs: 25 | dropServiceURI: https://devdiv.artifacts.visualstudio.com 26 | buildNumber: $(ProfilingInputsDropName) 27 | sourcePath: $(Build.ArtifactStagingDirectory)\OptProf\ProfilingInputs 28 | toLowerCase: false 29 | usePat: true 30 | displayName: 📢 Publish to Artifact Services - ProfilingInputs 31 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) 32 | 33 | - task: PublishBuildArtifacts@1 34 | inputs: 35 | PathtoPublish: $(Build.ArtifactStagingDirectory)/InsertionOutputs 36 | ArtifactName: InsertionOutputs 37 | ArtifactType: Container 38 | displayName: 📢 Publish InsertionOutputs as Azure DevOps artifacts 39 | -------------------------------------------------------------------------------- /azure-pipelines/microbuild.before.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: EnableLocalization 3 | type: boolean 4 | default: false 5 | - name: EnableOptProf 6 | type: boolean 7 | default: false 8 | - name: IsOptProf 9 | type: boolean 10 | default: false 11 | - name: ShouldSkipOptimize 12 | type: boolean 13 | default: false 14 | - name: RealSign 15 | type: boolean 16 | 17 | steps: 18 | - ${{ if and(not(parameters.IsOptProf), ne(variables['Build.Reason'], 'PullRequest')) }}: 19 | # notice@0 requires CG detection to run first, and non-default branches don't inject it automatically. 20 | - ${{ if ne(variables['Build.SourceBranch'], 'refs/heads/main') }}: 21 | - task: ComponentGovernanceComponentDetection@0 22 | displayName: 🔍 Component Detection 23 | 24 | - task: notice@0 25 | displayName: 🛠️ Generate NOTICE file 26 | inputs: 27 | outputfile: $(System.DefaultWorkingDirectory)/obj/NOTICE 28 | outputformat: text 29 | retryCountOnTaskFailure: 3 # fails when the cloud service is overloaded 30 | continueOnError: ${{ not(parameters.RealSign) }} # Tolerate failures when we're not building something that may ship. 31 | 32 | - ${{ if parameters.IsOptProf }}: 33 | # We have to install these plugins ourselves for Optprof runs because those pipelines haven't migrated to 1ES PT yet. 34 | - task: MicroBuildOptProfPlugin@6 35 | inputs: 36 | ProfilingInputsDropName: $(ProfilingInputsDropName) 37 | OptimizationInputsLookupMethod: DropPrefix 38 | DropNamePrefix: OptimizationInputs/$(System.TeamProject)/$(Build.Repository.Name) 39 | ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }} 40 | AccessToken: $(System.AccessToken) 41 | displayName: 🔧 Install OptProf Plugin 42 | 43 | - task: MicroBuildSigningPlugin@4 44 | inputs: 45 | signType: Real 46 | zipSources: false 47 | displayName: 🔧 Install MicroBuild Signing Plugin 48 | 49 | - ${{ if parameters.EnableLocalization }}: 50 | - task: MicroBuildLocalizationPlugin@4 51 | inputs: 52 | languages: $(LocLanguages) 53 | displayName: 🔧 Install MicroBuild Localization Plugin 54 | -------------------------------------------------------------------------------- /azure-pipelines/no_authenticode.txt: -------------------------------------------------------------------------------- 1 | bin\packages\release\vsix\_manifest\manifest.cat,sbom signed 2 | bin\packages\release\vsix\_manifest\spdx_2.2\manifest.cat,sbom signed 3 | *\yamldotnet.dll,oss 4 | -------------------------------------------------------------------------------- /azure-pipelines/no_strongname.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CsWin32/10ff614acb54f6d5a5dbb77c59bd8786e5c99097/azure-pipelines/no_strongname.txt -------------------------------------------------------------------------------- /azure-pipelines/publish-codecoverage.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: EnableMacOSBuild 3 | type: boolean 4 | - name: EnableLinuxBuild 5 | type: boolean 6 | 7 | steps: 8 | - download: current 9 | artifact: coverageResults-Windows 10 | displayName: 🔻 Download Windows code coverage results 11 | continueOnError: true 12 | - ${{ if parameters.EnableLinuxBuild }}: 13 | - download: current 14 | artifact: coverageResults-Linux 15 | displayName: 🔻 Download Linux code coverage results 16 | continueOnError: true 17 | - ${{ if parameters.EnableMacOSBuild }}: 18 | - download: current 19 | artifact: coverageResults-macOS 20 | displayName: 🔻 Download macOS code coverage results 21 | continueOnError: true 22 | - powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputFile coveragereport/merged.cobertura.xml -Format Cobertura -Verbose 23 | displayName: ⚙ Merge coverage 24 | - task: PublishCodeCoverageResults@2 25 | displayName: 📢 Publish code coverage results to Azure DevOps 26 | inputs: 27 | summaryFileLocation: coveragereport/merged.cobertura.xml 28 | failIfCoverageEmpty: true 29 | -------------------------------------------------------------------------------- /azure-pipelines/publish-symbols.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: EnableMacOSBuild 3 | type: boolean 4 | - name: EnableLinuxBuild 5 | type: boolean 6 | 7 | steps: 8 | - task: DownloadPipelineArtifact@2 9 | inputs: 10 | artifact: symbols-Windows 11 | path: $(Pipeline.Workspace)/symbols/Windows 12 | displayName: 🔻 Download Windows symbols 13 | continueOnError: true 14 | - ${{ if parameters.EnableLinuxBuild }}: 15 | - task: DownloadPipelineArtifact@2 16 | inputs: 17 | artifact: symbols-Linux 18 | path: $(Pipeline.Workspace)/symbols/Linux 19 | displayName: 🔻 Download Linux symbols 20 | continueOnError: true 21 | - ${{ if parameters.EnableMacOSBuild }}: 22 | - task: DownloadPipelineArtifact@2 23 | inputs: 24 | artifact: symbols-macOS 25 | path: $(Pipeline.Workspace)/symbols/macOS 26 | displayName: 🔻 Download macOS symbols 27 | continueOnError: true 28 | 29 | - task: DownloadPipelineArtifact@2 30 | inputs: 31 | artifact: test_symbols-Windows 32 | path: $(Pipeline.Workspace)/test_symbols/Windows 33 | displayName: 🔻 Download Windows test symbols 34 | continueOnError: true 35 | - ${{ if parameters.EnableLinuxBuild }}: 36 | - task: DownloadPipelineArtifact@2 37 | inputs: 38 | artifact: test_symbols-Linux 39 | path: $(Pipeline.Workspace)/test_symbols/Linux 40 | displayName: 🔻 Download Linux test symbols 41 | continueOnError: true 42 | - ${{ if parameters.EnableMacOSBuild }}: 43 | - task: DownloadPipelineArtifact@2 44 | inputs: 45 | artifact: test_symbols-macOS 46 | path: $(Pipeline.Workspace)/test_symbols/macOS 47 | displayName: 🔻 Download macOS test symbols 48 | continueOnError: true 49 | 50 | - task: PublishSymbols@2 51 | inputs: 52 | SymbolsFolder: $(Pipeline.Workspace)/symbols 53 | SearchPattern: '**/*.pdb' 54 | IndexSources: false 55 | SymbolServerType: TeamServices 56 | displayName: 📢 Publish symbols 57 | 58 | - task: PublishSymbols@2 59 | inputs: 60 | SymbolsFolder: $(Pipeline.Workspace)/test_symbols 61 | SearchPattern: '**/*.pdb' 62 | IndexSources: false 63 | SymbolServerType: TeamServices 64 | displayName: 📢 Publish test symbols 65 | 66 | - powershell: tools/Prepare-Legacy-Symbols.ps1 -Path $(Pipeline.Workspace)/symbols/Windows 67 | displayName: ⚙ Prepare symbols for symbol archival 68 | -------------------------------------------------------------------------------- /azure-pipelines/publish_artifacts.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script translates all the artifacts described by _all.ps1 4 | into commands that instruct Azure Pipelines to actually collect those artifacts. 5 | #> 6 | 7 | [CmdletBinding()] 8 | param ( 9 | [string]$ArtifactNameSuffix, 10 | [switch]$StageOnly, 11 | [switch]$AvoidSymbolicLinks 12 | ) 13 | 14 | Function Set-PipelineVariable($name, $value) { 15 | if ((Test-Path "Env:\$name") -and (Get-Item "Env:\$name").Value -eq $value) { 16 | return # already set 17 | } 18 | 19 | #New-Item -LiteralPath "Env:\$name".ToUpper() -Value $value -Force | Out-Null 20 | Write-Host "##vso[task.setvariable variable=$name]$value" 21 | } 22 | 23 | Function Test-ArtifactUploaded($artifactName) { 24 | $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())" 25 | Test-Path "env:$varName" 26 | } 27 | 28 | & "$PSScriptRoot/../tools/artifacts/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix -AvoidSymbolicLinks:$AvoidSymbolicLinks |% { 29 | # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts 30 | # will skip this one from a check in the _all.ps1 script. 31 | Set-PipelineVariable "ARTIFACTSTAGED_$($_.Name.ToUpper())" 'true' 32 | Write-Host "Staged artifact $($_.Name) to $($_.Path)" 33 | 34 | if (!$StageOnly) { 35 | if (Test-ArtifactUploaded $_.Name) { 36 | Write-Host "Skipping $($_.Name) because it has already been uploaded." -ForegroundColor DarkGray 37 | } else { 38 | Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" 39 | 40 | # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts 41 | # will skip this one from a check in the _all.ps1 script. 42 | Set-PipelineVariable "ARTIFACTUPLOADED_$($_.Name.ToUpper())" 'true' 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /azure-pipelines/release-deployment-prep.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - download: CI 3 | artifact: Variables-Windows 4 | displayName: 🔻 Download Variables-Windows artifact 5 | - powershell: $(Pipeline.Workspace)/CI/Variables-Windows/_define.ps1 6 | displayName: ⚙️ Set pipeline variables based on artifacts 7 | -------------------------------------------------------------------------------- /azure-pipelines/schedule-only-steps.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - powershell: echo "##vso[build.addbuildtag]auto-insertion" 3 | displayName: Tag for auto-insertion 4 | -------------------------------------------------------------------------------- /azurepipelines-coverage.yml: -------------------------------------------------------------------------------- 1 | # https://learn.microsoft.com/azure/devops/pipelines/test/codecoverage-for-pullrequests?view=azure-devops 2 | coverage: 3 | status: 4 | comments: on # add comment to PRs reporting diff in coverage of modified files 5 | diff: # diff coverage is code coverage only for the lines changed in a pull request. 6 | target: 70% # set this to a desired %. Default is 70% 7 | -------------------------------------------------------------------------------- /docfx/.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | api/ 3 | -------------------------------------------------------------------------------- /docfx/docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "src": "../src/Microsoft.Windows.CsWin32", 7 | "files": [ 8 | "**/*.csproj" 9 | ] 10 | } 11 | ], 12 | "dest": "api" 13 | } 14 | ], 15 | "build": { 16 | "content": [ 17 | { 18 | "files": [ 19 | "**/*.{md,yml}" 20 | ], 21 | "exclude": [ 22 | "_site/**" 23 | ] 24 | } 25 | ], 26 | "resource": [ 27 | { 28 | "files": [ 29 | "images/**" 30 | ] 31 | } 32 | ], 33 | "xref": [ 34 | "https://learn.microsoft.com/en-us/dotnet/.xrefmap.json" 35 | ], 36 | "output": "_site", 37 | "template": [ 38 | "default", 39 | "modern" 40 | ], 41 | "globalMetadata": { 42 | "_appName": "CsWin32", 43 | "_appTitle": "CsWin32", 44 | "_enableSearch": true, 45 | "pdf": false 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /docfx/docs/3rdPartyMetadata.md: -------------------------------------------------------------------------------- 1 | # 3rd party metadata 2 | 3 | CsWin32 comes with dependencies on Windows metadata for the SDK and WDK, allowing C# programs to generate interop code for Windows applications. 4 | But the general transformation from metadata to C# code may be applied to other metadata inputs, allowing you to generate similar metadata for 3rd party native libraries and use CsWin32 to generate C# interop APIs for it. 5 | 6 | ## Constructing metadata for other libraries 7 | 8 | Constructing metadata is outside the scope of this document. 9 | However you may find [the win32metadata architecture](https://github.com/microsoft/win32metadata/blob/main/docs/architecture.md) document instructive. 10 | 11 | ## Hooking metadata into CsWin32 12 | 13 | Metadata is fed into CsWin32 through MSBuild items. 14 | 15 | Item Type | Purpose 16 | --|-- 17 | `ProjectionMetadataWinmd` | Path to the .winmd file. 18 | `ProjectionDocs` | Path to an optional msgpack data file that contains API-level documentation. 19 | `AppLocalAllowedLibraries` | The filename (including extension) of a native library that is allowed to ship in the app directory (as opposed to only %windir%\system32). 20 | 21 | ## Packaging up metadata 22 | 23 | Build a NuGet package with the following layout: 24 | 25 | ``` 26 | buildTransitive\ 27 | YourPackageId.props 28 | yournativelib.winmd 29 | runtimes\ 30 | win-x86\ 31 | yournativelib.dll 32 | win-x64\ 33 | yournativelib.dll 34 | win-arm64\ 35 | yournativelib.dll 36 | ... 37 | ``` 38 | 39 | Your package metadata may want to express a dependency on the Microsoft.Windows.CsWin32 package. 40 | 41 | The `YourPackageId.props` file should include the msbuild items above, as appropriate. 42 | For example: 43 | 44 | ```xml 45 | 46 | 47 | 48 | 49 | 50 | 51 | ``` 52 | 53 | ## Consuming your package 54 | 55 | A project can reference your NuGet package to get both the native dll deployed with their app and the C# interop APIs generated as they require through NativeMethods.txt using CsWin32, just like they can for Win32 APIs. 56 | -------------------------------------------------------------------------------- /docfx/docs/features.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | * Rapidly add P/Invoke methods and supporting types to your C# project. 4 | * No bulky assemblies to ship alongside your application. 5 | * Generate the optimal code for your target framework and C# language version. 6 | * `SafeHandle`-types automatically generated. 7 | * Generates xml documentation based on and links back to docs.microsoft.com 8 | 9 | ![Animation demonstrating p/invoke code generation](../images/demo.gif) 10 | -------------------------------------------------------------------------------- /docfx/docs/toc.yml: -------------------------------------------------------------------------------- 1 | items: 2 | - href: features.md 3 | - href: getting-started.md 4 | - href: 3rdPartyMetadata.md 5 | 6 | -------------------------------------------------------------------------------- /docfx/images/ConfigurationManager_x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CsWin32/10ff614acb54f6d5a5dbb77c59bd8786e5c99097/docfx/images/ConfigurationManager_x64.png -------------------------------------------------------------------------------- /docfx/images/StandardToolbarPlatformSwitcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CsWin32/10ff614acb54f6d5a5dbb77c59bd8786e5c99097/docfx/images/StandardToolbarPlatformSwitcher.png -------------------------------------------------------------------------------- /docfx/images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CsWin32/10ff614acb54f6d5a5dbb77c59bd8786e5c99097/docfx/images/demo.gif -------------------------------------------------------------------------------- /docfx/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | _layout: landing 3 | --- 4 | 5 | # Overview 6 | 7 | This is your docfx landing page. 8 | 9 | Click "Docs" across the top to get started. 10 | -------------------------------------------------------------------------------- /docfx/toc.yml: -------------------------------------------------------------------------------- 1 | items: 2 | - name: Docs 3 | href: docs/ 4 | - name: Source Generator API 5 | href: api/ 6 | - name: GitHub 7 | href: https://github.com/microsoft/CsWin32 8 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.200", 4 | "rollForward": "patch", 5 | "allowPrerelease": false 6 | }, 7 | "msbuild-sdks": { 8 | "Microsoft.Build.NoTargets": "3.7.56" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /init.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | SETLOCAL 3 | set PS1UnderCmd=1 4 | 5 | :: Get the datetime in a format that can go in a filename. 6 | set _my_datetime=%date%_%time% 7 | set _my_datetime=%_my_datetime: =_% 8 | set _my_datetime=%_my_datetime::=% 9 | set _my_datetime=%_my_datetime:/=_% 10 | set _my_datetime=%_my_datetime:.=_% 11 | set CmdEnvScriptPath=%temp%\envvarscript_%_my_datetime%.cmd 12 | 13 | powershell.exe -NoProfile -NoLogo -ExecutionPolicy bypass -Command "try { & '%~dpn0.ps1' %*; exit $LASTEXITCODE } catch { write-host $_; exit 1 }" 14 | 15 | :: Set environment variables in the parent cmd.exe process. 16 | IF EXIST "%CmdEnvScriptPath%" ( 17 | ENDLOCAL 18 | CALL "%CmdEnvScriptPath%" 19 | DEL "%CmdEnvScriptPath%" 20 | ) 21 | -------------------------------------------------------------------------------- /integration-tests/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /integration-tests/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /integration-tests/nonsdk/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /integration-tests/nonsdk/NativeMethods.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file may be blank, but it exercises the analyzer's System.Text.Json and dependencies. 3 | } -------------------------------------------------------------------------------- /integration-tests/nonsdk/NativeMethods.txt: -------------------------------------------------------------------------------- 1 | GetTickCount 2 | -------------------------------------------------------------------------------- /integration-tests/nonsdk/Program.cs: -------------------------------------------------------------------------------- 1 | class Program 2 | { 3 | static void Main(string[] args) 4 | { 5 | Windows.Win32.PInvoke.GetTickCount(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /integration-tests/nonsdk/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ConsoleApp1")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ConsoleApp1")] 13 | [assembly: AssemblyCopyright("Copyright © 2023")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9765d95c-6df9-4cbf-91ee-ad70986830b6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /integration-tests/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /integration-tests/sdk/NativeMethods.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file may be blank, but it exercises the analyzer's System.Text.Json and dependencies. 3 | } -------------------------------------------------------------------------------- /integration-tests/sdk/NativeMethods.txt: -------------------------------------------------------------------------------- 1 | GetTickCount 2 | -------------------------------------------------------------------------------- /integration-tests/sdk/Program.cs: -------------------------------------------------------------------------------- 1 | class Program 2 | { 3 | static void Main(string[] args) 4 | { 5 | Windows.Win32.PInvoke.GetTickCount(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /integration-tests/sdk/sdk.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0-windows 6 | 9 7 | 8 | 9 | 10 | 11 | $(NuGetPackageVersion) 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | all 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /settings.VisualStudio.json: -------------------------------------------------------------------------------- 1 | { 2 | "textEditor.codeCleanup.profile": "profile1" 3 | } 4 | -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # SA1600: Elements should be documented 4 | dotnet_diagnostic.SA1600.severity = silent 5 | -------------------------------------------------------------------------------- /src/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma warning disable IDE0005 // Using directive is unnecessary. 5 | using System.Runtime.InteropServices; 6 | #pragma warning restore IDE0005 // Using directive is unnecessary. 7 | 8 | [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] 9 | -------------------------------------------------------------------------------- /src/AssemblyInfo.vb: -------------------------------------------------------------------------------- 1 | ' Copyright (c) Microsoft Corporation. All rights reserved. 2 | ' Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | Imports System.Runtime.InteropServices 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | README.md 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/AnalyzerReleases.Shipped.md: -------------------------------------------------------------------------------- 1 | ; Shipped analyzer releases 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/AnalyzerReleases.Unshipped.md: -------------------------------------------------------------------------------- 1 | ; Unshipped analyzer release 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | 4 | ### New Rules 5 | Rule ID | Category | Severity | Notes 6 | --------|----------|----------|------- 7 | PInvoke000 | Functionality | Error | SourceGenerator 8 | PInvoke001 | Functionality | Warning | SourceGenerator 9 | PInvoke002 | Functionality | Warning | SourceGenerator 10 | PInvoke003 | Functionality | Warning | SourceGenerator 11 | PInvoke004 | Functionality | Warning | SourceGenerator 12 | PInvoke005 | Functionality | Warning | SourceGenerator 13 | PInvoke006 | Configuration | Warning | SourceGenerator 14 | PInvoke007 | Functionality | Error | SourceGenerator 15 | PInvoke008 | Configuration | Error | SourceGenerator -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/ArrayTypeHandleInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | internal record ArrayTypeHandleInfo(TypeHandleInfo ElementType, ArrayShape Shape) : TypeHandleInfo, ITypeHandleContainer 7 | { 8 | public override string ToString() => this.ToTypeSyntaxForDisplay().ToString(); 9 | 10 | internal override TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes) 11 | { 12 | TypeSyntaxAndMarshaling element = this.ElementType.ToTypeSyntax(inputs, forElement, customAttributes); 13 | if (inputs.AllowMarshaling || inputs.IsField) 14 | { 15 | ArrayTypeSyntax arrayType = ArrayType(element.Type, SingletonList(ArrayRankSpecifier().AddSizes(this.Shape.Sizes.Select(size => LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(size))).ToArray()))); 16 | MarshalAsAttribute? marshalAs = element.MarshalAsAttribute is object ? new MarshalAsAttribute(UnmanagedType.LPArray) { ArraySubType = element.MarshalAsAttribute.Value } : null; 17 | return new TypeSyntaxAndMarshaling(arrayType, marshalAs, element.NativeArrayInfo); 18 | } 19 | else 20 | { 21 | return new TypeSyntaxAndMarshaling(PointerType(element.Type)); 22 | } 23 | } 24 | 25 | internal override bool? IsValueType(TypeSyntaxSettings inputs) => false; 26 | } 27 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/BindingRedirects.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | internal static class BindingRedirects 7 | { 8 | private static readonly string SourceGeneratorAssemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 9 | private static readonly Lazy> LocalAssemblies; 10 | 11 | static BindingRedirects() 12 | { 13 | LocalAssemblies = new Lazy>( 14 | () => Directory.GetFiles(SourceGeneratorAssemblyDirectory, "*.dll").ToDictionary(Path.GetFileNameWithoutExtension, StringComparer.OrdinalIgnoreCase)); 15 | } 16 | 17 | private static bool IsNetFramework => RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase); 18 | 19 | #pragma warning disable CA2255 // The 'ModuleInitializer' attribute should not be used in libraries 20 | [ModuleInitializer] 21 | #pragma warning restore CA2255 // The 'ModuleInitializer' attribute should not be used in libraries 22 | internal static void ApplyBindingRedirects() 23 | { 24 | if (IsNetFramework) 25 | { 26 | AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; 27 | } 28 | } 29 | 30 | private static Assembly? CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 31 | { 32 | AssemblyName expected = new(args.Name); 33 | if (LocalAssemblies.Value.TryGetValue(expected.Name, out string? path)) 34 | { 35 | var actual = AssemblyName.GetAssemblyName(path); 36 | if (actual.Version >= expected.Version) 37 | { 38 | return Assembly.LoadFile(path); 39 | } 40 | } 41 | 42 | return null; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/CustomAttributeTypeProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; 5 | 6 | namespace Microsoft.Windows.CsWin32; 7 | 8 | internal class CustomAttributeTypeProvider : ICustomAttributeTypeProvider 9 | { 10 | internal static readonly CustomAttributeTypeProvider Instance = new CustomAttributeTypeProvider(); 11 | 12 | private CustomAttributeTypeProvider() 13 | { 14 | } 15 | 16 | public TypeSyntax GetPrimitiveType(PrimitiveTypeCode typeCode) => PrimitiveTypeHandleInfo.ToTypeSyntax(typeCode, preferNativeInt: false); 17 | 18 | public TypeSyntax GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind) 19 | { 20 | // CONSIDER: reuse GetNestingQualifiedName (with namespace support added) here. 21 | TypeReference tr = reader.GetTypeReference(handle); 22 | string name = reader.GetString(tr.Name); 23 | string ns = reader.GetString(tr.Namespace); 24 | return ParseName(ns + "." + name); 25 | } 26 | 27 | public TypeSyntax GetTypeFromSerializedName(string name) => ParseName(name.IndexOf(',') is int index && index >= 0 ? name.Substring(0, index) : name); 28 | 29 | public PrimitiveTypeCode GetUnderlyingEnumType(TypeSyntax type) => PrimitiveTypeCode.Int32; // an assumption that works for now. 30 | 31 | public bool IsSystemType(TypeSyntax type) => type is QualifiedNameSyntax { Left: IdentifierNameSyntax { Identifier: { ValueText: "System" } }, Right: { Identifier: { ValueText: "Type" } } }; 32 | 33 | public TypeSyntax GetSystemType() => throw new NotImplementedException(); 34 | 35 | public TypeSyntax GetSZArrayType(TypeSyntax elementType) => throw new NotImplementedException(); 36 | 37 | public TypeSyntax GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind) => throw new NotImplementedException(); 38 | } 39 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/GenerationFailedException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | /// 7 | /// An exception thrown when code generation fails. 8 | /// 9 | [Serializable] 10 | public class GenerationFailedException : Exception 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public GenerationFailedException() 16 | { 17 | } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// 23 | public GenerationFailedException(string message) 24 | : base(message) 25 | { 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// 32 | public GenerationFailedException(string message, Exception inner) 33 | : base(message, inner) 34 | { 35 | } 36 | 37 | /// 38 | /// Initializes a new instance of the class. 39 | /// 40 | /// 41 | protected GenerationFailedException( 42 | System.Runtime.Serialization.SerializationInfo info, 43 | System.Runtime.Serialization.StreamingContext context) 44 | : base(info, context) 45 | { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/GeneratorExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | /// 7 | /// Extension methods for the interface. 8 | /// 9 | public static class GeneratorExtensions 10 | { 11 | /// 12 | public static bool TryGenerate(this IGenerator generator, string apiNameOrModuleWildcard, CancellationToken cancellationToken) => generator.TryGenerate(apiNameOrModuleWildcard, out _, cancellationToken); 13 | 14 | /// 15 | public static bool TryGenerateType(this IGenerator generator, string possiblyQualifiedName) => generator.TryGenerateType(possiblyQualifiedName, out _); 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | global using System.Collections.Immutable; 5 | global using System.Diagnostics; 6 | global using System.Diagnostics.CodeAnalysis; 7 | global using System.Globalization; 8 | global using System.Reflection; 9 | global using System.Reflection.Metadata; 10 | global using System.Runtime.CompilerServices; 11 | global using System.Runtime.InteropServices; 12 | global using System.Text; 13 | global using Microsoft.CodeAnalysis; 14 | global using Microsoft.CodeAnalysis.CSharp; 15 | global using Microsoft.CodeAnalysis.CSharp.Syntax; 16 | global using Microsoft.Windows.SDK.Win32Docs; 17 | global using static System.FormattableString; 18 | global using static Microsoft.Windows.CsWin32.FastSyntaxFactory; 19 | global using static Microsoft.Windows.CsWin32.SimpleSyntaxFactory; 20 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/ITypeHandleContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | internal interface ITypeHandleContainer 7 | { 8 | TypeHandleInfo ElementType { get; } 9 | } 10 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/MetadataCache.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | internal class MetadataCache 7 | { 8 | internal static readonly MetadataCache Default = new(); 9 | 10 | private readonly Dictionary metadataFiles = new(StringComparer.OrdinalIgnoreCase); 11 | 12 | /// 13 | /// Gets a file accessor for the given path that supports many concurrent readers. 14 | /// 15 | /// The path to the .winmd file. 16 | /// The file accessor. 17 | internal MetadataFile GetMetadataFile(string path) 18 | { 19 | lock (this.metadataFiles) 20 | { 21 | MetadataFile? metadataFile; 22 | DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(path); 23 | if (this.metadataFiles.TryGetValue(path, out metadataFile)) 24 | { 25 | if (metadataFile.LastWriteTimeUtc == lastWriteTimeUtc) 26 | { 27 | // We already have the file, and it is still current. Happy path. 28 | return metadataFile; 29 | } 30 | 31 | // Stale file. Evict from the cache. 32 | this.metadataFiles.Remove(path); 33 | metadataFile.Dispose(); 34 | } 35 | 36 | // New or updated file. Re-open. 37 | this.metadataFiles.Add(path, metadataFile = new MetadataFile(path)); 38 | return metadataFile; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/MetadataQualifiedTokens.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | internal record struct QualifiedTypeReferenceHandle(Generator Generator, TypeReferenceHandle ReferenceHandle) 7 | { 8 | internal MetadataReader Reader => this.Generator.Reader; 9 | 10 | internal QualifiedTypeReference Resolve() => new(this.Generator, this.Generator.Reader.GetTypeReference(this.ReferenceHandle)); 11 | } 12 | 13 | internal record struct QualifiedTypeReference(Generator Generator, TypeReference Reference) 14 | { 15 | internal MetadataReader Reader => this.Generator.Reader; 16 | } 17 | 18 | internal record struct QualifiedTypeDefinitionHandle(Generator Generator, TypeDefinitionHandle DefinitionHandle) 19 | { 20 | internal MetadataReader Reader => this.Generator.Reader; 21 | 22 | internal QualifiedTypeDefinition Resolve() => new(this.Generator, this.Generator.Reader.GetTypeDefinition(this.DefinitionHandle)); 23 | } 24 | 25 | internal record struct QualifiedTypeDefinition(Generator Generator, TypeDefinition Definition) 26 | { 27 | internal MetadataReader Reader => this.Generator.Reader; 28 | } 29 | 30 | internal record struct QualifiedMethodDefinitionHandle(Generator Generator, MethodDefinitionHandle MethodHandle) 31 | { 32 | internal MetadataReader Reader => this.Generator.Reader; 33 | 34 | internal QualifiedMethodDefinition Resolve() => new(this.Generator, this.Generator.Reader.GetMethodDefinition(this.MethodHandle)); 35 | } 36 | 37 | internal record struct QualifiedMethodDefinition(Generator Generator, MethodDefinition Method) 38 | { 39 | internal MetadataReader Reader => this.Generator.Reader; 40 | } 41 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/Microsoft.Windows.CsWin32.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | true 5 | netstandard2.0 6 | enable 7 | 8 | 9 | false 10 | false 11 | true 12 | $(NoWarn);NU5128;NU5127;NU5104 13 | Microsoft.Windows.CsWin32.nuspec 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | true 24 | build\ 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | all 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/ModuleInitializerAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace System.Runtime.CompilerServices; 5 | 6 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] 7 | internal sealed class ModuleInitializerAttribute : Attribute 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/NamespaceMetadata.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | /// 7 | /// An immutable index into metadata. 8 | /// 9 | /// 10 | /// This class must not contain definitions. It may contain handles. See devremarks for details. 11 | /// 12 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] 13 | internal class NamespaceMetadata 14 | { 15 | internal NamespaceMetadata(string name) 16 | { 17 | this.Name = name; 18 | } 19 | 20 | public string Name { get; } 21 | 22 | public bool IsEmpty => this.Fields.Count == 0 && this.Methods.Count == 0 && this.Types.Count == 0; 23 | 24 | internal Dictionary Fields { get; } = new(StringComparer.Ordinal); 25 | 26 | internal Dictionary Methods { get; } = new(StringComparer.Ordinal); 27 | 28 | internal Dictionary Types { get; } = new(StringComparer.Ordinal); 29 | 30 | internal HashSet MethodsForOtherPlatform { get; } = new HashSet(StringComparer.Ordinal); 31 | 32 | internal HashSet TypesForOtherPlatform { get; } = new HashSet(StringComparer.Ordinal); 33 | 34 | private string DebuggerDisplay => $"{this.Name} (Constants: {this.Fields.Count}, Methods: {this.Methods.Count}, Types: {this.Types.Count}"; 35 | } 36 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/PlatformIncompatibleException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | /// 7 | /// An exception thrown when code generation fails because the requested type or member is not available given the target CPU architecture. 8 | /// 9 | [Serializable] 10 | public class PlatformIncompatibleException : GenerationFailedException 11 | { 12 | /// 13 | /// Initializes a new instance of the class. 14 | /// 15 | public PlatformIncompatibleException() 16 | { 17 | } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// 23 | public PlatformIncompatibleException(string message) 24 | : base(message) 25 | { 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// 32 | public PlatformIncompatibleException(string message, Exception inner) 33 | : base(message, inner) 34 | { 35 | } 36 | 37 | /// 38 | /// Initializes a new instance of the class. 39 | /// 40 | /// 41 | protected PlatformIncompatibleException( 42 | System.Runtime.Serialization.SerializationInfo info, 43 | System.Runtime.Serialization.StreamingContext context) 44 | : base(info, context) 45 | { 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/README.md: -------------------------------------------------------------------------------- 1 | # Automated generation of C# bindings for the Win32 API 2 | 3 | Get immediate access to the full Win32 API from C#, just by naming the APIs you require. 4 | Generated APIs will be accurate for your CPU architecture and target Windows version. 5 | All APIs are generated directly into your project, allowing you to ship without any additional runtime dependencies. 6 | 7 | Reach functionality that .NET doesn't expose via the Base Class Library (BCL) to give your library or application that feature that really sets it apart. 8 | 9 | Install this package, then create a NativeMethods.txt file with a list of any APIs you need for example: 10 | 11 | NativeMethods.txt: 12 | 13 | ``` 14 | CreateFile 15 | IUIRibbon 16 | S_OK 17 | NTSTATUS 18 | IsPwrHibernateAllowed 19 | ISpellChecker 20 | `````` 21 | 22 | Any supporting APIs (e.g. enums, structs) are automatically generated when they are required by what you've directly asked for. 23 | 24 | Call extern methods through the `PInvoke` class 25 | 26 | ```cs 27 | using SafeHandle f = PInvoke.CreateFile( 28 | "some.txt", 29 | (uint)GENERIC_ACCESS_RIGHTS.GENERIC_READ, 30 | FILE_SHARE_MODE.FILE_SHARE_READ, 31 | lpSecurityAttributes: null, 32 | FILE_CREATION_DISPOSITION.CREATE_ALWAYS, 33 | FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, 34 | hTemplateFile: null); 35 | ``` 36 | 37 | Learn more from [our README on GitHub](https://github.com/microsoft/CsWin32#readme). 38 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/Rental.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | internal struct Rental : IDisposable 7 | where T : class 8 | { 9 | private Action? disposeAction; 10 | private T? value; 11 | private object? state; 12 | 13 | internal Rental(T value, Action disposeAction, object? state) 14 | { 15 | this.value = value; 16 | this.disposeAction = disposeAction; 17 | this.state = state; 18 | } 19 | 20 | public T Value => this.value ?? throw new ObjectDisposedException(this.GetType().FullName); 21 | 22 | public void Dispose() 23 | { 24 | T? value = this.value; 25 | this.value = null; 26 | if (value is not null) 27 | { 28 | this.disposeAction?.Invoke(value, this.state); 29 | } 30 | 31 | this.disposeAction = null; 32 | this.state = null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/TypeHandleInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | internal abstract record TypeHandleInfo 7 | { 8 | private static readonly TypeSyntaxSettings DebuggerDisplaySettings = new TypeSyntaxSettings(null, PreferNativeInt: false, PreferMarshaledTypes: false, AllowMarshaling: false, QualifyNames: true); 9 | 10 | internal bool IsConstantField { get; init; } 11 | 12 | internal abstract TypeSyntaxAndMarshaling ToTypeSyntax(TypeSyntaxSettings inputs, Generator.GeneratingElement forElement, CustomAttributeHandleCollection? customAttributes, ParameterAttributes parameterAttributes = default); 13 | 14 | internal abstract bool? IsValueType(TypeSyntaxSettings inputs); 15 | 16 | protected static bool TryGetSimpleName(TypeSyntax nameSyntax, [NotNullWhen(true)] out string? simpleName) 17 | { 18 | if (nameSyntax is QualifiedNameSyntax qname) 19 | { 20 | simpleName = qname.Right.Identifier.ValueText; 21 | } 22 | else if (nameSyntax is SimpleNameSyntax simple) 23 | { 24 | simpleName = simple.Identifier.ValueText; 25 | } 26 | else 27 | { 28 | simpleName = null; 29 | return false; 30 | } 31 | 32 | return true; 33 | } 34 | 35 | protected TypeSyntax ToTypeSyntaxForDisplay() => this.ToTypeSyntax(DebuggerDisplaySettings, Generator.GeneratingElement.Other, null).Type; 36 | 37 | protected Generator.Context GetContext(TypeSyntaxSettings inputs) => inputs.Generator is not null 38 | ? inputs.Generator.DefaultContext with { AllowMarshaling = inputs.AllowMarshaling } 39 | : new() { AllowMarshaling = inputs.AllowMarshaling }; 40 | } 41 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/TypeSyntaxSettings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.CsWin32; 5 | 6 | internal record TypeSyntaxSettings( 7 | Generator? Generator, 8 | bool PreferNativeInt, 9 | bool PreferMarshaledTypes, 10 | bool AllowMarshaling, 11 | bool QualifyNames, 12 | bool IsField = false, 13 | bool PreferInOutRef = false, 14 | bool AvoidWinmdRootAlias = false) 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/build/Microsoft.Windows.CsWin32.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | @(ProjectionMetadataWinmd->'%(FullPath)','|') 24 | @(ProjectionDocs->'%(FullPath)','|') 25 | @(AppLocalAllowedLibraries->'%(FullPath)','|') 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/build/net20/Microsoft.Windows.CsWin32.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/build/netstandard1.0/Microsoft.Windows.CsWin32.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/readme.txt: -------------------------------------------------------------------------------- 1 | Microsoft Windows SDK Win32 API Source Generator 2 | ================================================== 3 | 4 | This package contains a source generator to add a user-defined set of Win32 P/Invoke 5 | methods and supporting types to a C# project. 6 | 7 | To get started, create a "NativeMethods.txt" file in your project directory 8 | that lists the names of Win32 APIs for which you need to have generated, one per line. 9 | 10 | You should also install the `System.Memory` package when targeting .NET Framework 4.5+ or .NET Standard 2.0, 11 | as that adds APIs that significantly improve much of the code generated by CsWin32: 12 | 13 | ```ps1 14 | dotnet add package System.Memory 15 | dotnet add package System.Runtime.CompilerServices.Unsafe 16 | ``` 17 | 18 | Projects targeting .NET Core 2.1+ or .NET 5+ do *not* need to add these package references, 19 | although it is harmless to do so. 20 | 21 | Note that while the `System.Memory` package depends on the `System.Runtime.CompilerServices.Unsafe` package, 22 | referencing the latter directly is still important to get the latest version of the APIs it provides. 23 | 24 | Your project must allow unsafe code to support the generated code that will likely use pointers. 25 | 26 | Learn more from our README on GitHub: https://github.com/microsoft/CsWin32#readme 27 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | indent_style = tab 3 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/BOOL.cs: -------------------------------------------------------------------------------- 1 | partial struct BOOL 2 | { 3 | internal BOOL(bool value) => this.Value = value ? 1 : 0; 4 | public static implicit operator bool(BOOL value) => value.Value != 0; 5 | public static implicit operator BOOL(bool value) => new BOOL(value); 6 | } 7 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/BOOLEAN.cs: -------------------------------------------------------------------------------- 1 | partial struct BOOLEAN 2 | { 3 | internal BOOLEAN(bool value) => this.Value = value ? (byte)1 : (byte)0; 4 | public static implicit operator bool(BOOLEAN value) => value.Value != 0; 5 | public static implicit operator BOOLEAN(bool value) => new BOOLEAN(value); 6 | } 7 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/BSTR.cs: -------------------------------------------------------------------------------- 1 | internal partial struct BSTR 2 | { 3 | /// 4 | /// Gets the length of the BSTR in characters. 5 | /// 6 | internal unsafe int Length => this.Value is null ? 0 : checked((int)(*(((uint*)this.Value) - 1) / sizeof(char))); 7 | 8 | public override string ToString() => this.Value != null ? Marshal.PtrToStringBSTR(new IntPtr(this.Value)) : null; 9 | 10 | #if canUseSpan 11 | public static unsafe implicit operator ReadOnlySpan(BSTR bstr) => bstr.Value != null ? new ReadOnlySpan(bstr.Value, *((int*)bstr.Value - 1) / 2) : default(ReadOnlySpan); 12 | 13 | internal ReadOnlySpan AsSpan() => this; 14 | #endif 15 | } 16 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/ComHelpers.cs: -------------------------------------------------------------------------------- 1 | internal static unsafe partial class ComHelpers 2 | { 3 | private static readonly winmdroot.Foundation.HRESULT COR_E_OBJECTDISPOSED = (winmdroot.Foundation.HRESULT)unchecked((int)0x80131622); 4 | private static readonly winmdroot.Foundation.HRESULT S_OK = (winmdroot.Foundation.HRESULT)0; 5 | 6 | internal static winmdroot.Foundation.HRESULT UnwrapCCW(TThis* @this, out TInterface @object) 7 | where TThis : unmanaged 8 | where TInterface : class 9 | { 10 | @object = ComWrappers.ComInterfaceDispatch.GetInstance((ComWrappers.ComInterfaceDispatch*)@this); 11 | return @object is null ? COR_E_OBJECTDISPOSED : S_OK; 12 | } 13 | 14 | #if canUseInterfaceStaticMembers 15 | internal static void PopulateIUnknown(System.Com.IUnknown.Vtbl* vtable) 16 | where TComInterface : unmanaged 17 | { 18 | PopulateIUnknownImpl(vtable); 19 | if (vtable->QueryInterface_1 is null) 20 | { 21 | throw new NotImplementedException("v-tables cannot be accessed unless the Windows.Win32.ComHelpers.PopulateIUnknownImpl partial method is implemented."); 22 | } 23 | } 24 | 25 | static partial void PopulateIUnknownImpl(System.Com.IUnknown.Vtbl* vtable) 26 | where TComInterface : unmanaged; 27 | #endif 28 | } 29 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/DECIMAL.cs: -------------------------------------------------------------------------------- 1 | internal partial struct DECIMAL 2 | { 3 | public DECIMAL(decimal value) 4 | { 5 | unchecked 6 | { 7 | const int SignMask = (int)0x80000000; 8 | #if NET5_0_OR_GREATER 9 | Span bits = stackalloc int[4]; 10 | decimal.GetBits(value, bits); 11 | #else 12 | int[] bits = decimal.GetBits(value); 13 | #endif 14 | uint lo32 = (uint)bits[0]; 15 | uint mid32 = (uint)bits[1]; 16 | uint hi32 = (uint)bits[2]; 17 | byte scale = (byte)(bits[3] >> 16); 18 | byte sign = (bits[3] & SignMask) == SignMask ? (byte)0x80 : (byte)0x00; 19 | this.Anonymous2 = new _Anonymous2_e__Union() { Anonymous = new _Anonymous2_e__Union._Anonymous_e__Struct() { Lo32 = lo32, Mid32 = mid32 } }; 20 | this.Hi32 = hi32; 21 | this.Anonymous1 = new _Anonymous1_e__Union() { Anonymous = new _Anonymous1_e__Union._Anonymous_e__Struct() { scale = scale, sign = sign } }; 22 | this.wReserved = 0; 23 | } 24 | } 25 | 26 | public static implicit operator decimal(DECIMAL value) 27 | { 28 | return new decimal( 29 | (int)value.Anonymous2.Anonymous.Lo32, 30 | (int)value.Anonymous2.Anonymous.Mid32, 31 | (int)value.Hi32, 32 | value.Anonymous1.Anonymous.sign == 0x80, 33 | value.Anonymous1.Anonymous.scale); 34 | } 35 | 36 | #if NET5_0_OR_GREATER 37 | public static implicit operator DECIMAL(decimal value) => new DECIMAL(value); 38 | #endif 39 | } 40 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/IUnknownHelperMethods.cs: -------------------------------------------------------------------------------- 1 | internal class IUnknownHelperMethods 2 | { 3 | internal unsafe global::Windows.Win32.Foundation.HRESULT QueryInterface(out T* ppv) 4 | where T : unmanaged 5 | { 6 | Guid guid = typeof(T).GUID; 7 | void* pv; 8 | var hr = this.QueryInterface(&guid, &pv); 9 | if (hr.Succeeded) 10 | { 11 | ppv = (T*)pv; 12 | } 13 | else 14 | { 15 | ppv = null; 16 | } 17 | 18 | return hr; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/IVTable.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// Non generic interface that allows constraining against a COM wrapper type directly. COM structs should 3 | /// implement . 4 | /// 5 | internal unsafe interface IVTable 6 | { 7 | static abstract System.Com.IUnknown.Vtbl* VTable { get; } 8 | } 9 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/IVTable`2.cs: -------------------------------------------------------------------------------- 1 | internal unsafe interface IVTable : IVTable 2 | where TVTable : unmanaged 3 | where TComInterface : unmanaged, IVTable 4 | { 5 | private protected static abstract void PopulateVTable(TVTable* vtable); 6 | 7 | static System.Com.IUnknown.Vtbl* IVTable.VTable { get; } = (System.Com.IUnknown.Vtbl*)CreateVTable(); 8 | 9 | private static TVTable* CreateVTable() 10 | { 11 | TVTable* vtbl = (TVTable*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(TVTable), sizeof(TVTable)); 12 | ComHelpers.PopulateIUnknown((System.Com.IUnknown.Vtbl*)vtbl); 13 | TComInterface.PopulateVTable(vtbl); 14 | return vtbl; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/NTSTATUS.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// Win32 return error codes. 3 | /// 4 | /// 5 | /// This values come from https://msdn.microsoft.com/en-us/library/cc704588.aspx 6 | /// Values are 32 bit values laid out as follows: 7 | /// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 8 | /// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 | /// +---+-+-+-----------------------+-------------------------------+ 10 | /// |Sev|C|R| Facility | Code | 11 | /// +---+-+-+-----------------------+-------------------------------+ 12 | /// where 13 | /// Sev - is the severity code 14 | /// 00 - Success 15 | /// 01 - Informational 16 | /// 10 - Warning 17 | /// 11 - Error 18 | /// C - is the Customer code flag 19 | /// R - is a reserved bit 20 | /// Facility - is the facility code 21 | /// Code - is the facility's status code 22 | /// 23 | /// FacilityCodes 0x5 - 0xF have been allocated by various drivers. 24 | /// The success status codes 0 - 63 are reserved for wait completion status. 25 | /// 26 | partial struct NTSTATUS 27 | { 28 | public static implicit operator uint(NTSTATUS value) => (uint)value.Value; 29 | public static explicit operator NTSTATUS(uint value) => new NTSTATUS((int)value); 30 | 31 | internal Severity SeverityCode => (Severity)(((uint)this.Value & 0xc0000000) >> 30); 32 | 33 | internal enum Severity 34 | { 35 | Success, 36 | Informational, 37 | Warning, 38 | Error, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/OverloadResolutionPriorityAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace System.Runtime.CompilerServices 2 | { 3 | /// 4 | /// Specifies the priority of a member in overload resolution. 5 | /// When unspecified, the default priority is 0. 6 | /// 7 | [global::System.AttributeUsage(global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Method | global::System.AttributeTargets.Property, AllowMultiple = false, Inherited = false)] 8 | internal sealed class OverloadResolutionPriorityAttribute : global::System.Attribute 9 | { 10 | /// 11 | /// Initializes a new instance of the class. 12 | /// 13 | /// The priority of the attributed member. Higher numbers are prioritized, lower numbers are deprioritized. 0 is the default if no attribute is present. 14 | public OverloadResolutionPriorityAttribute(int priority) 15 | { 16 | this.Priority = priority; 17 | } 18 | 19 | /// 20 | /// The priority of the member. 21 | /// 22 | public int Priority { get; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PCSTR.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// A pointer to a null-terminated, constant, ANSI character string. 3 | /// 4 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] 5 | internal unsafe readonly partial struct PCSTR 6 | : IEquatable 7 | { 8 | /// 9 | /// A pointer to the first character in the string. The content should be considered readonly, as it was typed as constant in the SDK. 10 | /// 11 | internal readonly byte* Value; 12 | internal PCSTR(byte* value) => this.Value = value; 13 | public static implicit operator byte*(PCSTR value) => value.Value; 14 | public static explicit operator PCSTR(byte* value) => new PCSTR(value); 15 | public bool Equals(PCSTR other) => this.Value == other.Value; 16 | public override bool Equals(object obj) => obj is PCSTR other && this.Equals(other); 17 | public override int GetHashCode() => unchecked((int)this.Value); 18 | 19 | /// 20 | /// Gets the number of characters up to the first null character (exclusive). 21 | /// 22 | internal int Length 23 | { 24 | get 25 | { 26 | byte* p = this.Value; 27 | if (p is null) 28 | return 0; 29 | while (*p != 0) 30 | p++; 31 | return checked((int)(p - this.Value)); 32 | } 33 | } 34 | 35 | /// 36 | /// Returns a with a copy of this character array, decoding as UTF-8. 37 | /// 38 | /// A , or if is . 39 | public override string ToString() => this.Value is null ? null : new string((sbyte*)this.Value, 0, this.Length, global::System.Text.Encoding.Default); 40 | 41 | #if canUseSpan 42 | /// 43 | /// Returns a span of the characters in this string, up to the first null character (exclusive). 44 | /// 45 | internal ReadOnlySpan AsSpan() => this.Value is null ? default(ReadOnlySpan) : new ReadOnlySpan(this.Value, this.Length); 46 | #endif 47 | 48 | private string DebuggerDisplay => this.ToString(); 49 | } 50 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PCWSTR.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// A pointer to a null-terminated, constant character string. 3 | /// 4 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] 5 | internal unsafe readonly partial struct PCWSTR 6 | : IEquatable 7 | { 8 | /// 9 | /// A pointer to the first character in the string. The content should be considered readonly, as it was typed as constant in the SDK. 10 | /// 11 | internal readonly char* Value; 12 | internal PCWSTR(char* value) => this.Value = value; 13 | public static explicit operator char*(PCWSTR value) => value.Value; 14 | public static implicit operator PCWSTR(char* value) => new PCWSTR(value); 15 | public bool Equals(PCWSTR other) => this.Value == other.Value; 16 | public override bool Equals(object obj) => obj is PCWSTR other && this.Equals(other); 17 | public override int GetHashCode() => unchecked((int)this.Value); 18 | 19 | /// 20 | /// Gets the number of characters up to the first null character (exclusive). 21 | /// 22 | internal int Length 23 | { 24 | get 25 | { 26 | char* p = this.Value; 27 | if (p is null) 28 | return 0; 29 | while (*p != '\0') 30 | p++; 31 | return checked((int)(p - this.Value)); 32 | } 33 | } 34 | 35 | /// 36 | /// Returns a with a copy of this character array, up to the first null character (exclusive). 37 | /// 38 | /// A , or if is . 39 | public override string ToString() => this.Value is null ? null : new string(this.Value); 40 | 41 | #if canUseSpan 42 | /// 43 | /// Returns a span of the characters in this string, up to the first null character (exclusive). 44 | /// 45 | internal ReadOnlySpan AsSpan() => this.Value is null ? default(ReadOnlySpan) : new ReadOnlySpan(this.Value, this.Length); 46 | #endif 47 | 48 | private string DebuggerDisplay => this.ToString(); 49 | } 50 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PCZZSTR.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// A pointer to a constant, empty-string terminated list of null-terminated strings with 1-byte characters (often UTF-8). 3 | /// 4 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] 5 | internal unsafe readonly partial struct PCZZSTR 6 | : IEquatable 7 | { 8 | /// 9 | /// A pointer to the first character in the string. The content should be considered readonly, as it was typed as constant in the SDK. 10 | /// 11 | internal readonly byte* Value; 12 | internal PCZZSTR(byte* value) => this.Value = value; 13 | public static implicit operator byte*(PCZZSTR value) => value.Value; 14 | public static explicit operator PCZZSTR(byte* value) => new PCZZSTR(value); 15 | public bool Equals(PCZZSTR other) => this.Value == other.Value; 16 | public override bool Equals(object obj) => obj is PCZZSTR other && this.Equals(other); 17 | public override int GetHashCode() => unchecked((int)this.Value); 18 | 19 | /// 20 | /// Gets the number of characters in this null-terminated string list, excluding the final null terminator. 21 | /// 22 | internal int Length 23 | { 24 | get 25 | { 26 | PCSTR str = new PCSTR(this.Value); 27 | while (true) 28 | { 29 | int len = str.Length; 30 | if (len > 0) 31 | { 32 | str = new PCSTR(str.Value + len + 1); 33 | } 34 | else 35 | { 36 | break; 37 | } 38 | } 39 | 40 | return checked((int)(str.Value - this.Value)); 41 | } 42 | } 43 | 44 | /// 45 | /// Returns a with a copy of this character array, decoding as UTF-8. 46 | /// 47 | /// A , or if is . 48 | public override string ToString() => this.Value is null ? null : new string((sbyte*)this.Value, 0, this.Length, global::System.Text.Encoding.Default); 49 | 50 | #if canUseSpan 51 | /// 52 | /// Returns a span of the characters in this string. 53 | /// 54 | internal ReadOnlySpan AsSpan() => this.Value is null ? default(ReadOnlySpan) : new ReadOnlySpan(this.Value, this.Length); 55 | #endif 56 | 57 | private string DebuggerDisplay => this.ToString(); 58 | } 59 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PCZZWSTR.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// A pointer to a constant, empty-string terminated list of null-terminated strings that uses UTF-16 encoding. 3 | /// 4 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] 5 | internal unsafe readonly partial struct PCZZWSTR 6 | : IEquatable 7 | { 8 | /// 9 | /// A pointer to the first character in the string. The content should be considered readonly, as it was typed as constant in the SDK. 10 | /// 11 | internal readonly char* Value; 12 | internal PCZZWSTR(char* value) => this.Value = value; 13 | public static explicit operator char*(PCZZWSTR value) => value.Value; 14 | public static implicit operator PCZZWSTR(char* value) => new PCZZWSTR(value); 15 | public bool Equals(PCZZWSTR other) => this.Value == other.Value; 16 | public override bool Equals(object obj) => obj is PCZZWSTR other && this.Equals(other); 17 | public override int GetHashCode() => unchecked((int)this.Value); 18 | 19 | /// 20 | /// Gets the number of characters in this null-terminated string list, excluding the final null terminator. 21 | /// 22 | internal int Length 23 | { 24 | get 25 | { 26 | PCWSTR str = new PCWSTR(this.Value); 27 | while (true) 28 | { 29 | int len = str.Length; 30 | if (len > 0) 31 | { 32 | str = new PCWSTR(str.Value + len + 1); 33 | } 34 | else 35 | { 36 | break; 37 | } 38 | } 39 | 40 | return checked((int)(str.Value - this.Value)); 41 | } 42 | } 43 | 44 | /// 45 | /// Returns a with a copy of this character array. 46 | /// 47 | /// A , or if is . 48 | public override string ToString() => this.Value is null ? null : new string(this.Value, 0, this.Length); 49 | 50 | #if canUseSpan 51 | /// 52 | /// Returns a span of the characters in this string. 53 | /// 54 | internal ReadOnlySpan AsSpan() => this.Value is null ? default(ReadOnlySpan) : new ReadOnlySpan(this.Value, this.Length); 55 | #endif 56 | 57 | private string DebuggerDisplay => this.ToString(); 58 | } 59 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PInvokeClassHelperMethods.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// This class wrapper is stripped so that individual helper methods may be injected into the generated PInvoke class. 3 | /// 4 | internal class PInvokeClassHelperMethods 5 | { 6 | private static void EnsureNullTerminated(Span buffer, string parameterName) 7 | { 8 | if (buffer != null && buffer.LastIndexOf('\0') == -1) 9 | { 10 | throw new ArgumentException("Required null terminator is missing.", parameterName); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PSTR.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// A pointer to a null-terminated, ANSI character string. 3 | /// 4 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] 5 | partial struct PSTR 6 | { 7 | public static implicit operator PCSTR(PSTR value) => new PCSTR(value.Value); 8 | 9 | /// 10 | internal int Length => new PCSTR(this.Value).Length; 11 | 12 | /// 13 | public override string ToString() => new PCSTR(this.Value).ToString(); 14 | 15 | #if canUseSpan 16 | /// 17 | /// Returns a span of the characters in this string, up to the first null character (exclusive). 18 | /// 19 | internal Span AsSpan() => this.Value is null ? default(Span) : new Span(this.Value, this.Length); 20 | #endif 21 | 22 | private string DebuggerDisplay => this.ToString(); 23 | } 24 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PWSTR.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// A pointer to a null-terminated character string. 3 | /// 4 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] 5 | partial struct PWSTR 6 | { 7 | public static implicit operator PCWSTR(PWSTR value) => new PCWSTR(value.Value); 8 | 9 | /// 10 | internal int Length => new PCWSTR(this.Value).Length; 11 | 12 | /// 13 | public override string ToString() => new PCWSTR(this.Value).ToString(); 14 | 15 | #if canUseSpan 16 | /// 17 | /// Returns a span of the characters in this string, up to the first null character (exclusive). 18 | /// 19 | internal Span AsSpan() => this.Value is null ? default(Span) : new Span(this.Value, this.Length); 20 | #endif 21 | 22 | private string DebuggerDisplay => this.ToString(); 23 | } 24 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PZZSTR.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// A pointer to an empty-string terminated list of null-terminated strings with 1-byte characters (often UTF-8). 3 | /// 4 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] 5 | internal unsafe readonly partial struct PZZSTR 6 | : IEquatable 7 | { 8 | /// 9 | /// A pointer to the first character in the string. 10 | /// 11 | internal readonly byte* Value; 12 | internal PZZSTR(byte* value) => this.Value = value; 13 | public static implicit operator byte*(PZZSTR value) => value.Value; 14 | public static explicit operator PZZSTR(byte* value) => new PZZSTR(value); 15 | public static implicit operator PCZZSTR(PZZSTR value) => new PCZZSTR(value.Value); 16 | public bool Equals(PZZSTR other) => this.Value == other.Value; 17 | public override bool Equals(object obj) => obj is PZZSTR other && this.Equals(other); 18 | public override int GetHashCode() => unchecked((int)this.Value); 19 | 20 | /// 21 | internal int Length => new PCZZSTR(this.Value).Length; 22 | 23 | /// 24 | public override string ToString() => new PCZZSTR(this.Value).ToString(); 25 | 26 | #if canUseSpan 27 | /// 28 | /// Returns a span of the characters in this string. 29 | /// 30 | internal Span AsSpan() => this.Value is null ? default(Span) : new Span(this.Value, this.Length); 31 | #endif 32 | 33 | private string DebuggerDisplay => this.ToString(); 34 | } 35 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/PZZWSTR.cs: -------------------------------------------------------------------------------- 1 | /// 2 | /// A pointer to an empty-string terminated list of null-terminated strings that uses UTF-16 encoding. 3 | /// 4 | [DebuggerDisplay("{" + nameof(DebuggerDisplay) + "}")] 5 | internal unsafe readonly partial struct PZZWSTR 6 | : IEquatable 7 | { 8 | /// 9 | /// A pointer to the first character in the string. 10 | /// 11 | internal readonly char* Value; 12 | internal PZZWSTR(char* value) => this.Value = value; 13 | public static explicit operator char*(PZZWSTR value) => value.Value; 14 | public static implicit operator PZZWSTR(char* value) => new PZZWSTR(value); 15 | public static implicit operator PCZZWSTR(PZZWSTR value) => new PCZZWSTR(value.Value); 16 | public bool Equals(PZZWSTR other) => this.Value == other.Value; 17 | public override bool Equals(object obj) => obj is PZZWSTR other && this.Equals(other); 18 | public override int GetHashCode() => unchecked((int)this.Value); 19 | 20 | /// 21 | internal int Length => new PCZZWSTR(this.Value).Length; 22 | 23 | /// 24 | public override string ToString() => new PCZZWSTR(this.Value).ToString(); 25 | 26 | #if canUseSpan 27 | /// 28 | /// Returns a span of the characters in this string. 29 | /// 30 | internal Span AsSpan() => this.Value is null ? default(Span) : new Span(this.Value, this.Length); 31 | #endif 32 | 33 | private string DebuggerDisplay => this.ToString(); 34 | } 35 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/RECT.cs: -------------------------------------------------------------------------------- 1 | partial struct RECT 2 | { 3 | #if canUseSystemDrawing 4 | internal RECT(global::System.Drawing.Rectangle value) : 5 | this(value.Left, value.Top, value.Right, value.Bottom) { } 6 | internal RECT(global::System.Drawing.Point location, global::System.Drawing.Size size) : 7 | this(location.X, location.Y, unchecked(location.X + size.Width), unchecked(location.Y + size.Height)) { } 8 | #endif 9 | internal RECT(int left, int top, int right, int bottom) 10 | { 11 | this.left = left; 12 | this.top = top; 13 | this.right = right; 14 | this.bottom = bottom; 15 | } 16 | 17 | internal static RECT FromXYWH(int x, int y, int width, int height) => 18 | new RECT(x, y, unchecked(x + width), unchecked(y + height)); 19 | internal readonly int Width => unchecked(this.right - this.left); 20 | internal readonly int Height => unchecked(this.bottom - this.top); 21 | internal readonly bool IsEmpty => this.left == 0 && this.top == 0 && this.right == 0 && this.bottom == 0; 22 | internal readonly int X => this.left; 23 | internal readonly int Y => this.top; 24 | #if canUseSystemDrawing 25 | internal readonly global::System.Drawing.Size Size => new global::System.Drawing.Size(this.Width, this.Height); 26 | public static implicit operator global::System.Drawing.Rectangle(RECT value) => new global::System.Drawing.Rectangle(value.left, value.top, value.Width, value.Height); 27 | public static implicit operator global::System.Drawing.RectangleF(RECT value) => new global::System.Drawing.RectangleF(value.left, value.top, value.Width, value.Height); 28 | public static implicit operator RECT(global::System.Drawing.Rectangle value) => new RECT(value); 29 | #endif 30 | } 31 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/SIZE.cs: -------------------------------------------------------------------------------- 1 | partial struct SIZE 2 | { 3 | #if canUseSystemDrawing 4 | internal SIZE(global::System.Drawing.Size value) : this(value.Width, value.Height) { } 5 | #endif 6 | internal SIZE(int width, int height) 7 | { 8 | this.cx = width; 9 | this.cy = height; 10 | } 11 | 12 | internal readonly int Width => this.cx; 13 | internal readonly int Height => this.cy; 14 | internal readonly bool IsEmpty => this.cx == 0 && this.cy == 0; 15 | #if canUseSystemDrawing 16 | public static implicit operator global::System.Drawing.Size(SIZE value) => new global::System.Drawing.Size(value.cx, value.cy); 17 | public static implicit operator SIZE(global::System.Drawing.Size value) => new SIZE(value); 18 | #endif 19 | } 20 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/SYSTEMTIME.cs: -------------------------------------------------------------------------------- 1 | partial struct SYSTEMTIME 2 | : IEquatable 3 | { 4 | public bool Equals(SYSTEMTIME other) => this.wYear == other.wYear && this.wMonth == other.wMonth && this.wDayOfWeek == other.wDayOfWeek && this.wDay == other.wDay && this.wHour == other.wHour && this.wMinute == other.wMinute && this.wSecond == other.wSecond && this.wMilliseconds == other.wMilliseconds; 5 | public override bool Equals(object obj) => obj is SYSTEMTIME other && this.Equals(other); 6 | public override int GetHashCode() => (this.wYear, this.wMonth, this.wDayOfWeek, this.wDay, this.wHour, this.wMinute, this.wSecond, this.wMilliseconds).GetHashCode(); 7 | public static bool operator ==(SYSTEMTIME d1, SYSTEMTIME d2) => d1.Equals(d2); 8 | public static bool operator !=(SYSTEMTIME d1, SYSTEMTIME d2) => !(d1 == d2); 9 | 10 | public static explicit operator global::System.DateTime(SYSTEMTIME sysTime) 11 | { 12 | if (sysTime == default) 13 | { 14 | return default; 15 | } 16 | 17 | return new global::System.DateTime(sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds); 18 | } 19 | 20 | public static explicit operator SYSTEMTIME(global::System.DateTime time) 21 | { 22 | if (time == default) 23 | { 24 | return default; 25 | } 26 | 27 | checked 28 | { 29 | return new SYSTEMTIME 30 | { 31 | wYear = (ushort)time.Year, 32 | wMonth = (ushort)time.Month, 33 | wDayOfWeek = (ushort)time.DayOfWeek, 34 | wDay = (ushort)time.Day, 35 | wHour = (ushort)time.Hour, 36 | wMinute = (ushort)time.Minute, 37 | wSecond = (ushort)time.Second, 38 | wMilliseconds = (ushort)time.Millisecond, 39 | }; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/VARIANT_BOOL.cs: -------------------------------------------------------------------------------- 1 | partial struct VARIANT_BOOL 2 | { 3 | internal VARIANT_BOOL(bool value) => this.Value = value ? VARIANT_TRUE : VARIANT_FALSE; 4 | public static implicit operator bool(VARIANT_BOOL value) => value != VARIANT_FALSE; 5 | public static implicit operator VARIANT_BOOL(bool value) => value ? VARIANT_TRUE : VARIANT_FALSE; 6 | } 7 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/VariableLengthInlineArray`1.cs: -------------------------------------------------------------------------------- 1 | internal struct VariableLengthInlineArray 2 | where T : unmanaged 3 | { 4 | internal T e0; 5 | 6 | #if canUseUnscopedRef 7 | 8 | #if canUseUnsafeAdd 9 | internal ref T this[int index] 10 | { 11 | [UnscopedRef] 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | get => ref Unsafe.Add(ref this.e0, index); 14 | } 15 | #endif 16 | 17 | #if canUseSpan 18 | [UnscopedRef] 19 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 20 | internal Span AsSpan(int length) 21 | { 22 | #if canCallCreateSpan 23 | return MemoryMarshal.CreateSpan(ref this.e0, length); 24 | #else 25 | unsafe 26 | { 27 | fixed (void* p = &this.e0) 28 | { 29 | return new Span(p, length); 30 | } 31 | } 32 | #endif 33 | } 34 | #endif 35 | 36 | #endif 37 | } 38 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/VariableLengthInlineArray`2.cs: -------------------------------------------------------------------------------- 1 | internal struct VariableLengthInlineArray 2 | where T : unmanaged 3 | where TBlittable : unmanaged 4 | { 5 | #if canUseUnscopedRef 6 | private TBlittable _e0; 7 | 8 | [UnscopedRef] 9 | internal ref T e0 => ref Unsafe.As(ref this._e0); 10 | 11 | #if canUseUnsafeAdd 12 | internal ref T this[int index] 13 | { 14 | [UnscopedRef] 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | get => ref Unsafe.Add(ref this.e0, index); 17 | } 18 | #endif 19 | 20 | #if canUseSpan 21 | [UnscopedRef] 22 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 23 | internal Span AsSpan(int length) 24 | { 25 | #if canCallCreateSpan 26 | return MemoryMarshal.CreateSpan(ref this.e0, length); 27 | #else 28 | unsafe 29 | { 30 | fixed (void* p = &this.e0) 31 | { 32 | return new Span(p, length); 33 | } 34 | } 35 | #endif 36 | } 37 | #endif 38 | 39 | #else 40 | internal TBlittable e0; 41 | #endif 42 | } 43 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/WinRTCustomMarshaler.cs: -------------------------------------------------------------------------------- 1 | namespace Windows.Win32.CsWin32.InteropServices 2 | { 3 | internal class WinRTCustomMarshaler : global::System.Runtime.InteropServices.ICustomMarshaler 4 | { 5 | private string winrtClassName; 6 | private bool lookedForFromAbi; 7 | private global::System.Reflection.MethodInfo fromAbi; 8 | 9 | private WinRTCustomMarshaler(string cookie) 10 | { 11 | this.winrtClassName = cookie; 12 | } 13 | 14 | /// 15 | /// Gets an instance of the marshaler given a cookie 16 | /// 17 | /// Cookie used to create marshaler 18 | /// Marshaler 19 | public static global::System.Runtime.InteropServices.ICustomMarshaler GetInstance(string cookie) 20 | { 21 | return new WinRTCustomMarshaler(cookie); 22 | } 23 | 24 | void global::System.Runtime.InteropServices.ICustomMarshaler.CleanUpManagedData(object ManagedObj) 25 | { 26 | } 27 | 28 | void global::System.Runtime.InteropServices.ICustomMarshaler.CleanUpNativeData(global::System.IntPtr pNativeData) 29 | { 30 | global::System.Runtime.InteropServices.Marshal.Release(pNativeData); 31 | } 32 | 33 | int global::System.Runtime.InteropServices.ICustomMarshaler.GetNativeDataSize() 34 | { 35 | throw new global::System.NotImplementedException(); 36 | } 37 | 38 | global::System.IntPtr global::System.Runtime.InteropServices.ICustomMarshaler.MarshalManagedToNative(object ManagedObj) 39 | { 40 | throw new global::System.NotImplementedException(); 41 | } 42 | 43 | object global::System.Runtime.InteropServices.ICustomMarshaler.MarshalNativeToManaged(global::System.IntPtr pNativeData) 44 | { 45 | if (!this.lookedForFromAbi) 46 | { 47 | var assembly = typeof(global::Windows.Foundation.IMemoryBuffer).Assembly; 48 | var type = global::System.Type.GetType($"{this.winrtClassName}, {assembly.FullName}"); 49 | 50 | this.fromAbi = type.GetMethod("FromAbi"); 51 | this.lookedForFromAbi = true; 52 | } 53 | 54 | if (this.fromAbi != null) 55 | { 56 | return this.fromAbi.Invoke(null, new object[] { pNativeData }); 57 | } 58 | else 59 | { 60 | return global::System.Runtime.InteropServices.Marshal.GetObjectForIUnknown(pNativeData); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/marshaling/CoCreateInstance.cs: -------------------------------------------------------------------------------- 1 | /// 2 | internal static unsafe global::Windows.Win32.Foundation.HRESULT CoCreateInstance(in Guid rclsid, object pUnkOuter, global::Windows.Win32.System.Com.CLSCTX dwClsContext, out T ppv) 3 | where T : class 4 | { 5 | global::Windows.Win32.Foundation.HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, typeof(T).GUID, out object o); 6 | ppv = (T)o; 7 | return hr; 8 | } 9 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/templates/no_marshaling/CoCreateInstance.cs: -------------------------------------------------------------------------------- 1 | /// 2 | internal static unsafe global::Windows.Win32.Foundation.HRESULT CoCreateInstance(in Guid rclsid, global::Windows.Win32.System.Com.IUnknown* pUnkOuter, global::Windows.Win32.System.Com.CLSCTX dwClsContext, out T* ppv) 3 | where T : unmanaged 4 | { 5 | global::Windows.Win32.Foundation.HRESULT hr = CoCreateInstance(rclsid, pUnkOuter, dwClsContext, typeof(T).GUID, out void* o); 6 | ppv = (T*)o; 7 | return hr; 8 | } 9 | -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 4 | 5 | foreach($analyzersPath in $analyzersPaths) 6 | { 7 | # Install the language agnostic analyzers. 8 | if (Test-Path $analyzersPath) 9 | { 10 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 11 | { 12 | if($project.Object.AnalyzerReferences) 13 | { 14 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 15 | } 16 | } 17 | } 18 | } 19 | 20 | # $project.Type gives the language name like (C# or VB.NET) 21 | $languageFolder = "" 22 | if($project.Type -eq "C#") 23 | { 24 | $languageFolder = "cs" 25 | } 26 | if($project.Type -eq "VB.NET") 27 | { 28 | $languageFolder = "vb" 29 | } 30 | if($languageFolder -eq "") 31 | { 32 | return 33 | } 34 | 35 | foreach($analyzersPath in $analyzersPaths) 36 | { 37 | # Install language specific analyzers. 38 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 39 | if (Test-Path $languageAnalyzersPath) 40 | { 41 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 42 | { 43 | if($project.Object.AnalyzerReferences) 44 | { 45 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 4 | 5 | foreach($analyzersPath in $analyzersPaths) 6 | { 7 | # Uninstall the language agnostic analyzers. 8 | if (Test-Path $analyzersPath) 9 | { 10 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 11 | { 12 | if($project.Object.AnalyzerReferences) 13 | { 14 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 15 | } 16 | } 17 | } 18 | } 19 | 20 | # $project.Type gives the language name like (C# or VB.NET) 21 | $languageFolder = "" 22 | if($project.Type -eq "C#") 23 | { 24 | $languageFolder = "cs" 25 | } 26 | if($project.Type -eq "VB.NET") 27 | { 28 | $languageFolder = "vb" 29 | } 30 | if($languageFolder -eq "") 31 | { 32 | return 33 | } 34 | 35 | foreach($analyzersPath in $analyzersPaths) 36 | { 37 | # Uninstall language specific analyzers. 38 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 39 | if (Test-Path $languageAnalyzersPath) 40 | { 41 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 42 | { 43 | if($project.Object.AnalyzerReferences) 44 | { 45 | try 46 | { 47 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 48 | } 49 | catch 50 | { 51 | 52 | } 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Microsoft.Windows.CsWin32/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "inherit": true, 3 | "assemblyVersion": { 4 | "precision": "revision" 5 | } 6 | } -------------------------------------------------------------------------------- /src/OptProf.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | IBC 5 | Common7\IDE\PrivateAssemblies\$(TargetFileName) 6 | /ExeConfig:"%VisualStudio.InstallationUnderTest.Path%\Common7\IDE\vsn.exe" 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/VSInsertionMetadata/Library.VSInsertionMetadata.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | true 5 | $(RepoRootPath)bin\Packages\$(Configuration)\VSRepo\ 6 | false 7 | false 8 | Contains metadata for insertion into VS. 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/VSInsertionMetadata/ProfilingInputs.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 3 | "settings": { 4 | "documentationRules": { 5 | "companyName": "Microsoft Corporation", 6 | "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} license. See {licenseFile} file in the project root for full license information.", 7 | "variables": { 8 | "licenseName": "MIT", 9 | "licenseFile": "LICENSE" 10 | }, 11 | "fileNamingConvention": "metadata", 12 | "xmlHeader": false 13 | }, 14 | "orderingRules": { 15 | "usingDirectivesPlacement": "outsideNamespace" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # SA1600: Elements should be documented 4 | dotnet_diagnostic.SA1600.severity = silent 5 | 6 | # SA1601: Partial elements should be documented 7 | dotnet_diagnostic.SA1601.severity = silent 8 | 9 | # SA1602: Enumeration items should be documented 10 | dotnet_diagnostic.SA1602.severity = silent 11 | 12 | # SA1615: Element return value should be documented 13 | dotnet_diagnostic.SA1615.severity = silent 14 | 15 | # VSTHRD103: Call async methods when in an async method 16 | dotnet_diagnostic.VSTHRD103.severity = silent 17 | 18 | # VSTHRD111: Use .ConfigureAwait(bool) 19 | dotnet_diagnostic.VSTHRD111.severity = none 20 | 21 | # VSTHRD200: Use Async suffix for async methods 22 | dotnet_diagnostic.VSTHRD200.severity = silent 23 | 24 | # CA1014: Mark assemblies with CLSCompliant 25 | dotnet_diagnostic.CA1014.severity = none 26 | 27 | # CA1050: Declare types in namespaces 28 | dotnet_diagnostic.CA1050.severity = none 29 | 30 | # CA1303: Do not pass literals as localized parameters 31 | dotnet_diagnostic.CA1303.severity = none 32 | 33 | # CS1591: Missing XML comment for publicly visible type or member 34 | dotnet_diagnostic.CS1591.severity = silent 35 | 36 | # CA1707: Identifiers should not contain underscores 37 | dotnet_diagnostic.CA1707.severity = silent 38 | 39 | # CA1062: Validate arguments of public methods 40 | dotnet_diagnostic.CA1062.severity = suggestion 41 | 42 | # CA1063: Implement IDisposable Correctly 43 | dotnet_diagnostic.CA1063.severity = silent 44 | 45 | # CA1816: Dispose methods should call SuppressFinalize 46 | dotnet_diagnostic.CA1816.severity = silent 47 | 48 | # CA2007: Consider calling ConfigureAwait on the awaited task 49 | dotnet_diagnostic.CA2007.severity = none 50 | 51 | # SA1310: Field names should not contain underscore 52 | dotnet_diagnostic.SA1310.severity = silent 53 | 54 | # SA1133: Do not combine attributes 55 | dotnet_diagnostic.SA1133.severity = silent 56 | 57 | # SA1401: Fields should be private 58 | dotnet_diagnostic.SA1401.severity = silent 59 | 60 | # SA1133: Do not combine attributes 61 | dotnet_diagnostic.SA1133.severity = silent 62 | 63 | # SA1611: Element parameters should be documented 64 | dotnet_diagnostic.SA1611.severity = suggestion 65 | -------------------------------------------------------------------------------- /test/CsWin32User.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | true 7 | false 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/BoolTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Windows.Win32.Foundation; 5 | 6 | public class BoolTests 7 | { 8 | [Fact] 9 | public void Ctor_bool() 10 | { 11 | BOOL b = true; 12 | bool b2 = b; 13 | Assert.True(b); 14 | Assert.True(b2); 15 | 16 | Assert.False(default(BOOL)); 17 | } 18 | 19 | [Fact] 20 | public void Ctor_int() 21 | { 22 | Assert.Equal(2, new BOOL(2).Value); 23 | } 24 | 25 | [Fact] 26 | public void ExplicitCast() 27 | { 28 | Assert.Equal(2, ((BOOL)2).Value); 29 | } 30 | 31 | [Theory] 32 | [InlineData(3)] 33 | [InlineData(-1)] 34 | [InlineData(0)] 35 | [InlineData(1)] 36 | [InlineData(0xfffff)] 37 | public void LossyConversionFromBOOLtoBool(int ordinal) 38 | { 39 | BOOL nativeBool = new BOOL(ordinal); 40 | bool managedBool = nativeBool; 41 | Assert.Equal(ordinal != 0, managedBool); 42 | BOOLEAN roundtrippedNativeBool = managedBool; 43 | Assert.Equal(managedBool ? 1 : 0, roundtrippedNativeBool); 44 | } 45 | 46 | [Fact] 47 | public void BOOLEqualsComparesExactValue() 48 | { 49 | BOOL b1 = new BOOL(1); 50 | BOOL b2 = new BOOL(2); 51 | Assert.Equal(b1, b1); 52 | Assert.NotEqual(b1, b2); 53 | } 54 | 55 | [Fact] 56 | public void BOOL_OverridesEqualityOperator() 57 | { 58 | var @true = new BOOL(true); 59 | var @false = new BOOL(false); 60 | Assert.True(@true == new BOOL(true)); 61 | Assert.False(@true != new BOOL(true)); 62 | Assert.True(@true != @false); 63 | Assert.False(@true == @false); 64 | 65 | var two = new BOOL(2); 66 | Assert.False(two == @true); 67 | Assert.True(two != @true); 68 | } 69 | 70 | [Fact] 71 | public void LogicalOperators_And() 72 | { 73 | BOOL @true = true, @false = false; 74 | Assert.False(@false && @false); 75 | Assert.False(@true && @false); 76 | Assert.True(@true && @true); 77 | } 78 | 79 | [Fact] 80 | public void LogicalOperators_Or() 81 | { 82 | BOOL @true = true, @false = false; 83 | Assert.True(@true || @false); 84 | Assert.False(@false || @false); 85 | Assert.True(@true || @true); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/BooleanTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Windows.Win32.Foundation; 5 | 6 | public class BooleanTests 7 | { 8 | [Fact] 9 | public void Ctor_Bool() 10 | { 11 | BOOLEAN b = true; 12 | bool b2 = b; 13 | Assert.True(b); 14 | Assert.True(b2); 15 | 16 | Assert.False(default(BOOLEAN)); 17 | } 18 | 19 | [Fact] 20 | public void Ctor_byte() 21 | { 22 | Assert.Equal(2, new BOOLEAN(2).Value); 23 | } 24 | 25 | [Fact] 26 | public void ExplicitCast() 27 | { 28 | Assert.Equal(2, ((BOOLEAN)2).Value); 29 | } 30 | 31 | [Theory] 32 | [InlineData(3)] 33 | [InlineData(0xff)] 34 | [InlineData(0x80)] 35 | [InlineData(0x00)] 36 | [InlineData(0x01)] 37 | public void LossyConversionFromBOOLEANtoBool(byte ordinal) 38 | { 39 | BOOLEAN nativeBool = new BOOLEAN(ordinal); 40 | bool managedBool = nativeBool; 41 | Assert.Equal(ordinal != 0, managedBool); 42 | BOOLEAN roundtrippedNativeBool = managedBool; 43 | Assert.Equal(managedBool ? 1 : 0, roundtrippedNativeBool); 44 | } 45 | 46 | [Fact] 47 | public void BOOLEANEqualsComparesExactValue() 48 | { 49 | BOOLEAN b1 = new BOOLEAN(1); 50 | BOOLEAN b2 = new BOOLEAN(2); 51 | Assert.Equal(b1, b1); 52 | Assert.NotEqual(b1, b2); 53 | } 54 | 55 | [Fact] 56 | public void BOOLEAN_OverridesEqualityOperator() 57 | { 58 | var @true = new BOOLEAN(true); 59 | var @false = new BOOLEAN(false); 60 | Assert.True(@true == new BOOLEAN(true)); 61 | Assert.False(@true != new BOOLEAN(true)); 62 | Assert.True(@true != @false); 63 | Assert.False(@true == @false); 64 | 65 | var two = new BOOLEAN(2); 66 | Assert.False(two == @true); 67 | Assert.True(two != @true); 68 | } 69 | 70 | [Fact] 71 | public void LogicalOperators_And() 72 | { 73 | BOOLEAN @true = true, @false = false; 74 | Assert.False(@false && @false); 75 | Assert.False(@true && @false); 76 | Assert.True(@true && @true); 77 | } 78 | 79 | [Fact] 80 | public void LogicalOperators_Or() 81 | { 82 | BOOLEAN @true = true, @false = false; 83 | Assert.True(@true || @false); 84 | Assert.False(@false || @false); 85 | Assert.True(@true || @true); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/ComRuntimeTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Windows.Win32; 5 | using Windows.Win32.UI.Shell; 6 | using IServiceProvider = Windows.Win32.System.Com.IServiceProvider; 7 | 8 | public class ComRuntimeTests 9 | { 10 | [Fact] 11 | [Trait("TestCategory", "FailsInCloudTest")] 12 | public void RemotableInterface() 13 | { 14 | IShellWindows shellWindows = (IShellWindows)new ShellWindows(); 15 | IServiceProvider serviceProvider = (IServiceProvider)shellWindows.FindWindowSW( 16 | PInvoke.CSIDL_DESKTOP, 17 | null, 18 | ShellWindowTypeConstants.SWC_DESKTOP, 19 | out int hwnd, 20 | ShellWindowFindWindowOptions.SWFO_NEEDDISPATCH); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/FILE_CREATE_FLAGS.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.Windows.Sdk; 5 | 6 | /// 7 | /// Written here explicitly to verify that the code generator will suppress codegen where a type already exists. 8 | /// 9 | internal enum FILE_CREATE_FLAGS 10 | { 11 | CREATE_NEW = 1, 12 | CREATE_ALWAYS = 2, 13 | OPEN_EXISTING = 3, 14 | OPEN_ALWAYS = 4, 15 | TRUNCATE_EXISTING = 5, 16 | } 17 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/FlexibleArrayTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Runtime.InteropServices; 5 | using Microsoft.Win32.SafeHandles; 6 | using Windows.Win32.System.Ole; 7 | 8 | public class FlexibleArrayTests 9 | { 10 | [Fact] 11 | public unsafe void FlexibleArraySizing() 12 | { 13 | const int count = 3; 14 | PAGESET* pPageSet = (PAGESET*)Marshal.AllocHGlobal(PAGESET.SizeOf(count)); 15 | try 16 | { 17 | pPageSet->rgPages[0].nFromPage = 0; 18 | 19 | Span pageRange = pPageSet->rgPages.AsSpan(count); 20 | for (int i = 0; i < count; i++) 21 | { 22 | pageRange[i].nFromPage = i * 2; 23 | pageRange[i].nToPage = (i * 2) + 1; 24 | } 25 | } 26 | finally 27 | { 28 | Marshal.FreeHGlobal((IntPtr)pPageSet); 29 | } 30 | } 31 | 32 | [Fact] 33 | public void SizeOf_Minimum1Element() 34 | { 35 | Assert.Equal(PAGESET.SizeOf(1), PAGESET.SizeOf(0)); 36 | Assert.Equal(Marshal.SizeOf(), PAGESET.SizeOf(2) - PAGESET.SizeOf(1)); 37 | } 38 | 39 | [Fact] 40 | [Trait("WindowsOnly", "true")] 41 | public unsafe void NonBlittableType_Char() 42 | { 43 | // The argument values are not relevant here. 44 | // The function is expected to return a failure error code in success cases. 45 | // This is a regression test for https://github.com/microsoft/CsWin32/issues/1184, 46 | // where the mere invocation of the function caused .NET Framework to throw a marshaling exception. 47 | uint size = 0; 48 | Windows.Win32.PInvoke.SetupDiGetDeviceInterfaceDetail( 49 | new SafeFileHandle(IntPtr.Zero, false), 50 | default, 51 | null, 52 | 0, 53 | &size, 54 | null); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/GenerationSandbox.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/NativeMethods.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "..\\..\\src\\Microsoft.Windows.CsWin32\\settings.schema.json", 3 | "emitSingleFile": true, 4 | "multiTargetingFriendlyAPIs": true, 5 | "comInterop": { 6 | "preserveSigMethods": [ 7 | "IEnumDebugPropertyInfo.Next" 8 | ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/NativeMethods.txt: -------------------------------------------------------------------------------- 1 | BCRYPT_KEY_HANDLE 2 | BM_REQUEST_TYPE 3 | BOOL 4 | BOOLEAN 5 | CHAR 6 | CreateCursor 7 | CreateFile 8 | CSIDL_DESKTOP 9 | DISPLAYCONFIG_VIDEO_SIGNAL_INFO 10 | EnumWindows 11 | FILE_ACCESS_RIGHTS 12 | FLICK_DATA 13 | GetForegroundWindow 14 | GetProcAddress 15 | GetTickCount 16 | GetWindowText 17 | GetWindowTextLength 18 | RmRegisterResources 19 | HDC_UserSize 20 | HIWORD 21 | HRESULT_FROM_WIN32 22 | IDirectorySearch 23 | IEnumDebugPropertyInfo 24 | IPersistFile 25 | IServiceProvider 26 | IShellWindows 27 | IStream 28 | KEY_EVENT_RECORD 29 | LoadLibrary 30 | LOWORD 31 | MainAVIHeader 32 | MAKELPARAM 33 | MAKELRESULT 34 | MAKEWPARAM 35 | MAX_PATH 36 | NTSTATUS 37 | PAGESET 38 | PathParseIconLocation 39 | PROCESS_BASIC_INFORMATION 40 | PZZSTR 41 | PZZWSTR 42 | RECT 43 | RegLoadAppKey 44 | RM_PROCESS_INFO 45 | S_OK 46 | SetupDiGetDeviceInterfaceDetail 47 | SHDESCRIPTIONID 48 | SHELLFLAGSTATE 49 | ShellLink 50 | ShellWindowFindWindowOptions 51 | ShellWindows 52 | ShellWindowTypeConstants 53 | SHFILEOPSTRUCTW 54 | SIZE 55 | VARDESC 56 | WER_REPORT_INFORMATION 57 | wglGetProcAddress 58 | WPARAM 59 | WriteFile 60 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/SystemDrawingStructTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Drawing; 5 | using Windows.Win32.Foundation; 6 | 7 | public class SystemDrawingStructTests 8 | { 9 | [Fact] 10 | public void Size() 11 | { 12 | SIZE s = new SIZE(1, 1); 13 | Size s2 = s; 14 | Assert.False(s.IsEmpty); 15 | Assert.False(s2.IsEmpty); 16 | 17 | Assert.True(default(SIZE).IsEmpty); 18 | } 19 | 20 | [Fact] 21 | public void NotLossyConversionBetweenSizeAndSIZE() 22 | { 23 | SIZE nativeSize = new SIZE(1, 1); 24 | Size managedSize = nativeSize; 25 | SIZE roundtrippedNativeSize = managedSize; 26 | Assert.Equal(nativeSize, roundtrippedNativeSize); 27 | } 28 | 29 | [Fact] 30 | public void NotLossyConversionBetweenSizeAndSIZE_Ctors() 31 | { 32 | SIZE nativeSize = new SIZE(1, 1); 33 | Size managedSize = nativeSize; 34 | SIZE roundtrippedNativeSize = new SIZE(managedSize); 35 | Assert.Equal(nativeSize, roundtrippedNativeSize); 36 | } 37 | 38 | [Fact] 39 | public void Rect() 40 | { 41 | RECT r = new RECT(1, 1, 2, 2); 42 | Rectangle r2 = r; 43 | Assert.False(r.IsEmpty); 44 | Assert.False(r2.IsEmpty); 45 | 46 | Assert.True(default(RECT).IsEmpty); 47 | } 48 | 49 | [Fact] 50 | public void NotLossyConversionBetweenRectangleAndRECT() 51 | { 52 | RECT nativeSize = new RECT(1, 1, 2, 2); 53 | Rectangle managedSize = nativeSize; 54 | RECT roundtrippedNativeSize = managedSize; 55 | Assert.Equal(nativeSize, roundtrippedNativeSize); 56 | } 57 | 58 | [Fact] 59 | public void NotLossyConversionBetweenRectangleAndRECT_Ctors() 60 | { 61 | RECT nativeSize = new RECT(1, 1, 2, 2); 62 | Rectangle managedSize = nativeSize; 63 | RECT roundtrippedNativeSize = new RECT(managedSize); 64 | Assert.Equal(nativeSize, roundtrippedNativeSize); 65 | } 66 | 67 | [Fact] 68 | public void RectangleAndRECTFromXYWH_AreEqual() 69 | { 70 | RECT nativeSize = RECT.FromXYWH(1, 1, 2, 2); 71 | Rectangle managedSize = new Rectangle(1, 1, 2, 2); 72 | Assert.Equal(nativeSize.left, managedSize.Left); 73 | Assert.Equal(nativeSize.right, managedSize.Right); 74 | Assert.Equal(nativeSize.top, managedSize.Top); 75 | Assert.Equal(nativeSize.bottom, managedSize.Bottom); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/TestUtils.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Diagnostics; 5 | 6 | internal static class TestUtils 7 | { 8 | #if DEBUG // Only tests that are conditioned for Debug mode can assert this. 9 | internal static void AssertDebugAssertFailed(Action action) 10 | { 11 | // We're mutating a static collection. 12 | // Protect against concurrent tests mutating the collection while we're using it. 13 | lock (Trace.Listeners) 14 | { 15 | TraceListener[] listeners = Trace.Listeners.Cast().ToArray(); 16 | Trace.Listeners.Clear(); 17 | Trace.Listeners.Add(new ThrowingTraceListener()); 18 | 19 | try 20 | { 21 | action(); 22 | Assert.Fail("Expected Debug.Assert to fail."); 23 | } 24 | catch (DebugAssertFailedException) 25 | { 26 | // PASS 27 | } 28 | finally 29 | { 30 | Trace.Listeners.Clear(); 31 | Trace.Listeners.AddRange(listeners); 32 | } 33 | } 34 | } 35 | #endif 36 | 37 | private class DebugAssertFailedException : Exception 38 | { 39 | } 40 | 41 | private class ThrowingTraceListener : TraceListener 42 | { 43 | public override void Fail(string? message) => throw new DebugAssertFailedException(); 44 | 45 | public override void Fail(string? message, string? detailMessage) => throw new DebugAssertFailedException(); 46 | 47 | public override void Write(string? message) 48 | { 49 | } 50 | 51 | public override void WriteLine(string? message) 52 | { 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", 3 | "shadowCopy": false 4 | } 5 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Unmarshalled.Tests/COMTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma warning disable IDE0005 5 | 6 | using Windows.Win32; 7 | using Windows.Win32.System.Com; 8 | 9 | public class COMTests 10 | { 11 | #if NET7_0_OR_GREATER 12 | [Fact] 13 | public void COMStaticGuid() 14 | { 15 | Assert.Equal(typeof(IPersistFile).GUID, IPersistFile.IID_Guid); 16 | Assert.Equal(typeof(IPersistFile).GUID, GetGuid()); 17 | } 18 | 19 | private static Guid GetGuid() 20 | where T : IComIID 21 | => T.Guid; 22 | #endif 23 | } 24 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Unmarshalled.Tests/ComHelpers.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #if NET7_0_OR_GREATER 5 | 6 | using System.Runtime.InteropServices; 7 | using Windows.Win32.Foundation; 8 | using Windows.Win32.System.Com; 9 | 10 | namespace Windows.Win32; 11 | 12 | // The `unsafe` modifier is only allowed to appear on the class declaration -- not the partial method declaration. 13 | // See https://github.com/dotnet/csharplang/discussions/7298 for more. 14 | internal unsafe partial class ComHelpers 15 | { 16 | static partial void PopulateIUnknownImpl(IUnknown.Vtbl* vtable) 17 | where TComInterface : unmanaged 18 | { 19 | // IUnknown member initialization of the v-table would go here. 20 | vtable->QueryInterface_1 = TestComWrappers.ComWrappersForIUnknown.QueryInterface_1; 21 | vtable->AddRef_2 = TestComWrappers.ComWrappersForIUnknown.AddRef_2; 22 | vtable->Release_3 = TestComWrappers.ComWrappersForIUnknown.Release_3; 23 | } 24 | 25 | private unsafe class TestComWrappers : ComWrappers 26 | { 27 | internal static readonly IUnknown.Vtbl ComWrappersForIUnknown = GetComWrappersUnknown(); 28 | 29 | // Abstracts that need implementation 30 | protected override unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) 31 | { 32 | count = 0; 33 | return null; 34 | } 35 | 36 | protected override object? CreateObject(nint externalComObject, CreateObjectFlags flags) => null; 37 | 38 | protected override void ReleaseObjects(global::System.Collections.IEnumerable objects) => throw new NotImplementedException(); 39 | 40 | private static IUnknown.Vtbl GetComWrappersUnknown() 41 | { 42 | GetIUnknownImpl(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease); 43 | return new IUnknown.Vtbl() 44 | { 45 | QueryInterface_1 = (delegate* unmanaged[Stdcall])fpQueryInterface, 46 | AddRef_2 = (delegate* unmanaged[Stdcall])fpAddRef, 47 | Release_3 = (delegate* unmanaged[Stdcall])fpRelease, 48 | }; 49 | } 50 | } 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Unmarshalled.Tests/GeneratedForm.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #pragma warning disable CA1812 // dead code 5 | #pragma warning disable CS0168 // Variable is declared but never used 6 | 7 | using Windows.Win32; 8 | using Windows.Win32.Foundation; 9 | using Windows.Win32.System.Com; 10 | using Windows.Win32.System.Com.Events; 11 | using Windows.Win32.System.Variant; 12 | 13 | /// 14 | /// Contains "tests" that never run. Merely compiling is enough to verify the generated code has the right API shape. 15 | /// 16 | internal static unsafe class GeneratedForm 17 | { 18 | private static unsafe void COMStructsPreserveSig() 19 | { 20 | IEventSubscription o = default; 21 | 22 | // Default is non-preservesig 23 | VARIANT v = o.GetPublisherProperty(null); 24 | BSTR bstr = o.MethodName; 25 | 26 | // NativeMethods.json opts into PreserveSig for these particular methods. 27 | HRESULT hr = o.GetSubscriberProperty(null, out v); 28 | hr = o.get_MachineName(out SysFreeStringSafeHandle sh); 29 | o.MachineName = bstr; 30 | } 31 | 32 | #if NET5_0_OR_GREATER 33 | private static unsafe void IStream_GetsCCW() 34 | { 35 | IStream.Vtbl vtbl; 36 | IStream.PopulateVTable(&vtbl); 37 | } 38 | #endif 39 | 40 | #if NET7_0_OR_GREATER 41 | private static unsafe void GetVTable() 42 | { 43 | IUnknown.Vtbl* vtbl = GetVtable(); 44 | 45 | static IUnknown.Vtbl* GetVtable() 46 | where T : IVTable 47 | => T.VTable; 48 | } 49 | #endif 50 | 51 | private static unsafe void IUnknownGetsVtbl() 52 | { 53 | // WinForms needs the v-table to be declared for these base interfaces. 54 | IUnknown.Vtbl v; 55 | IDispatch.Vtbl v2; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Unmarshalled.Tests/GenerationSandbox.Unmarshalled.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Unmarshalled.Tests/NativeMethods.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "..\\..\\src\\Microsoft.Windows.CsWin32\\settings.schema.json", 3 | "emitSingleFile": true, 4 | "multiTargetingFriendlyAPIs": true, 5 | "allowMarshaling": false, 6 | "comInterop": { 7 | "preserveSigMethods": [ 8 | "IEventSubscription.GetSubscriberProperty", 9 | "IEventSubscription.get_MachineName" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/GenerationSandbox.Unmarshalled.Tests/NativeMethods.txt: -------------------------------------------------------------------------------- 1 | IEventSubscription 2 | IPersistFile 3 | IStream 4 | -------------------------------------------------------------------------------- /test/GenerationSandbox.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net9.0-windows7.0;net8.0-windows7.0;net472 6 | Exe 7 | 8 | x64 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/ConstantsTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | public class ConstantsTests : GeneratorTestBase 5 | { 6 | public ConstantsTests(ITestOutputHelper logger) 7 | : base(logger) 8 | { 9 | } 10 | 11 | [Theory] 12 | [InlineData("SECURITY_NULL_SID_AUTHORITY")] // SID_IDENTIFIER_AUTHORITY with byte[6] inline array 13 | [InlineData("g_wszStreamBufferRecordingDuration")] // string 14 | [InlineData("HWND_BOTTOM")] // A constant typed as a typedef'd struct 15 | [InlineData("D2D1_DEFAULT_FLATTENING_TOLERANCE")] // a float constant 16 | [InlineData("WIA_CATEGORY_FINISHED_FILE")] // GUID constant 17 | [InlineData("DEVPKEY_MTPBTH_IsConnected")] // DEVPROPKEY constant 18 | [InlineData("PKEY_AudioEndpoint_FormFactor")] // PROPERTYKEY constant 19 | [InlineData("X509_CERT")] // A constant defined as PCSTR 20 | [InlineData("RT_CURSOR")] // PCWSTR constant 21 | [InlineData("HBMMENU_POPUP_RESTORE")] // A HBITMAP handle as a constant 22 | [InlineData("CONDITION_VARIABLE_INIT")] // A 0 constant typed void* 23 | [InlineData("DEVPKEY_Bluetooth_DeviceAddress")] // WDK constant defined as a type from the SDK 24 | public void InterestingConstants(string name) 25 | { 26 | this.compilation = this.compilation.WithOptions(this.compilation.Options.WithPlatform(Platform.X64)); 27 | this.GenerateApi(name); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/DelegateTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | public class DelegateTests : GeneratorTestBase 5 | { 6 | public DelegateTests(ITestOutputHelper logger) 7 | : base(logger) 8 | { 9 | } 10 | 11 | [Theory] 12 | [CombinatorialData] 13 | public void InterestingDelegates( 14 | [CombinatorialValues( 15 | "LPD3DHAL_RENDERSTATECB")] // A delegate with a pointer parameter to a managed struct. 16 | string name, 17 | bool allowMarshaling) 18 | { 19 | var options = DefaultTestGeneratorOptions with 20 | { 21 | AllowMarshaling = allowMarshaling, 22 | }; 23 | this.GenerateApi(name); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/EnumTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | public class EnumTests : GeneratorTestBase 5 | { 6 | public EnumTests(ITestOutputHelper logger) 7 | : base(logger) 8 | { 9 | } 10 | 11 | [Fact] 12 | public void EnumsIncludeAssociatedConstants() 13 | { 14 | this.GenerateApi("SERVICE_ERROR"); 15 | EnumDeclarationSyntax enumDecl = Assert.IsType(this.FindGeneratedType("SERVICE_ERROR").Single()); 16 | 17 | // The enum should contain the constant. 18 | Assert.Contains(enumDecl.Members, value => value.Identifier.ValueText == "SERVICE_NO_CHANGE"); 19 | 20 | // The constant should not be generated as a separate constant. 21 | Assert.Empty(this.FindGeneratedConstant("SERVICE_NO_CHANGE")); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/NOTICE.md: -------------------------------------------------------------------------------- 1 | This folder contains winmd files obtained from other sources which we use for testing. 2 | 3 | Metadata | Source 4 | --|-- 5 | ServiceFabric.winmd | [youyuanwu/fabric-metadata](https://github.com/youyuanwu/fabric-metadata/raw/a1bcca6ad6f6a772c9e5ff4bdba80ae5e5f24cfc/.windows/winmd/ServiceFabric.winmd) 6 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/ServiceFabric.winmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/CsWin32/10ff614acb54f6d5a5dbb77c59bd8786e5c99097/test/Microsoft.Windows.CsWin32.Tests/ExternalMetadata/ServiceFabric.winmd -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/GeneratorConfiguration.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | internal record GeneratorConfiguration 5 | { 6 | internal static GeneratorConfiguration Default { get; } = new(); 7 | 8 | internal ImmutableArray InputMetadataPaths { get; init; } = CollectAssemblyMetadata("ProjectionMetadataWinmd"); 9 | 10 | internal ImmutableArray InputDocPaths { get; init; } = CollectAssemblyMetadata("ProjectionDocs"); 11 | 12 | internal string ToGlobalConfigString() 13 | { 14 | StringBuilder globalConfigBuilder = new(); 15 | globalConfigBuilder.AppendLine("is_global = true"); 16 | globalConfigBuilder.AppendLine(); 17 | AddPathsProperty("CsWin32InputMetadataPaths", this.InputMetadataPaths); 18 | AddPathsProperty("CsWin32InputDocPaths", this.InputDocPaths); 19 | 20 | return globalConfigBuilder.ToString(); 21 | 22 | void AddPathsProperty(string name, ImmutableArray paths) 23 | { 24 | if (!paths.IsEmpty) 25 | { 26 | globalConfigBuilder.AppendLine($"build_property.{name} = {string.Join("|", paths)}"); 27 | } 28 | } 29 | } 30 | 31 | private static ImmutableArray CollectAssemblyMetadata(string name) => [.. typeof(GeneratorTests).Assembly.GetCustomAttributes().Where(metadata => metadata.Key == name && metadata.Value is not null).Select(metadata => metadata.Value!)]; 32 | } 33 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/GeneratorOptionsTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | public class GeneratorOptionsTests 5 | { 6 | [Fact] 7 | public void Validate_Default() 8 | { 9 | new GeneratorOptions().Validate(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | global using System.Collections.Immutable; 5 | global using System.Reflection; 6 | global using System.Reflection.Metadata; 7 | global using System.Runtime.CompilerServices; 8 | global using System.Runtime.InteropServices; 9 | global using System.Text; 10 | global using Microsoft.CodeAnalysis; 11 | global using Microsoft.CodeAnalysis.CSharp; 12 | global using Microsoft.CodeAnalysis.CSharp.Syntax; 13 | global using Microsoft.CodeAnalysis.Testing; 14 | global using Microsoft.CodeAnalysis.Text; 15 | global using Microsoft.Windows.CsWin32; 16 | global using Xunit; 17 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/MacrosTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | public class MacrosTests : GeneratorTestBase 5 | { 6 | public MacrosTests(ITestOutputHelper logger) 7 | : base(logger) 8 | { 9 | } 10 | 11 | [Theory, PairwiseData] 12 | public void MacroAPIsGenerateWithAppropriateVisibility(bool publicVisibility) 13 | { 14 | this.generator = this.CreateGenerator(DefaultTestGeneratorOptions with { Public = publicVisibility }); 15 | Assert.True(this.generator.TryGenerate("MAKELONG", CancellationToken.None)); 16 | this.CollectGeneratedCode(this.generator); 17 | this.AssertNoDiagnostics(); 18 | var makelongMethod = Assert.Single(this.FindGeneratedMethod("MAKELONG")); 19 | Assert.True(makelongMethod.Modifiers.Any(publicVisibility ? SyntaxKind.PublicKeyword : SyntaxKind.InternalKeyword)); 20 | } 21 | 22 | [Theory] 23 | [MemberData(nameof(AvailableMacros))] 24 | public void MacroAPIsGenerate(string macro) 25 | { 26 | this.generator = this.CreateGenerator(); 27 | Assert.True(this.generator.TryGenerate(macro, CancellationToken.None)); 28 | this.CollectGeneratedCode(this.generator); 29 | this.AssertNoDiagnostics(); 30 | Assert.Single(this.FindGeneratedMethod(macro)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/Microsoft.Windows.CsWin32.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | Exe 6 | 7 | 8 | 9 | 10 | <_AssemblyMetadata1 Include="@(ProjectionMetadataWinmd)"> 11 | %(Identity) 12 | 13 | 14 | 15 | <_AssemblyMetadata2 Include="@(ProjectionDocs)"> 16 | %(Identity) 17 | 18 | 19 | 20 | 21 | 22 | 23 | PreserveNewest 24 | 25 | 26 | PreserveNewest 27 | 28 | 29 | PreserveNewest 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/MultiMetadataTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | public class MultiMetadataTests : GeneratorTestBase 5 | { 6 | public MultiMetadataTests(ITestOutputHelper logger) 7 | : base(logger) 8 | { 9 | } 10 | 11 | [Theory, PairwiseData] 12 | public void BasicServiceFabric(bool allowMarshaling) 13 | { 14 | this.generator = this.CreateSuperGenerator(DefaultMetadataPaths.Concat(new[] { ServiceFabricMetadataPath }).ToArray(), DefaultTestGeneratorOptions with { AllowMarshaling = allowMarshaling }); 15 | Assert.True(this.generator.TryGenerate("IFabricStringResult", CancellationToken.None)); 16 | this.CollectGeneratedCode(this.generator); 17 | this.AssertNoDiagnostics(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/MyReferenceAssemblies.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | internal static class MyReferenceAssemblies 5 | { 6 | #pragma warning disable SA1202 // Elements should be ordered by access - because field initializer depend on each other 7 | private static readonly ImmutableArray AdditionalLegacyPackages = ImmutableArray.Create( 8 | new PackageIdentity("Microsoft.Windows.SDK.Contracts", "10.0.22621.2428")); 9 | 10 | private static readonly ImmutableArray AdditionalModernPackages = AdditionalLegacyPackages.AddRange(ImmutableArray.Create( 11 | ExtraPackages.Unsafe, 12 | ExtraPackages.Memory, 13 | ExtraPackages.Registry)); 14 | 15 | internal static readonly ReferenceAssemblies NetStandard20 = ReferenceAssemblies.NetStandard.NetStandard20.AddPackages(AdditionalModernPackages); 16 | #pragma warning restore SA1202 // Elements should be ordered by access 17 | 18 | internal static class NetFramework 19 | { 20 | internal static readonly ReferenceAssemblies Net35 = ReferenceAssemblies.NetFramework.Net35.WindowsForms.AddPackages(AdditionalLegacyPackages); 21 | internal static readonly ReferenceAssemblies Net472 = ReferenceAssemblies.NetFramework.Net472.WindowsForms.AddPackages(AdditionalModernPackages); 22 | } 23 | 24 | internal static class Net 25 | { 26 | internal static readonly ReferenceAssemblies Net80 = ReferenceAssemblies.Net.Net80.AddPackages(AdditionalModernPackages); 27 | internal static readonly ReferenceAssemblies Net90 = ReferenceAssemblies.Net.Net90.AddPackages(AdditionalModernPackages); 28 | } 29 | 30 | internal static class ExtraPackages 31 | { 32 | internal static readonly PackageIdentity Unsafe = new PackageIdentity("System.Runtime.CompilerServices.Unsafe", "6.0.0"); 33 | internal static readonly PackageIdentity Memory = new PackageIdentity("System.Memory", "4.5.5"); 34 | internal static readonly PackageIdentity Registry = new PackageIdentity("Microsoft.Win32.Registry", "5.0.0"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/NumberedLineWriter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | internal class NumberedLineWriter : TextWriter 5 | { 6 | private readonly ITestOutputHelper logger; 7 | private readonly StringBuilder lineBuilder = new StringBuilder(); 8 | private int lineNumber; 9 | 10 | internal NumberedLineWriter(ITestOutputHelper logger) 11 | { 12 | this.logger = logger; 13 | } 14 | 15 | public override Encoding Encoding => Encoding.Unicode; 16 | 17 | public override void WriteLine(string? value) 18 | { 19 | this.logger.WriteLine($"{++this.lineNumber,6}: {this.lineBuilder}{value}"); 20 | this.lineBuilder.Clear(); 21 | } 22 | 23 | public override void Write(string? value) 24 | { 25 | if (value is null) 26 | { 27 | return; 28 | } 29 | 30 | if (value.EndsWith("\r\n", StringComparison.Ordinal)) 31 | { 32 | this.WriteLine(value.Substring(0, value.Length - 2)); 33 | } 34 | else if (value.EndsWith("\n", StringComparison.Ordinal)) 35 | { 36 | this.WriteLine(value.Substring(0, value.Length - 1)); 37 | } 38 | else 39 | { 40 | this.lineBuilder.Append(value); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/TestUtils.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Text.RegularExpressions; 5 | 6 | internal static class TestUtils 7 | { 8 | private const string ExpectedGeneratedSourceLineEnding = "\r\n"; 9 | private static readonly Regex NewLineRegex = new(@"\r?\n"); 10 | 11 | public static string NormalizeToExpectedLineEndings(string text) 12 | { 13 | return NewLineRegex.Replace(text, ExpectedGeneratedSourceLineEnding); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/Microsoft.Windows.CsWin32.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", 3 | "shadowCopy": false 4 | } 5 | -------------------------------------------------------------------------------- /test/SpellChecker/NativeMethods.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "..\\..\\src\\Microsoft.Windows.CsWin32\\settings.schema.json" 3 | } 4 | -------------------------------------------------------------------------------- /test/SpellChecker/NativeMethods.txt: -------------------------------------------------------------------------------- 1 | CLSCTX 2 | CoCreateInstance 3 | CoTaskMemFree 4 | ISpellChecker 5 | ISpellCheckerFactory 6 | S_FALSE 7 | S_OK 8 | SpellCheckerFactory 9 | -------------------------------------------------------------------------------- /test/SpellChecker/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using Windows.Win32; 5 | using Windows.Win32.Foundation; 6 | using Windows.Win32.Globalization; 7 | using Windows.Win32.System.Com; 8 | using static Windows.Win32.PInvoke; 9 | 10 | unsafe 11 | { 12 | var spellCheckerFactory = (ISpellCheckerFactory)new SpellCheckerFactory(); 13 | 14 | BOOL supported = spellCheckerFactory.IsSupported("en-US"); 15 | 16 | if (!supported) 17 | { 18 | return; 19 | } 20 | 21 | ISpellChecker spellChecker = spellCheckerFactory.CreateSpellChecker("en-US"); 22 | 23 | var text = @"""Cann I I haev some?"""; 24 | 25 | Console.WriteLine(@"Check {0}", text); 26 | 27 | IEnumSpellingError errors = spellChecker.Check(text); 28 | 29 | Span suggestionResult = new PWSTR[1]; 30 | while (true) 31 | { 32 | if (errors.Next(out ISpellingError error).ThrowOnFailure() == HRESULT.S_FALSE) 33 | { 34 | break; 35 | } 36 | 37 | uint startIndex = error.StartIndex; 38 | uint length = error.Length; 39 | 40 | var word = text.Substring((int)startIndex, (int)length); 41 | 42 | CORRECTIVE_ACTION action = error.CorrectiveAction; 43 | 44 | switch (action) 45 | { 46 | case CORRECTIVE_ACTION.CORRECTIVE_ACTION_DELETE: 47 | Console.WriteLine(@"Delete ""{0}""", word); 48 | break; 49 | case CORRECTIVE_ACTION.CORRECTIVE_ACTION_REPLACE: 50 | PWSTR replacement = error.Replacement; 51 | Console.WriteLine(@"Replace ""{0}"" with ""{1}""", word, replacement); 52 | CoTaskMemFree(replacement); 53 | break; 54 | case CORRECTIVE_ACTION.CORRECTIVE_ACTION_GET_SUGGESTIONS: 55 | Console.WriteLine(@"Suggest replacing ""{0}"" with:", word); 56 | IEnumString suggestions = spellChecker.Suggest(word); 57 | do 58 | { 59 | suggestions.Next(suggestionResult, null); 60 | if (suggestionResult[0].Value is not null) 61 | { 62 | Console.WriteLine($"\t{suggestionResult[0]}"); 63 | CoTaskMemFree(suggestionResult[0]); 64 | } 65 | } 66 | while (suggestionResult[0].Value is not null); 67 | 68 | break; 69 | default: 70 | break; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /test/SpellChecker/SpellChecker.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Exe 6 | net8.0-windows8.0;net472 7 | false 8 | true 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/WinRTInteropTest/NativeMethods.txt: -------------------------------------------------------------------------------- 1 | BeginPaint 2 | BS_PUSHBUTTON 3 | CreateDispatcherQueueController 4 | CreateWindowExW 5 | CW_USEDEFAULT 6 | DefWindowProc 7 | DestroyWindow 8 | DispatchMessage 9 | EndPaint 10 | GetMessage 11 | GetModuleHandle 12 | HDC 13 | HMENU 14 | HMODULE 15 | HWND 16 | ICompositorDesktopInterop 17 | IDC_ARROW 18 | IDI_APPLICATION 19 | InvalidateRect 20 | LoadCursor 21 | LoadIcon 22 | MSG 23 | PAINTSTRUCT 24 | PostMessage 25 | PostQuitMessage 26 | RegisterClassExW 27 | ShowWindow 28 | TranslateMessage 29 | UpdateWindow 30 | WM_CLOSE 31 | WM_COMMAND 32 | WM_CREATE 33 | WM_DESTROY 34 | WM_PAINT 35 | WNDCLASSEXW 36 | -------------------------------------------------------------------------------- /test/WinRTInteropTest/WinRTInteropTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | WinExe 6 | net8.0-windows10.0.19041.0 7 | disable 8 | false 9 | true 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tools/Check-DotNetRuntime.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Checks whether a given .NET Core runtime is installed. 4 | #> 5 | [CmdletBinding()] 6 | Param ( 7 | [Parameter()] 8 | [ValidateSet('Microsoft.AspNetCore.App','Microsoft.NETCore.App')] 9 | [string]$Runtime='Microsoft.NETCore.App', 10 | [Parameter(Mandatory=$true)] 11 | [Version]$Version 12 | ) 13 | 14 | $dotnet = Get-Command dotnet -ErrorAction SilentlyContinue 15 | if (!$dotnet) { 16 | # Nothing is installed. 17 | Write-Output $false 18 | exit 1 19 | } 20 | 21 | Function IsVersionMatch { 22 | Param( 23 | [Parameter()] 24 | $actualVersion 25 | ) 26 | return $actualVersion -and 27 | $Version.Major -eq $actualVersion.Major -and 28 | $Version.Minor -eq $actualVersion.Minor -and 29 | (($Version.Build -eq -1) -or ($Version.Build -eq $actualVersion.Build)) -and 30 | (($Version.Revision -eq -1) -or ($Version.Revision -eq $actualVersion.Revision)) 31 | } 32 | 33 | $installedRuntimes = dotnet --list-runtimes |? { $_.Split()[0] -ieq $Runtime } |% { $v = $null; [Version]::tryparse($_.Split()[1], [ref] $v); $v } 34 | $matchingRuntimes = $installedRuntimes |? { IsVersionMatch -actualVersion $_ } 35 | if (!$matchingRuntimes) { 36 | Write-Output $false 37 | exit 1 38 | } 39 | 40 | Write-Output $true 41 | exit 0 42 | -------------------------------------------------------------------------------- /tools/Check-DotNetSdk.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Checks whether the .NET Core SDK required by this repo is installed. 4 | #> 5 | [CmdletBinding()] 6 | Param ( 7 | ) 8 | 9 | $dotnet = Get-Command dotnet -ErrorAction SilentlyContinue 10 | if (!$dotnet) { 11 | # Nothing is installed. 12 | Write-Output $false 13 | exit 1 14 | } 15 | 16 | # We need to set the current directory so dotnet considers the SDK required by our global.json file. 17 | Push-Location "$PSScriptRoot\.." 18 | try { 19 | dotnet -h 2>&1 | Out-Null 20 | if (($LASTEXITCODE -eq 129) -or # On Linux 21 | ($LASTEXITCODE -eq -2147450751) # On Windows 22 | ) { 23 | # These exit codes indicate no matching SDK exists. 24 | Write-Output $false 25 | exit 2 26 | } 27 | 28 | # The required SDK is already installed! 29 | Write-Output $true 30 | exit 0 31 | } catch { 32 | # I don't know why, but on some build agents (e.g. MicroBuild), an exception is thrown from the `dotnet` invocation when a match is not found. 33 | Write-Output $false 34 | exit 3 35 | } finally { 36 | Pop-Location 37 | } 38 | -------------------------------------------------------------------------------- /tools/Convert-PDB.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Converts between Windows PDB and Portable PDB formats. 4 | .PARAMETER DllPath 5 | The path to the DLL whose PDB is to be converted. 6 | .PARAMETER PdbPath 7 | The path to the PDB to convert. May be omitted if the DLL was compiled on this machine and the PDB is still at its original path. 8 | .PARAMETER OutputPath 9 | The path of the output PDB to write. 10 | #> 11 | [CmdletBinding()] 12 | Param( 13 | [Parameter(Mandatory=$true,Position=0)] 14 | [string]$DllPath, 15 | [Parameter()] 16 | [string]$PdbPath, 17 | [Parameter(Mandatory=$true,Position=1)] 18 | [string]$OutputPath 19 | ) 20 | 21 | if ($IsMacOS -or $IsLinux) { 22 | Write-Error "This script only works on Windows" 23 | return 24 | } 25 | 26 | $version = '1.1.0-beta2-21101-01' 27 | $baseDir = "$PSScriptRoot/../obj/tools" 28 | $pdb2pdbpath = "$baseDir/Microsoft.DiaSymReader.Pdb2Pdb.$version/tools/Pdb2Pdb.exe" 29 | if (-not (Test-Path $pdb2pdbpath)) { 30 | if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } 31 | $baseDir = (Resolve-Path $baseDir).Path # Normalize it 32 | Write-Verbose "& (& $PSScriptRoot/Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null" 33 | & (& $PSScriptRoot/Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null 34 | } 35 | 36 | $args = $DllPath,'/out',$OutputPath,'/nowarn','0021' 37 | if ($PdbPath) { 38 | $args += '/pdb',$PdbPath 39 | } 40 | 41 | Write-Verbose "$pdb2pdbpath $args" 42 | & $pdb2pdbpath $args 43 | -------------------------------------------------------------------------------- /tools/Get-ArtifactsStagingDirectory.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [switch]$CleanIfLocal 3 | ) 4 | if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { 5 | $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY 6 | } elseif ($env:RUNNER_TEMP) { 7 | $ArtifactStagingFolder = Join-Path $env:RUNNER_TEMP _artifacts 8 | } else { 9 | $ArtifactStagingFolder = [System.IO.Path]::GetFullPath("$PSScriptRoot/../obj/_artifacts") 10 | if ($CleanIfLocal -and (Test-Path $ArtifactStagingFolder)) { 11 | Remove-Item $ArtifactStagingFolder -Recurse -Force 12 | } 13 | } 14 | 15 | $ArtifactStagingFolder 16 | -------------------------------------------------------------------------------- /tools/Get-LibTemplateBasis.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns the name of the well-known branch in the Library.Template repository upon which HEAD is based. 4 | #> 5 | [CmdletBinding(SupportsShouldProcess = $true)] 6 | Param( 7 | [switch]$ErrorIfNotRelated 8 | ) 9 | 10 | # This list should be sorted in order of decreasing specificity. 11 | $branchMarkers = @( 12 | @{ commit = 'fd0a7b25ccf030bbd16880cca6efe009d5b1fffc'; branch = 'microbuild' }; 13 | @{ commit = '05f49ce799c1f9cc696d53eea89699d80f59f833'; branch = 'main' }; 14 | ) 15 | 16 | foreach ($entry in $branchMarkers) { 17 | if (git rev-list HEAD | Select-String -Pattern $entry.commit) { 18 | return $entry.branch 19 | } 20 | } 21 | 22 | if ($ErrorIfNotRelated) { 23 | Write-Error "Library.Template has not been previously merged with this repo. Please review https://github.com/AArnott/Library.Template/tree/main?tab=readme-ov-file#readme for instructions." 24 | exit 1 25 | } 26 | -------------------------------------------------------------------------------- /tools/Get-NuGetTool.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads the NuGet.exe tool and returns the path to it. 4 | .PARAMETER NuGetVersion 5 | The version of the NuGet tool to acquire. 6 | #> 7 | Param( 8 | [Parameter()] 9 | [string]$NuGetVersion='6.12.2' 10 | ) 11 | 12 | $toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" 13 | $binaryToolsPath = Join-Path $toolsPath $NuGetVersion 14 | if (!(Test-Path $binaryToolsPath)) { $null = mkdir $binaryToolsPath } 15 | $nugetPath = Join-Path $binaryToolsPath nuget.exe 16 | 17 | if (!(Test-Path $nugetPath)) { 18 | Write-Host "Downloading nuget.exe $NuGetVersion..." -ForegroundColor Yellow 19 | (New-Object System.Net.WebClient).DownloadFile("https://dist.nuget.org/win-x86-commandline/v$NuGetVersion/NuGet.exe", $nugetPath) 20 | } 21 | 22 | return (Resolve-Path $nugetPath).Path 23 | -------------------------------------------------------------------------------- /tools/Get-ProcDump.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads 32-bit and 64-bit procdump executables and returns the path to where they were installed. 4 | #> 5 | $version = '0.0.1' 6 | $baseDir = "$PSScriptRoot\..\obj\tools" 7 | $procDumpToolPath = "$baseDir\procdump.$version\bin" 8 | if (-not (Test-Path $procDumpToolPath)) { 9 | if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } 10 | $baseDir = (Resolve-Path $baseDir).Path # Normalize it 11 | & (& $PSScriptRoot\Get-NuGetTool.ps1) install procdump -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://api.nuget.org/v3/index.json | Out-Null 12 | } 13 | 14 | (Resolve-Path $procDumpToolPath).Path 15 | -------------------------------------------------------------------------------- /tools/Get-SymbolFiles.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Collect the list of PDBs built in this repo. 4 | .PARAMETER Path 5 | The directory to recursively search for PDBs. 6 | .PARAMETER Tests 7 | A switch indicating to find PDBs only for test binaries instead of only for shipping shipping binaries. 8 | #> 9 | [CmdletBinding()] 10 | param ( 11 | [parameter(Mandatory=$true)] 12 | [string]$Path, 13 | [switch]$Tests 14 | ) 15 | 16 | $ActivityName = "Collecting symbols from $Path" 17 | Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" 18 | $PDBs = Get-ChildItem -rec "$Path/*.pdb" 19 | 20 | # Filter PDBs to product OR test related. 21 | $testregex = "unittest|tests|\.test\.|WinRTInteropTest|SpellChecker" 22 | 23 | Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" 24 | $PDBsByHash = @{} 25 | $i = 0 26 | $PDBs |% { 27 | Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" -PercentComplete (100 * $i / $PDBs.Length) 28 | $hash = Get-FileHash $_ 29 | $i++ 30 | Add-Member -InputObject $_ -MemberType NoteProperty -Name Hash -Value $hash.Hash 31 | Write-Output $_ 32 | } | Sort-Object CreationTime |% { 33 | # De-dupe based on hash. Prefer the first match so we take the first built copy. 34 | if (-not $PDBsByHash.ContainsKey($_.Hash)) { 35 | $PDBsByHash.Add($_.Hash, $_.FullName) 36 | Write-Output $_ 37 | } 38 | } |? { 39 | if ($Tests) { 40 | $_.FullName -match $testregex 41 | } else { 42 | $_.FullName -notmatch $testregex 43 | } 44 | } |% { 45 | # Collect the DLLs/EXEs as well. 46 | $rootName = "$($_.Directory)/$($_.BaseName)" 47 | if ($rootName.EndsWith('.ni')) { 48 | $rootName = $rootName.Substring(0, $rootName.Length - 3) 49 | } 50 | 51 | $dllPath = "$rootName.dll" 52 | $exePath = "$rootName.exe" 53 | if (Test-Path $dllPath) { 54 | $BinaryImagePath = $dllPath 55 | } elseif (Test-Path $exePath) { 56 | $BinaryImagePath = $exePath 57 | } else { 58 | Write-Warning "`"$_`" found with no matching binary file." 59 | $BinaryImagePath = $null 60 | } 61 | 62 | if ($BinaryImagePath) { 63 | Write-Output $BinaryImagePath 64 | Write-Output $_.FullName 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tools/Get-TempToolsPath.ps1: -------------------------------------------------------------------------------- 1 | if ($env:AGENT_TEMPDIRECTORY) { 2 | $path = "$env:AGENT_TEMPDIRECTORY\$env:BUILD_BUILDID" 3 | } elseif ($env:localappdata) { 4 | $path = "$env:localappdata\gitrepos\tools" 5 | } else { 6 | $path = "$PSScriptRoot\..\obj\tools" 7 | } 8 | 9 | if (!(Test-Path $path)) { 10 | New-Item -ItemType Directory -Path $Path | Out-Null 11 | } 12 | 13 | (Resolve-Path $path).Path 14 | -------------------------------------------------------------------------------- /tools/Prepare-Legacy-Symbols.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [string]$Path 3 | ) 4 | 5 | $ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1" 6 | $ArtifactStagingFolder += '/symbols-legacy' 7 | robocopy $Path $ArtifactStagingFolder /mir /njh /njs /ndl /nfl 8 | $WindowsPdbSubDirName = 'symstore' 9 | 10 | Get-ChildItem "$ArtifactStagingFolder\*.pdb" -Recurse |% { 11 | $dllPath = "$($_.Directory)/$($_.BaseName).dll" 12 | $exePath = "$($_.Directory)/$($_.BaseName).exe" 13 | if (Test-Path $dllPath) { 14 | $BinaryImagePath = $dllPath 15 | } elseif (Test-Path $exePath) { 16 | $BinaryImagePath = $exePath 17 | } else { 18 | Write-Warning "`"$_`" found with no matching binary file." 19 | $BinaryImagePath = $null 20 | } 21 | 22 | if ($BinaryImagePath) { 23 | # Convert the PDB to legacy Windows PDBs 24 | Write-Host "Converting PDB for $_" -ForegroundColor DarkGray 25 | $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName" 26 | if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null } 27 | $legacyPdbPath = "$WindowsPdbDir\$($_.BaseName).pdb" 28 | & "$PSScriptRoot\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath $legacyPdbPath 29 | if ($LASTEXITCODE -ne 0) { 30 | Write-Warning "PDB conversion of `"$_`" failed." 31 | } 32 | 33 | Move-Item $legacyPdbPath $_ -Force 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tools/artifacts/APIScanInputs.ps1: -------------------------------------------------------------------------------- 1 | $inputs = & "$PSScriptRoot/symbols.ps1" 2 | 3 | if (!$inputs) { return } 4 | 5 | # Filter out specific files that target OS's that are not subject to APIScan. 6 | # Files that are subject but are not supported must be scanned and an SEL exception filed. 7 | $outputs = @{} 8 | $forbiddenSubPaths = @( 9 | , 'linux-*' 10 | , 'osx*' 11 | ) 12 | 13 | $inputs.GetEnumerator() | % { 14 | $list = $_.Value | ? { 15 | $path = $_.Replace('\', '/') 16 | return !($forbiddenSubPaths | ? { $path -like "*/$_/*" }) 17 | } 18 | $outputs[$_.Key] = $list 19 | } 20 | 21 | 22 | $outputs 23 | -------------------------------------------------------------------------------- /tools/artifacts/LocBin.ps1: -------------------------------------------------------------------------------- 1 | # Identify LCE files and the binary files they describe 2 | $BinRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin") 3 | if (!(Test-Path $BinRoot)) { return } 4 | 5 | $FilesToCopy = @() 6 | $FilesToCopy += Get-ChildItem -Recurse -File -Path $BinRoot |? { $_.FullName -match '\\Localize\\' } 7 | 8 | Get-ChildItem -rec "$BinRoot\*.lce" -File | % { 9 | $FilesToCopy += $_ 10 | $FilesToCopy += $_.FullName.SubString(0, $_.FullName.Length - 4) 11 | } 12 | 13 | $FilesToCopy += Get-ChildItem -rec "$BinRoot\*.lcg" -File | % { [xml](Get-Content $_) } | % { $_.lcx.name } 14 | 15 | @{ 16 | "$BinRoot" = $FilesToCopy; 17 | } 18 | -------------------------------------------------------------------------------- /tools/artifacts/VSInsertion.ps1: -------------------------------------------------------------------------------- 1 | # This artifact captures everything needed to insert into VS (NuGet packages, insertion metadata, etc.) 2 | 3 | [CmdletBinding()] 4 | Param ( 5 | ) 6 | 7 | if ($IsMacOS -or $IsLinux) { 8 | # We only package up for insertions on Windows agents since they are where optprof can happen. 9 | Write-Verbose "Skipping VSInsertion artifact since we're not on Windows." 10 | return @{} 11 | } 12 | 13 | $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") 14 | $BuildConfiguration = $env:BUILDCONFIGURATION 15 | if (!$BuildConfiguration) { 16 | $BuildConfiguration = 'Debug' 17 | } 18 | 19 | $PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" 20 | $NuGetPackages = "$PackagesRoot/NuGet" 21 | $VsixPackages = "$PackagesRoot/Vsix" 22 | 23 | if (!(Test-Path $NuGetPackages)) { 24 | Write-Warning "Skipping because NuGet packages haven't been built yet." 25 | return @{} 26 | } 27 | 28 | $result = @{ 29 | "$NuGetPackages" = (Get-ChildItem $NuGetPackages -Recurse) 30 | } 31 | 32 | if (Test-Path $VsixPackages) { 33 | $result["$PackagesRoot"] += Get-ChildItem $VsixPackages -Recurse 34 | } 35 | 36 | if ($env:IsOptProf) { 37 | $VSRepoPackages = "$PackagesRoot/VSRepo" 38 | $result["$VSRepoPackages"] = (Get-ChildItem "$VSRepoPackages\*.VSInsertionMetadata.*.nupkg"); 39 | } 40 | 41 | $result 42 | -------------------------------------------------------------------------------- /tools/artifacts/Variables.ps1: -------------------------------------------------------------------------------- 1 | # This artifact captures all variables defined in the ..\variables folder. 2 | # It "snaps" the values of these variables where we can compute them during the build, 3 | # and otherwise captures the scripts to run later during an Azure Pipelines environment release. 4 | 5 | $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot/../..") 6 | $ArtifactBasePath = "$RepoRoot/obj/_artifacts" 7 | $VariablesArtifactPath = Join-Path $ArtifactBasePath variables 8 | if (-not (Test-Path $VariablesArtifactPath)) { New-Item -ItemType Directory -Path $VariablesArtifactPath | Out-Null } 9 | 10 | # Copy variables, either by value if the value is calculable now, or by script 11 | Get-ChildItem "$PSScriptRoot/../variables" |% { 12 | $value = $null 13 | if (-not $_.BaseName.StartsWith('_')) { # Skip trying to interpret special scripts 14 | # First check the environment variables in case the variable was set in a queued build 15 | # Always use all caps for env var access because Azure Pipelines converts variables to upper-case for env vars, 16 | # and on non-Windows env vars are case sensitive. 17 | $envVarName = $_.BaseName.ToUpper() 18 | if (Test-Path env:$envVarName) { 19 | $value = Get-Content "env:$envVarName" 20 | } 21 | 22 | # If that didn't give us anything, try executing the script right now from its original position 23 | if (-not $value) { 24 | $value = & $_.FullName 25 | } 26 | 27 | if ($value) { 28 | # We got something, so wrap it with quotes so it's treated like a literal value. 29 | $value = "'$value'" 30 | } 31 | } 32 | 33 | # If that didn't get us anything, just copy the script itself 34 | if (-not $value) { 35 | $value = Get-Content -LiteralPath $_.FullName 36 | } 37 | 38 | Set-Content -LiteralPath "$VariablesArtifactPath/$($_.Name)" -Value $value 39 | } 40 | 41 | @{ 42 | "$VariablesArtifactPath" = (Get-ChildItem $VariablesArtifactPath -Recurse); 43 | } 44 | -------------------------------------------------------------------------------- /tools/artifacts/build_logs.ps1: -------------------------------------------------------------------------------- 1 | $ArtifactStagingFolder = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" 2 | 3 | if (!(Test-Path $ArtifactStagingFolder/build_logs)) { return } 4 | 5 | @{ 6 | "$ArtifactStagingFolder/build_logs" = (Get-ChildItem -Recurse "$ArtifactStagingFolder/build_logs") 7 | } 8 | -------------------------------------------------------------------------------- /tools/artifacts/coverageResults.ps1: -------------------------------------------------------------------------------- 1 | $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") 2 | 3 | $coverageFiles = @(Get-ChildItem "$RepoRoot/test/*.cobertura.xml" -Recurse | Where {$_.FullName -notlike "*/In/*" -and $_.FullName -notlike "*\In\*" }) 4 | 5 | # Prepare code coverage reports for merging on another machine 6 | $repoRoot = $env:SYSTEM_DEFAULTWORKINGDIRECTORY 7 | if (!$repoRoot) { $repoRoot = $env:GITHUB_WORKSPACE } 8 | if ($repoRoot) { 9 | Write-Host "Substituting $repoRoot with `"{reporoot}`"" 10 | $coverageFiles |% { 11 | $content = Get-Content -LiteralPath $_ |% { $_ -Replace [regex]::Escape($repoRoot), "{reporoot}" } 12 | Set-Content -LiteralPath $_ -Value $content -Encoding UTF8 13 | } 14 | } else { 15 | Write-Warning "coverageResults: Cloud build not detected. Machine-neutral token replacement skipped." 16 | } 17 | 18 | if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return } 19 | 20 | @{ 21 | $RepoRoot = ( 22 | $coverageFiles + 23 | (Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse) 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /tools/artifacts/deployables.ps1: -------------------------------------------------------------------------------- 1 | $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") 2 | $BuildConfiguration = $env:BUILDCONFIGURATION 3 | if (!$BuildConfiguration) { 4 | $BuildConfiguration = 'Debug' 5 | } 6 | 7 | $PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" 8 | 9 | if (!(Test-Path $PackagesRoot)) { return } 10 | 11 | @{ 12 | "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse) 13 | } 14 | -------------------------------------------------------------------------------- /tools/artifacts/projectAssetsJson.ps1: -------------------------------------------------------------------------------- 1 | $ObjRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\obj") 2 | 3 | if (!(Test-Path $ObjRoot)) { return } 4 | 5 | @{ 6 | "$ObjRoot" = ( 7 | (Get-ChildItem "$ObjRoot\project.assets.json" -Recurse) 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /tools/artifacts/symbols.ps1: -------------------------------------------------------------------------------- 1 | $BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") 2 | if (!(Test-Path $BinPath)) { return } 3 | $symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique 4 | 5 | @{ 6 | "$BinPath" = $SymbolFiles; 7 | } 8 | -------------------------------------------------------------------------------- /tools/artifacts/testResults.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | Param( 3 | ) 4 | 5 | $result = @{} 6 | 7 | $testRoot = Resolve-Path "$PSScriptRoot\..\..\test" 8 | $result[$testRoot] = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File) 9 | 10 | $artifactStaging = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" 11 | $testlogsPath = Join-Path $artifactStaging "test_logs" 12 | if (Test-Path $testlogsPath) { 13 | $result[$testlogsPath] = Get-ChildItem $testlogsPath -Recurse; 14 | } 15 | 16 | $result 17 | -------------------------------------------------------------------------------- /tools/artifacts/test_symbols.ps1: -------------------------------------------------------------------------------- 1 | $BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") 2 | if (!(Test-Path $BinPath)) { return } 3 | $symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath -Tests | Get-Unique 4 | 5 | @{ 6 | "$BinPath" = $SymbolFiles; 7 | } 8 | -------------------------------------------------------------------------------- /tools/publish-CodeCov.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Uploads code coverage to codecov.io 4 | .PARAMETER CodeCovToken 5 | Code coverage token to use 6 | .PARAMETER PathToCodeCoverage 7 | Path to root of code coverage files 8 | .PARAMETER Name 9 | Name to upload with codecoverge 10 | .PARAMETER Flags 11 | Flags to upload with codecoverge 12 | #> 13 | [CmdletBinding()] 14 | Param ( 15 | [Parameter(Mandatory=$true)] 16 | [string]$CodeCovToken, 17 | [Parameter(Mandatory=$true)] 18 | [string]$PathToCodeCoverage, 19 | [string]$Name, 20 | [string]$Flags 21 | ) 22 | 23 | $RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path 24 | 25 | Get-ChildItem -Recurse -LiteralPath $PathToCodeCoverage -Filter "*.cobertura.xml" | % { 26 | $relativeFilePath = Resolve-Path -relative $_.FullName 27 | 28 | Write-Host "Uploading: $relativeFilePath" -ForegroundColor Yellow 29 | & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t $CodeCovToken -f $relativeFilePath -R $RepoRoot -F $Flags -n $Name 30 | } 31 | -------------------------------------------------------------------------------- /tools/variables/BusinessGroupName.ps1: -------------------------------------------------------------------------------- 1 | 'Visual Studio - VS Core' 2 | -------------------------------------------------------------------------------- /tools/variables/DotNetSdkVersion.ps1: -------------------------------------------------------------------------------- 1 | $globalJson = Get-Content -LiteralPath "$PSScriptRoot\..\..\global.json" | ConvertFrom-Json 2 | $globalJson.sdk.version 3 | -------------------------------------------------------------------------------- /tools/variables/InsertJsonValues.ps1: -------------------------------------------------------------------------------- 1 | $vstsDropNames = & "$PSScriptRoot\VstsDropNames.ps1" 2 | $BuildConfiguration = $env:BUILDCONFIGURATION 3 | if (!$BuildConfiguration) { 4 | $BuildConfiguration = 'Debug' 5 | } 6 | 7 | $BasePath = "$PSScriptRoot\..\..\bin\Packages\$BuildConfiguration\Vsix" 8 | 9 | if (Test-Path $BasePath) { 10 | $vsmanFiles = @() 11 | Get-ChildItem $BasePath *.vsman -Recurse -File |% { 12 | $version = (Get-Content $_.FullName | ConvertFrom-Json).info.buildVersion 13 | $fn = $_.Name 14 | $vsmanFiles += "$fn{$version}=https://vsdrop.corp.microsoft.com/file/v1/$vstsDropNames;$fn" 15 | } 16 | 17 | [string]::join(',',$vsmanFiles) 18 | } 19 | -------------------------------------------------------------------------------- /tools/variables/InsertPropsValues.ps1: -------------------------------------------------------------------------------- 1 | $InsertedPkgs = (& "$PSScriptRoot\..\artifacts\VSInsertion.ps1") 2 | 3 | $icv=@() 4 | foreach ($kvp in $InsertedPkgs.GetEnumerator()) { 5 | $kvp.Value |% { 6 | if ($_.Name -match "^(.*?)\.(\d+\.\d+\.\d+(?:\.\d+)?(?:-.*?)?)(?:\.symbols)?\.nupkg$") { 7 | $id = $Matches[1] 8 | $version = $Matches[2] 9 | $icv += "$id=$version" 10 | } 11 | } 12 | } 13 | 14 | Write-Output ([string]::join(',',$icv)) 15 | -------------------------------------------------------------------------------- /tools/variables/InsertTargetBranch.ps1: -------------------------------------------------------------------------------- 1 | # This is the default branch of the VS repo that we will use to insert into VS. 2 | 'main' 3 | -------------------------------------------------------------------------------- /tools/variables/InsertVersionsValues.ps1: -------------------------------------------------------------------------------- 1 | # When you need binding redirects in the VS repo updated to match 2 | # assemblies that you build here, remove the "return" statement 3 | # and update the hashtable below with the T4 macro you'll use for 4 | # your libraries as defined in the src\ProductData\AssemblyVersions.tt file. 5 | return 6 | 7 | $MacroName = 'LibraryNoDotsVersion' 8 | $SampleProject = "$PSScriptRoot\..\..\src\LibraryName" 9 | [string]::join(',',(@{ 10 | ($MacroName) = & { (dotnet nbgv get-version --project $SampleProject --format json | ConvertFrom-Json).AssemblyVersion }; 11 | }.GetEnumerator() |% { "$($_.key)=$($_.value)" })) 12 | -------------------------------------------------------------------------------- /tools/variables/IsSigned.ps1: -------------------------------------------------------------------------------- 1 | if ($env:SYSTEM_COLLECTIONID -eq 'cb55739e-4afe-46a3-970f-1b49d8ee7564') { 2 | if ($env:BUILD_REASON -eq 'Schedule') { 3 | 'true' 4 | } else { 5 | if ($env:SIGNSELECTION) { 6 | $env:SIGNSELECTION 7 | } else { 8 | 'false' 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tools/variables/LocLanguages.ps1: -------------------------------------------------------------------------------- 1 | ## For faster PR/CI builds localize only for 2 languages, ENU and JPN provide good enough coverage 2 | if ($env:BUILD_REASON -eq 'PullRequest') { 3 | 'ENU,JPN' 4 | } else { 5 | 'VS' 6 | } 7 | -------------------------------------------------------------------------------- /tools/variables/ProfilingInputsDropName.ps1: -------------------------------------------------------------------------------- 1 | if ($env:SYSTEM_TEAMPROJECT) { 2 | "ProfilingInputs/$env:SYSTEM_TEAMPROJECT/$env:BUILD_REPOSITORY_NAME/$env:BUILD_SOURCEBRANCHNAME/$env:BUILD_BUILDID" 3 | } else { 4 | Write-Warning "No Azure Pipelines build detected. No Azure Pipelines drop name will be computed." 5 | } 6 | -------------------------------------------------------------------------------- /tools/variables/SymbolsFeatureName.ps1: -------------------------------------------------------------------------------- 1 | 'Microsoft.Windows.CsWin32' 2 | -------------------------------------------------------------------------------- /tools/variables/VstsDropNames.ps1: -------------------------------------------------------------------------------- 1 | "Products/$env:SYSTEM_TEAMPROJECT/$env:BUILD_REPOSITORY_NAME/$env:BUILD_SOURCEBRANCHNAME/$env:BUILD_BUILDID" 2 | -------------------------------------------------------------------------------- /tools/variables/_all.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | <# 4 | .SYNOPSIS 5 | This script returns a hashtable of build variables that should be set 6 | at the start of a build or release definition's execution. 7 | #> 8 | 9 | [CmdletBinding(SupportsShouldProcess = $true)] 10 | param ( 11 | ) 12 | 13 | $vars = @{} 14 | 15 | Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" |% { 16 | Write-Host "Computing $($_.BaseName) variable" 17 | $vars[$_.BaseName] = & $_ 18 | } 19 | 20 | $vars 21 | -------------------------------------------------------------------------------- /tools/variables/_define.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script translates the variables returned by the _all.ps1 script 4 | into commands that instruct Azure Pipelines to actually set those variables for other pipeline tasks to consume. 5 | 6 | The build or release definition may have set these variables to override 7 | what the build would do. So only set them if they have not already been set. 8 | #> 9 | 10 | [CmdletBinding()] 11 | param ( 12 | ) 13 | 14 | (& "$PSScriptRoot\_all.ps1").GetEnumerator() |% { 15 | # Always use ALL CAPS for env var names since Azure Pipelines converts variable names to all caps and on non-Windows OS, env vars are case sensitive. 16 | $keyCaps = $_.Key.ToUpper() 17 | if ((Test-Path "env:$keyCaps") -and (Get-Content "env:$keyCaps")) { 18 | Write-Host "Skipping setting $keyCaps because variable is already set to '$(Get-Content env:$keyCaps)'." -ForegroundColor Cyan 19 | } else { 20 | Write-Host "$keyCaps=$($_.Value)" -ForegroundColor Yellow 21 | if ($env:TF_BUILD) { 22 | # Create two variables: the first that can be used by its simple name and accessible only within this job. 23 | Write-Host "##vso[task.setvariable variable=$keyCaps]$($_.Value)" 24 | # and the second that works across jobs and stages but must be fully qualified when referenced. 25 | Write-Host "##vso[task.setvariable variable=$keyCaps;isOutput=true]$($_.Value)" 26 | } elseif ($env:GITHUB_ACTIONS) { 27 | Add-Content -LiteralPath $env:GITHUB_ENV -Value "$keyCaps=$($_.Value)" 28 | } 29 | Set-Item -LiteralPath "env:$keyCaps" -Value $_.Value 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "0.3", 4 | "assemblyVersion": { 5 | "precision": "revision" 6 | }, 7 | "publicReleaseRefSpec": [ 8 | "^refs/heads/main$", 9 | "^refs/heads/v\\d+(?:\\.\\d+)?$" 10 | ], 11 | "cloudBuild": { 12 | "setVersionVariables": false 13 | } 14 | } 15 | --------------------------------------------------------------------------------