├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── Bug report form.yml │ ├── Feature request form.yml │ └── config.yml ├── labeler.yml └── workflows │ ├── autoAssign.yml │ ├── dailySummary.yml │ ├── githubMetrics.yml │ ├── issueOpened.yml │ ├── regexCommenter.yml │ ├── regexLabeler.yml │ ├── syncAdo.yml │ ├── tagPriorityLow.yml │ ├── testAction.yml │ └── weeklySummary.yml ├── README.md ├── SECURITY.md ├── diagnostics ├── README.md ├── WebView2.wprp ├── WebView2_CPU.wprp ├── code_integrity.md ├── compatibility_problem.png ├── crash.md ├── crashes.png ├── etw.md ├── gpu.md ├── install.md ├── network.md ├── task_manager_dump.md ├── test_canary.md └── version.md └── specs ├── APIReview_AllowExternalDrop.md ├── AdditionalAllowedFrameAncestors.md ├── AllowHostInputProcessing.md ├── AreBrowserAcceleratorKeysEnabled.md ├── Autofill.md ├── AutomationProvider.md ├── BackgroundColor.md ├── BrowserProcessExited.md ├── BrowserTaskManager.md ├── CDPSessionIdSupport.md ├── ClearBrowsingData.md ├── ClientCertificate.md ├── ContextMenuRequested.md ├── CookieManagement.md ├── CoreWebView2.CreateFromCOMObject.md ├── CoreWebView2ControllerOptions.DefaultBackgroundColor.md ├── CustomDataPartition.md ├── CustomDefaultDownloadLocation.md ├── CustomDownload.md ├── CustomScrollbar.md ├── DOMContentLoaded.md ├── DefaultDownloadDialog.md ├── DisableCrashReporting.md ├── DisableNavigatingBackAndForward.md ├── DragStarting.md ├── ExclusiveUserDataFolderAccess.md ├── ExecuteScriptWithResult.md ├── ExtendedNewWindowRequested.md ├── ExtendedProcessFailed.md ├── Extensions.md ├── FileTypePolicy.md ├── FrameProcesssInfo.md ├── Freeze.md ├── GetEnvironment.md ├── GetFavicon.md ├── HiddenPdfToolbarItems.md ├── HostResourceMapping.md ├── HttpStatusCode.md ├── IFramePermissionRequested.md ├── IsNonClientRegionSupportEnabled.md ├── IsPinchZoomEnabled.md ├── IsSmartScreenRequired.md ├── LaunchingExternalUriScheme.md ├── LoaderDllFolderPath.md ├── Media.md ├── MemoryUsageTargetLevel.md ├── MultiProfile.md ├── NavigateWithWebResourceRequest.md ├── NestedFrame.md ├── NewWindowSourceFrameInfo.md ├── NonClientHitTestKind.md ├── NotifyDropTargetAction.md ├── PermissionManagement.md ├── PreferredColorScheme.md ├── Print.md ├── PrintToPdf.md ├── ProcessInfo.md ├── ProgrammaticSaveAs.md ├── RasterizationScale.md ├── RestartRequested.md ├── ServerCertificate.md ├── SharedBuffer.md ├── StatusBarMessage.md ├── SystemCursorId.md ├── TrackingPrevention.md ├── UpdateRuntime.md ├── UserAgent.md ├── UserDataFolder.md ├── WPF_WebView2CompositionControl.md ├── WebAuthenticationRequested.md ├── WebMessageObjects.md ├── WebResourceRequested-CustomScheme.md ├── WebResourceResponseReceived.md ├── Workers.md ├── images ├── EdgeSettingsAppearance.png └── TrackingPreventionLevels.png ├── template.md └── wv2winrt-cacheable-properties.md /.github/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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug report form.yml: -------------------------------------------------------------------------------- 1 | name: Report a problem/bug 2 | title: '[Problem/Bug]: ' 3 | description: Report if something is not working 4 | labels: ["bug"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: 9 | Thanks for taking time to fill up the bug report! Here is [a good bug report](https://github.com/MicrosoftEdge/WebView2Feedback/issues/3648) that will help us in identifying the issue. 10 | - id: what-happened 11 | type: textarea 12 | attributes: 13 | description: Describe the issue you encountered. Callstacks and error messages are helpful. 14 | label: What happened? 15 | validations: 16 | required: true 17 | - id: importance 18 | type: dropdown 19 | attributes: 20 | label: Importance 21 | description: How important is this bug to your app? 22 | multiple: false 23 | options: 24 | - ----Please select---- 25 | - Blocking. My app's basic functions are not working due to this issue. 26 | - Important. My app's user experience is significantly compromised. 27 | - Moderate. My app's user experience is affected, but still usable. 28 | - Low. My app is not very affected, or this only affects development. 29 | validations: 30 | required: true 31 | - id: runtime-channel 32 | type: dropdown 33 | attributes: 34 | label: Runtime Channel 35 | description: Are you seeing this issue in stable release or prerelease of WebView2 runtime? 36 | multiple: true 37 | options: 38 | - Stable release (WebView2 Runtime) 39 | - Prerelease (Edge Canary/Dev/Beta) 40 | validations: 41 | required: true 42 | - type: markdown 43 | attributes: 44 | value: | 45 | **Tip:** it's recommended to test your web content in the WebView2 control against [Microsoft Edge Insider (preview) Channels (Beta, Dev, or Canary)](https://www.microsoft.com/en-us/edge/download/insider?form=MA13FJ). For more information please check out [testing app for forward-compatibility](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#test-your-app-for-forward-compatibility). 46 | - id: runtime-version 47 | type: input 48 | attributes: 49 | description: Which runtime version are you using? Instructions [here](https://github.com/MicrosoftEdge/WebView2Feedback/blob/victorhuangwq/updatetemplate/diagnostics/version.md) 50 | label: Runtime Version 51 | placeholder: (eg. 114.0.1823.79) 52 | - id: sdk-version 53 | type: input 54 | attributes: 55 | description: Which SDK version are you using? Instructions [here](https://github.com/MicrosoftEdge/WebView2Feedback/blob/victorhuangwq/updatetemplate/diagnostics/version.md) 56 | label: SDK Version 57 | placeholder: (eg. 1.0.1905-prerelease) 58 | 59 | - id: framework 60 | type: dropdown 61 | attributes: 62 | description: What UI framework are you using? 63 | label: Framework 64 | options: 65 | - ----Please select---- 66 | - WPF 67 | - Win32 68 | - Winforms 69 | - WinUI2/UWP 70 | - WinUI3/WinAppSDK 71 | - Unity Plugin 72 | - Other 73 | validations: 74 | required: true 75 | - id: os 76 | type: dropdown 77 | attributes: 78 | description: Which operating system are you seeing this issue with? 79 | label: Operating System 80 | multiple: true 81 | options: 82 | - Windows 10 83 | - Windows 11 84 | - Earlier than Windows 10 (deprecated) 85 | - Windows Server 86 | - Xbox 87 | - Hololens 88 | - Other 89 | validations: 90 | required: true 91 | 92 | - id: os-version 93 | type: input 94 | attributes: 95 | description: Version can be found in System > About or System Information 96 | label: OS Version 97 | placeholder: (e.g. 22621.2283 or 10.0.22621) 98 | validations: 99 | required: false 100 | - id: repro-steps 101 | type: textarea 102 | attributes: 103 | description: What are the steps needed to reproduce the bug? Describe the expected behavior against the actual behavior. 104 | label: Repro steps 105 | validations: 106 | required: true 107 | - id: repro-in-edge 108 | type: dropdown 109 | attributes: 110 | description: Does this issue reporduce in the Edge or Chrome browsers? 111 | label: Repros in Edge Browser 112 | options: 113 | - 'No, issue does not reproduce in the corresponding Edge version' 114 | - 'Yes, issue can be reproduced in the corresponding Edge version' 115 | validations: 116 | required: true 117 | - id: regression 118 | type: dropdown 119 | attributes: 120 | description: Was this working before, but has regressed? 121 | label: Regression 122 | options: 123 | - No, this never worked 124 | - Regression in newer Runtime 125 | - Regression in newer SDK 126 | - Don't know 127 | validations: 128 | required: true 129 | - id: last-working-version 130 | type: input 131 | attributes: 132 | description: If this is a regression, what was the last working version of SDK and Runtime? 133 | label: Last working version (if regression) 134 | placeholder: (e.g. SDK 1.0.1774.30, Runtime 114.0.1823.32) 135 | validations: 136 | required: false 137 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature request form.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | title: "[Feature]: " 3 | description: Share your idea for a new feature/API enhancement 4 | labels: ["feature request"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Thanks for taking the time to fill out this feature request. Here is an example of a [good feature request](https://github.com/MicrosoftEdge/WebView2Feedback/issues/3683) 10 | 11 | - type: textarea 12 | id: feature-need 13 | attributes: 14 | label: Describe the feature/enhancement you need 15 | description: Describe what you want to happen, or what problem you are seeing without this feature. 16 | placeholder: I need to do xyz when ... but I'm having trouble achieving this because... 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | id: usecases 22 | attributes: 23 | label: The scenario/use case where you would use this feature 24 | placeholder: e.g. our user needs to print out a report based on a pre-defined template. We need to set the print options in a dialog box with values defined in the template. 25 | validations: 26 | required: true 27 | 28 | - type: dropdown 29 | id: importance 30 | attributes: 31 | label: How important is this request to you? 32 | options: 33 | - ----Please select---- 34 | - Critical. My app's basic functions wouldn't work without it. 35 | - Impactful. My app's user experience would be significantly compromised without it. 36 | - Nice to have. There are other ways to tackle this, but having official API support would be beneficial. 37 | validations: 38 | required: true 39 | - type: markdown 40 | attributes: 41 | value: | 42 | ## ---Helpful additional info--- 43 | 44 | - type: textarea 45 | id: suggested-implementation 46 | attributes: 47 | label: Suggested implementation 48 | description: If you have solution ideas you'd like to suggest, please describe here. 49 | placeholder: I'd like to suggest... 50 | validations: 51 | required: false 52 | - type: textarea 53 | id: app-background 54 | attributes: 55 | label: What does your app do? Is there a pending deadline for this request? 56 | description: If you haven't shared before, it would be helpful to understand what your app does, how WebView2 is used, and if there's any pending timeline. 57 | placeholder: e.g. our app use WebView2 to handle form submission and printing in hospital kiosks. We need to release in this December. 58 | validations: 59 | required: false 60 | 61 | - type: markdown 62 | attributes: 63 | value: | 64 | ## ---How to add a '+1' reply for this request--- 65 | We welcome other developers who saw the original post to indicate they also want this feature. Please reply with these info to help us prioritize: 66 | - Your use cases/scenario as it may differ from the original post 67 | - How important is this request to you? 68 | - Additionally, any context such as what does your app do, and any pending timeline 69 | 70 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | contact_links: 2 | - name: WebView2 Questions and Answers 3 | url: https://github.com/MicrosoftEdge/WebView2Feedback/discussions/new?category=q-a 4 | about: Ask the community for help 5 | - name: WebView2 Tips and Tricks 6 | url: https://github.com/MicrosoftEdge/WebView2Feedback/discussions/new?category=tips-and-tricks 7 | about: Share tips and tricks you've learned for using WebView2 8 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | regression: 2 | - '(Regression in newer Runtime|Regression in newer SDK)' 3 | 4 | bluescreen: 5 | - '(blue screen|bug check|BSOD|bugcheck)' -------------------------------------------------------------------------------- /.github/workflows/autoAssign.yml: -------------------------------------------------------------------------------- 1 | name: Auto Assign 2 | on: 3 | issues: 4 | types: [labeled] 5 | jobs: 6 | run: 7 | runs-on: ubuntu-latest 8 | 9 | permissions: 10 | issues: write 11 | 12 | steps: 13 | - uses: wow-actions/auto-assign@v3 14 | with: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | assignees: ambikakunnath 17 | includeLabels: regression 18 | - uses: wow-actions/auto-assign@v3 19 | with: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | assignees: ambikakunnath 22 | includeLabels: bluescreen 23 | -------------------------------------------------------------------------------- /.github/workflows/dailySummary.yml: -------------------------------------------------------------------------------- 1 | name: get issue summary of yesterday 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 1 * * *' 7 | 8 | jobs: 9 | alert: 10 | runs-on: ubuntu-latest 11 | name: get summary 12 | steps: 13 | - uses: shangminx/Auto-Digest@main 14 | id: getsummary 15 | with: 16 | daily_or_weekly: 'daily' 17 | - uses: plantree/github-actions-issue-notify-teams@main 18 | with: 19 | type: daily-report 20 | message: ${{ steps.getsummary.outputs.dailysummary }} 21 | webhook: ${{ secrets.WEBHOOK }} 22 | -------------------------------------------------------------------------------- /.github/workflows/githubMetrics.yml: -------------------------------------------------------------------------------- 1 | name: Score Issue 2 | 3 | on: 4 | # On issue changes and issue comments, the action will update the 5 | # corresponding issue. 6 | issue_comment: 7 | types: [created, edited, deleted] 8 | issues: 9 | types: [opened, edited, deleted, labeled, unlabeled] 10 | # But we also run once daily to update a bunch of random issues. 11 | # This way we can hopefully pick up issues that got new reactions 12 | # (reactions do not trigger issue changes). 13 | workflow_dispatch: 14 | schedule: 15 | - cron: '0 0 * * *' 16 | 17 | permissions: 18 | id-token: write 19 | contents: read 20 | 21 | jobs: 22 | metrics: 23 | runs-on: windows-latest 24 | steps: 25 | - name: Azure login 26 | uses: azure/login@v2 27 | with: 28 | client-id: ${{ secrets.AZURE_CLIENT_ID }} 29 | tenant-id: ${{ secrets.AZURE_TENANT_ID }} 30 | subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} 31 | - uses: champnic/Porpoise@azurecli 32 | env: 33 | GH_PAT: '${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}' 34 | GH_OWNER: 'MicrosoftEdge' 35 | GH_REPO: 'WebView2Feedback' 36 | GH_TRACKED_LABELS: 'tracked' 37 | ADO_PAT: '${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}' 38 | ADO_ORG: 'microsoft' 39 | ADO_PROJECT: 'edge' 40 | COEFF_VERSION: '0.1.1' # Not going to rev this, but updating NEG_REACTIONS from -1 to 2, and MENTIONS from 5 to 10. 41 | COEFF_UNIQUE_USERS: '10' 42 | COEFF_POS_REACTIONS: '5' 43 | COEFF_NEG_REACTIONS: '2' 44 | COEFF_NEUTRAL_REACTIONS: '2' 45 | COEFF_POS_COMMENT_REACTIONS: '1' 46 | COEFF_NON_MEMBER_COMMENTS: '1' 47 | COEFF_MEMBER_COMMENTS: '0' 48 | COEFF_MENTIONS: '10' 49 | -------------------------------------------------------------------------------- /.github/workflows/issueOpened.yml: -------------------------------------------------------------------------------- 1 | name: get security issue by title and body 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | jobs: 8 | alert: 9 | runs-on: ubuntu-latest 10 | name: get security issue by title and body 11 | steps: 12 | - name: filter issue by keyword and send email 13 | id: script 14 | uses: ElyssaJyu/GH-Auto-Digest-Bot@main 15 | with: 16 | email_password: ${{ secrets.EMAIL_PASSWORD }} 17 | sender_email: ${{secrets.SENDER_EMAIL}} 18 | recipient_email: ${{secrets.RECIPIENT_EMAIL}} 19 | - name: need send to teams 20 | if: ${{ steps.script.outputs.need_attention == 'true'}} 21 | uses: plantree/github-actions-issue-notify-teams@main 22 | with: 23 | type: new-issue 24 | message: ${{ steps.script.outputs.issue_info}} 25 | webhook: ${{ secrets.WEBHOOK }} 26 | - name: do not need send 27 | if: ${{ steps.script.outputs.need_attention == 'false'}} 28 | run: echo '${{ github.event.issue.html_url }}' 29 | -------------------------------------------------------------------------------- /.github/workflows/regexCommenter.yml: -------------------------------------------------------------------------------- 1 | name: "Auto comment on issues on regex match" 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | permissions: 8 | issues: write 9 | 10 | jobs: 11 | auto-comment: 12 | runs-on: ubuntu-latest 13 | steps: 14 | 15 | - uses: actions-ecosystem/action-regex-match@v2 16 | id: regex-match 17 | with: 18 | text: ${{ github.event.issue.title }} ${{ github.event.issue.body }} 19 | regex: '\bcrash\b' 20 | flags: i 21 | 22 | - uses: actions-ecosystem/action-create-comment@v1 23 | if: ${{ steps.regex-match.outputs.match != '' }} 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | body: | 27 | Hi, @${{ github.actor }}! 28 | 29 | It seems that your issue contains the word "crash". If you have not already, could you attach a crash dump as a comment? 30 | 31 | WV2 crash dumps are located in a subfolder of the app's user data folder (UDF): `\EBWebView\Crashpad\reports\`. By default, the user data folder is created in the app's folder with a name like `.exe.WebView2`. Refer to [Crash Diagnostics](https://github.com/MicrosoftEdge/WebView2Feedback/blob/main/diagnostics/crash.md) for more information. 32 | 33 | Thank you for your cooperation! 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/regexLabeler.yml: -------------------------------------------------------------------------------- 1 | name: "Issue Labeler" 2 | on: 3 | issues: 4 | types: [opened, edited] 5 | 6 | permissions: 7 | issues: write 8 | contents: read 9 | 10 | jobs: 11 | triage: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: github/issue-labeler@v3.2 15 | with: 16 | configuration-path: .github/labeler.yml 17 | enable-versioned-regex: 0 18 | include-title: 1 19 | repo-token: ${{ github.token }} 20 | - uses: wow-actions/auto-assign@v3 21 | with: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | assignees: ambikakunnath 24 | includeLabels: bluescreen 25 | - uses: wow-actions/auto-assign@v3 26 | with: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | assignees: ambikakunnath 29 | includeLabels: regression 30 | -------------------------------------------------------------------------------- /.github/workflows/syncAdo.yml: -------------------------------------------------------------------------------- 1 | name: Sync ADO Issue 2 | 3 | on: 4 | issues: 5 | types: [labeled, closed, reopened] 6 | 7 | permissions: 8 | id-token: write 9 | contents: read 10 | 11 | jobs: 12 | alert: 13 | runs-on: windows-latest 14 | name: Syncing to Azure DevOps 15 | steps: 16 | - name: Azure login 17 | uses: azure/login@v2 18 | with: 19 | client-id: ${{ secrets.AZURE_CLIENT_ID }} 20 | tenant-id: ${{ secrets.AZURE_TENANT_ID }} 21 | subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} 22 | - name: Sync to ADO 23 | uses: champnic/github-actions-issue-to-work-item@simple-sync-azurecli 24 | env: 25 | github_token: "${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}" 26 | with: 27 | label: 'tracked' 28 | ado_organization: 'microsoft' 29 | ado_project: 'Edge' 30 | ado_area_path: 'Edge\Web Experience\WebView2' 31 | ado_tags: 'WV2_GitHub' 32 | ado_gh_closed_tag: 'WV2_GitHub_Closed' 33 | -------------------------------------------------------------------------------- /.github/workflows/tagPriorityLow.yml: -------------------------------------------------------------------------------- 1 | name: tag low priority issues 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | permissions: 7 | issues: write 8 | 9 | jobs: 10 | tag-low-priority-issues: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: '20.x' 16 | - run: npm install azure-devops-node-api 17 | - uses: actions/github-script@v7 18 | env: 19 | ado_token: '${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}' 20 | query_id: '6777cf01-7065-42ca-99ca-ba0d7b77d8fd' 21 | with: 22 | script: | 23 | const azdev = require('azure-devops-node-api') 24 | 25 | // Get the ADO client 26 | try { 27 | const orgUrl = "https://dev.azure.com/microsoft"; 28 | const adoAuthHandler = azdev.getPersonalAccessTokenHandler(process.env.ado_token); 29 | const adoConnection = new azdev.WebApi(orgUrl, adoAuthHandler); 30 | adoClient = await adoConnection.getWorkItemTrackingApi(); 31 | } catch (e) { 32 | console.error(e); 33 | core.setFailed('Could not connect to ADO'); 34 | return; 35 | } 36 | 37 | // Querying Lastest Work Items 38 | const queryResult = await adoClient.queryById(process.env.query_id); 39 | 40 | // Iterate over work items, including relations 41 | // https://github.com/microsoft/azure-devops-node-api/blob/master/api/interfaces/WorkItemTrackingInterfaces.ts#L1485 42 | const workItemsDetails = await adoClient.getWorkItems(queryResult.workItems.map(wi => wi.id), null, null, 1); 43 | 44 | // Obtain GitHub Issue Number 45 | function getGitHubIssueNumber(workItem) { 46 | 47 | // Try using relations 48 | const relation = workItem.relations.find(r => r.rel === 'Hyperlink' && r.url.includes('github.com')); 49 | if (relation) { 50 | const match = relation.url.match(/github.com\/[^/]+\/[^/]+\/issues\/(\d+)/); 51 | if (match) { 52 | return match[1]; 53 | } 54 | } 55 | 56 | // Try using the title, which includes [GitHub #123] 57 | const match = workItem.fields['System.Title'].match(/\[GitHub #(\d+)\]/); 58 | if (match) { 59 | return match[1]; 60 | } 61 | 62 | return null; 63 | } 64 | 65 | // Map ADO work items to GitHub number, remove nulls 66 | const ghIssueNumbers = workItemsDetails.map(wi => getGitHubIssueNumber(wi)).filter(n => n !== null); 67 | 68 | // Add priority-low label to GitHub issues 69 | const addLowPriorityLabel = async (issueNumber) => { 70 | // Check if the issue already has the label 71 | const { data: labels } = await github.rest.issues.listLabelsOnIssue({ 72 | issue_number: issueNumber, 73 | owner: context.repo.owner, 74 | repo: context.repo.repo 75 | }); 76 | 77 | if (labels.some(l => l.name === 'priority-low')) { 78 | console.log(`Issue #${issueNumber} already has the label`); 79 | return; 80 | } 81 | 82 | // Add the label 83 | await github.rest.issues.addLabels({ 84 | issue_number: issueNumber, 85 | owner: context.repo.owner, 86 | repo: context.repo.repo, 87 | labels: ['priority-low'] 88 | }); 89 | console.log(`Added label to issue #${issueNumber}`); 90 | } 91 | 92 | ghIssueNumbers.forEach(async (issueNumber) => { 93 | await addLowPriorityLabel(issueNumber); 94 | }); 95 | 96 | core.setOutput('Tagged Issues', ghIssueNumbers.join(',')); 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /.github/workflows/testAction.yml: -------------------------------------------------------------------------------- 1 | name: Run test action 2 | 3 | on: 4 | workflow_dispatch 5 | # issues: 6 | # types: [labeled, closed, reopened] 7 | 8 | permissions: 9 | id-token: write 10 | contents: read 11 | 12 | jobs: 13 | alert: 14 | runs-on: windows-latest 15 | name: Syncing to Azure DevOps 16 | steps: 17 | - name: Azure login 18 | uses: azure/login@v2 19 | with: 20 | client-id: ${{ secrets.AZURE_CLIENT_ID }} 21 | tenant-id: ${{ secrets.AZURE_TENANT_ID }} 22 | subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} 23 | - name: Sync to ADO 24 | uses: champnic/github-actions-issue-to-work-item@simple-sync-azurecli 25 | env: 26 | github_token: "${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}" 27 | with: 28 | label: 'test' 29 | ado_organization: 'microsoft' 30 | ado_project: 'Edge' 31 | ado_area_path: 'Edge\Web Experience\WebView2' 32 | ado_tags: 'WV2_GitHub' 33 | ado_gh_closed_tag: 'WV2_GitHub_Closed' 34 | -------------------------------------------------------------------------------- /.github/workflows/weeklySummary.yml: -------------------------------------------------------------------------------- 1 | name: get issue summary of last week 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 1 * * 1' 7 | 8 | jobs: 9 | alert: 10 | runs-on: ubuntu-latest 11 | name: get summary 12 | steps: 13 | - uses: shangminx/Auto-Digest@main 14 | id: getsummary 15 | with: 16 | daily_or_weekly: 'weekly' 17 | - uses: shangminx/Auto-Digest/sendEmail@main 18 | id: sendEmail 19 | with: 20 | email_password: ${{ secrets.EMAIL_PASSWORD }} 21 | sender_email: ${{secrets.SENDER_EMAIL}} 22 | recipient_email: ${{secrets.RECIPIENT_EMAIL}} 23 | report_data: ${{ steps.getsummary.outputs.dailysummary }} 24 | - uses: plantree/github-actions-issue-notify-teams@main 25 | with: 26 | type: weekly-report 27 | message: ${{ steps.getsummary.outputs.dailysummary }} 28 | webhook: ${{ secrets.WEBHOOK }} 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microsoft Edge WebView2 2 | 3 | Welcome to Microsoft Edge WebView2 feedback repository. 4 | 5 | This is a place for all developers of the [Microsoft Edge WebView2](https://aka.ms/webview) to report bugs, make feature requests, and ask questions and have discussions about WebView2. 6 | 7 | - 🐞 [How to report a bug](#-how-to-report-a-bug) 8 | - 💡 [How to request a feature](#-how-to-request-a-feature) 9 | - ❓ [Ask a question about WebView2](https://github.com/MicrosoftEdge/WebView2Feedback/discussions/new?category=q-a) 10 | - 💬 [Discuss WebView2 with other developers](https://github.com/MicrosoftEdge/WebView2Feedback/discussions) 11 | - 📣 [Subscribe to WebView2Announcements for news, API proposals and SDK Release announcements](https://github.com/MicrosoftEdge/WebView2Announcements) 12 | - 📖 [Read the WebView2 documentation](https://aka.ms/webview) 13 | 14 |

15 | Graphic of a developer using WebView2 in their applications 16 |

17 | 18 | ### 🐞 How to report a bug 19 | 20 | 1. [Search for existing open bugs](https://github.com/MicrosoftEdge/WebView2Feedback/issues?q=is%3Aissue+is%3Aopen+label%3Abug) to avoid duplicates. 21 | 1. If you find that your bug is already reported, give it a 👍 reaction, and add a comment with additional details that may help us investigate. 22 | 1. If the issue is not already reported, [open a new issue](https://github.com/MicrosoftEdge/WebView2Feedback/issues/new/choose). 23 | 1. Tracked issues will be labeled with the `tracked` label. If you see this label, we are aware of the issue and tracking it on our internal backlog. 24 | 25 | ### 💡 How to request a feature 26 | 27 | 1. [Search for existing feature request](https://github.com/MicrosoftEdge/WebView2Feedback/issues?q=is%3Aissue+is%3Aopen+label%3A%22feature+request%22) to avoid duplicates. 28 | 1. If you find a similar feature request, give it a 👍 reaction, and provide additional context into how you would use the feature. 29 | 2. If the feature is not already requested, [open a new issue](https://github.com/MicrosoftEdge/WebView2Feedback/issues/new/choose). 30 | 1. Tracked issues will be labeled with the `tracked` label. If you see this label, we are aware of the issue and tracking it on our internal backlog. 31 | 32 | 33 | ### What do the labels on the issues mean? 34 | 35 | - `tracked` We have acknowledged the issue and are tracking it on our internal backlog. We will consider and investigate them in the near future. 36 | - For bugs, it means we think this is an actual product issue. 37 | - For feature requests, it means we consider it to be a valid request. 38 | - `regression` A behavior that used to work in a previous version of WebView2, but no longer works as expected. We will prioritize this issue higher. 39 | - `priority-low` We have considered this issue and decided that we will not be able to address it in the near future. Developers are welcomed to provide justifications on this issue for us to revisit the prioritization. 40 | 41 | ## Code of Conduct 42 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 43 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * Any special configuration required to reproduce the issue 24 | * Step-by-step instructions to reproduce the issue 25 | * Proof-of-concept or exploit code (if possible) 26 | * Impact of the issue, including how an attacker might exploit the issue 27 | 28 | This information will help us triage your report more quickly. 29 | 30 | Reports via MSRC may qualify for the Edge Bug Bounty. Details of the program, including terms and conditions, can be found at [Microsoft Edge Bounty Program](https://www.microsoft.com/en-us/msrc/bounty-new-edge). 31 | 32 | ## Preferred Languages 33 | 34 | We prefer all communications to be in English. 35 | 36 | ## Policy 37 | 38 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd). 39 | 40 | 41 | -------------------------------------------------------------------------------- /diagnostics/README.md: -------------------------------------------------------------------------------- 1 | # Gathering Diagnostics and Logs 2 | This folder contains directions for gathering various detailed diagnostics/logs when reporting WV2-related issues. There's generally no need to proactively get any of these diagnostics before opening an issue, but if one seems obvious feel free to get it before opening an issue. Otherwise, a WV2 developer might link you to one of these pages to help them investigate an issue: 3 | 4 | - [Crash Dumps](crash.md): Crash dumps are used to better understand why a WV2 process is crashing and firing a [ProcessFailed](https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.processfailed) event. 5 | - [Crash Dumps from Task Manager](task_manager_dump.md): There are cases where crash dumps aren't automatically generated and need to be collected manually. 6 | - [ETW Trace](etw.md): Event Tracing for Windows (ETW) traces include detailed events on system state and the activities WV2 was doing before and when an issue occurs. 7 | - [Installer Logs](install.md): Installer logs include information about any errors that WV2's installer/updater hit when trying to install or update the WV2 runtime. 8 | - [GPU Info](gpu.md): GPU logs include details on the user's GPU and any potential graphics or rendering issues. 9 | - [Network Logs](network.md): Network logs include the network requests, responses, and details on any errors when loading files. 10 | - [Code Integrity](code_integrity.md): how to root cause STATUS_INVALID_IMAGE_HASH errors. 11 | - [Test in Canary](test_canary.md): how to test new WebView2 runtime changes by using Edge Canary. -------------------------------------------------------------------------------- /diagnostics/WebView2.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 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 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /diagnostics/WebView2_CPU.wprp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 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 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /diagnostics/code_integrity.md: -------------------------------------------------------------------------------- 1 | # Code Integrity in WebView2 2 | 3 | ## Why it is important 4 | Code integrity is a feature of Windows that verifies the authenticity and integrity of the code that runs on your system. It helps protect your system from malware, tampering, and unauthorized changes. Code integrity checks the digital signatures of the files that are loaded into memory, and prevents any file that does not have a valid signature from running in webview2. 5 | 6 | ## Symptoms 7 | Child process failed with kind COREWEBVIEW2_PROCESS_FAILED_KIND_RENDER_PROCESS_EXITED 8 | and exit code -1073740760 or STATUS_INVALID_IMAGE_HASH. 9 | 10 | Users may see error page in the WebView2: 11 | 12 | ![Compatibility problem](compatibility_problem.png) 13 | 14 | ## Update antimalware software 15 | Starting versions 118 and 119 the options to disable Code Integrity in WebView2 are deprecated and the guard is always on. 16 | We are seeing cases where old antimalware software violating our policies. Please make sure that antimalware on your devices is up to date when using WebView2. 17 | 18 | ## Identify the dll 19 | 20 | **Programmatically** app can subscribe to [ProcessFailed event](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/process-related-events?tabs=dotnetcsharp#events-for-processes-that-exited-or-failed). [Starting from 120.0.2164.0](https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes?tabs=dotnetcsharp#experimental-apis) 21 | `FailureSourceModulePath` property in the `ProcessFailedEventArgs` contains full path of the module that caused the crash in cases of Windows code integrity failures. 22 | 23 | **Compatibility problem** web page may also show the culprit file otherwise use Event Viewer. 24 | 25 | Open Event Viewer by typing eventvwr in the search box on the taskbar and selecting the app. 26 | 27 | - In the left pane, expand Windows Logs and click on System. 28 | - In the right pane, click on Filter Current Log. 29 | - In the Filter tab, under Event sources, select Microsoft-Windows-CodeIntegrity and click on OK. 30 | - You will see a list of events related to code integrity – search for the ones with msedgewebview2.exe process. 31 | - The file name and path of the file that caused the code integrity violation are shown in the message. 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /diagnostics/compatibility_problem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftEdge/WebView2Feedback/08c19658c259637dda8ae4dca7a6705fae89a172/diagnostics/compatibility_problem.png -------------------------------------------------------------------------------- /diagnostics/crash.md: -------------------------------------------------------------------------------- 1 | # Crash Dumps 2 | Crash dumps are used to better understand why a WV2 process is crashing and firing a [ProcessFailed](https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.processfailed) event. If you're experiencing crashes, the information included in the [ProcessFailed event arguments](https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2processfailedeventargs) is a good starting point: 3 | - ExitCode 4 | - ProcessDescription 5 | - ProcessFailedKind 6 | - Reason 7 | 8 | In addition to that, crash dumps are extremely helpful. WV2 crash dumps are located in a subfolder of the app's user data folder (UDF): `\EBWebView\Crashpad\reports\`. 9 | By default the user data folder is created in the app's folder by default with a name like 10 | `.exe.WebView2`. If an app sets its user data folder location manually when creating a [WV2 Environment object](https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2environment), it may be in a different location. 11 | 12 | If you do not have crash dumps - please navigate your webview2 control to `edge://crashes` to see if there are new reports. Copy necessary data to Clipboard and share with us. 13 | 14 | ![crashes](crashes.png) -------------------------------------------------------------------------------- /diagnostics/crashes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftEdge/WebView2Feedback/08c19658c259637dda8ae4dca7a6705fae89a172/diagnostics/crashes.png -------------------------------------------------------------------------------- /diagnostics/etw.md: -------------------------------------------------------------------------------- 1 | # Gathering an ETW Trace 2 | [Event Tracing for Windows (ETW)](https://learn.microsoft.com/en-us/windows-hardware/test/wpt/event-tracing-for-windows)traces include detailed events on system state and the activities WV2 was doing before and when an issue occurs. 3 | 4 | This repo has a WV2 recording profile - [WebView2_CPU.wprp](WebView2_CPU.wprp) that includes the events that we find most useful. 5 | 6 | ETW traces can get fairly large, so try to keep the amount of extra time spent when recording as small as possible. If you need a longer trace, ask the WV2 developer that you're working with if `WebView2.wprp` will suffice (it gathers less data). 7 | 8 | 1. Close Edge and any other apps using WV2 to make the trace more clear. Common apps using WV2 may include `widgets.exe`, `msteams.exe`, and Microsoft Office products. 9 | 2. Download [WebView2_CPU.wprp](WebView2_CPU.wprp) from this repo. 10 | 3. If your app has a specific profile, merge it with [WebView2_CPU.wprp](WebView2_CPU.wprp) to ensure all events are captured in a single ETL file. 11 | 4. In an elevated command prompt run `wpr -start WebView2_CPU.wprp -filemode` (wpr.exe is included in Windows). 12 | 5. Reproduce the issue. 13 | 6. In an elevated command prompt run `wpr -stop trace.etl "trace"`. 14 | 15 | ETW traces can contain sensitive information, if you're concerned with sharing one publicly in a GitHub issue, you can ask the WV2 developer you're working with for an email address to send to them privately. 16 | -------------------------------------------------------------------------------- /diagnostics/gpu.md: -------------------------------------------------------------------------------- 1 | # Graphics and GPU info 2 | GPU logs include details on the user's GPU and any potential graphics or rendering issues. If your WV2 has been created successfully but the content is not there, it might be due to a hosting and/or GPU driver issue. 3 | 4 | There's a few pieces of information that can help us investigate these issues: 5 | ## DirectX Details 6 | On the device that is hitting the issue: 7 | 1. Run `dxdiag` from a console window 8 | 1. Once the dialog displays and is done capturing info (there is a small progress bar) hit the "Save All Information" button to save the info to a `dxdiag.txt` file 9 | 1. Share the `dxdiag.txt` file 10 | 11 | ## GPU Logs 12 | 1. Navigate your WV2 to `edge://gpu`. This needs to be done programmatically inside the application, and can't be done via DevTools console or similar means. 13 | 1. Wait for the page to load content under the "Log Messages" header towards the bottom. 14 | 1. Hit "Copy Report to Clipboard" at the top 15 | 1. Paste it into a text file, and share it. -------------------------------------------------------------------------------- /diagnostics/install.md: -------------------------------------------------------------------------------- 1 | # Installer / Setup Logs 2 | Installer logs include information about any errors that WV2's installer/updater hit when trying to install or update the WV2 runtime. There are a few different logs that we need to best look in to any issues. 3 | 4 | ## Installer History & File List 5 | There are some registry keys that contain important update information like when the last update occurred, recent error codes, and updater version information. The list of installed files that actually exist the device is also helpful in case there are errors or other processes removing them. 6 | 7 | 1. Open a command prompt. 8 | 2. Run `reg export HKCU\SOFTWARE\Microsoft\EdgeUpdate\ClientState EdgeRegistryUser.txt` 9 | 3. Run `reg export HKLM\SOFTWARE\Microsoft\EdgeUpdate\ClientState EdgeRegistryMachine.txt /reg:32` 10 | 4. Run `dir "c:\Program Files (x86)\Microsoft\EdgeWebView" /s > EdgeFiles.txt` 11 | 5. Run `dir "c:\Program Files (x86)\Microsoft\EdgeCore" /s >> EdgeFiles.txt` 12 | 13 | You should now have three files: `EdgeRegistryUser.txt`, `EdgeRegistryMachine.txt`, and `EdgeFiles.txt`. 14 | 15 | ## Installer Logs 16 | There are four places where WV2's updater will write important details about any install or update issues. If you don't have all of these that's not a problem, include what exists: 17 | 18 | 1. `C:\ProgramData\Microsoft\EdgeUpdate\Log\MicrosoftEdgeUpdate.log` 19 | 2. `%localappdata%\Temp\MicrosoftEdgeUpdate.log` 20 | 3. `%temp%\msedge_installer.log` 21 | 4. `%systemroot%\Temp\msedge_installer.log` 22 | 5. `%systemroot%\SystemTemp\msedge_installer.log` 23 | 24 | Once you have these files, share them with the WV2 developer who is helping you. 25 | -------------------------------------------------------------------------------- /diagnostics/network.md: -------------------------------------------------------------------------------- 1 | # Network Logs 2 | Network logs include the network requests, responses, and details on any errors when loading files. The easiest way to gather network logs for WV2 is to pass the `--log-net-log` command-line parameter to your WV2 app by setting the `WEBVIEW_ADDITIONAL_BROWSER_ARGUMENTS` environment variable to `--log-net-log=C:\MyPath\Log.json` (replacing the path with a location that your app can write to). 3 | 4 | If that doesn't work in your scenario, there's more options for gathering network logs [in this post](https://textslashplain.com/2020/01/17/capture-network-logs-from-edge-and-chrome/). Additionally, [Chromium documentation](https://dev.chromium.org/for-testers/providing-network-details) has more details on some of the options. -------------------------------------------------------------------------------- /diagnostics/task_manager_dump.md: -------------------------------------------------------------------------------- 1 | # Crash Dump from Task Manager 2 | Normally, crash dumps are gathered automatically and available in the app's user data folder (see [Crash Dumps](crash.md)). In some cases, a user might need to manually gather a crash dump, normally for unresponsive processes. To do so: 3 | 4 | 1. Open Task Manager (Ctrl+Shift+Esc). 5 | 2. Click "Details" on the left menu. 6 | 3. Sort by the "Name" column. 7 | 4. Scroll to find "msedgewebview2.exe" 8 | 5. To find the right msedgewebview2.exe, you can use a combination of: 9 | 1. The "Package name" column, which will represent the application using WebView2. (you might need to right-click the column headers, choose "select columns" and check the box for "Package name") 10 | 2. The "Description" column, which will describe which of WebView2's processes it is. (you might need to make Task Manager very wide to see this one, you can drag to re-arrange the columns if needed) 11 | 12 | For example, if you're asked to get a crash dump of "Outlook's Manager process", you'll want the process that has "Outlook" as its Package name, and "WebView2 Manager" for its Description. 13 | 6. Right-click the process on the list and choose "Create memory dump file" 14 | 7. Once that completes, click "Open file location" 15 | 8. Copy the msedgewebview2.DMP file to a location where you can share it. -------------------------------------------------------------------------------- /diagnostics/test_canary.md: -------------------------------------------------------------------------------- 1 | # Test Feature in Canary 2 | 3 | The latest runtime changes are first shipped in the WebView2 runtime in the Edge Canary Browser. If you would like to test the new changes or help us to verify that your issue is fixed with your application, here's a suggested way to do so: 4 | 5 | 1. Download [Edge Canary](https://www.microsoft.com/en-us/edge/download/insider) 6 | 2. Run the following command in a PowerShell with Administrative Priviledges: 7 | `REG ADD HKCU\Software\Policies\Microsoft\Edge\WebView2\ChannelSearchKind /v /t REG_DWORD /d 1` 8 | 3. Restart your application, and you should be able to see that your application picks up the latest runtime. 9 | 10 | To remove the registry key added, run the following: 11 | `REG DELETE HKCU\Software\Policies\Microsoft\Edge\WebView2\ChannelSearchKind /v ` 12 | 13 | For more information, read the documentation on [Test upcoming APIs and features](https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/set-preview-channel) 14 | -------------------------------------------------------------------------------- /diagnostics/version.md: -------------------------------------------------------------------------------- 1 | # Figuring out SDK and runtime version 2 | 3 | SDK and runtime verion number of WebView2 is helpful for someone who is trying to reproduce a bug. The follow options are ways for you to obtain the version numbers of the host app. 4 | 5 | ### Option 1: Use WebView2 Utilities (SDK and runtime) 6 | An easy way to obtain the SDK and runtime version for any host app that is currently running, is to use [WebView2Utilities](https://github.com/david-risney/WebView2Utilities). 7 | 8 | ### Option 2a: Check NuGet Package Manager (SDK only) 9 | If you are a developer for the WebView2 application, on Visual Studio Code, go to `Tools > NuGet Package Manager > Manage NuGet Packages for Solution`, and see the SDK version that is being used for the project 10 | 11 | ### Option 2b: Check WebView2 child process of host app (Runtime only) 12 | For any application, to check the which WebView2 runtime is being used, do the following: 13 | 14 | 1. Open Task Manager 15 | 2. Right click on the WebView2 process of the application you are interested in 16 | 3. Click on Open File Location 17 | 18 | The directory of the file location is the WebView2 runtime version 19 | -------------------------------------------------------------------------------- /specs/APIReview_AllowExternalDrop.md: -------------------------------------------------------------------------------- 1 | # Background 2 | Currently dragging and dropping external objects (e.g. files, hyperlinks) into webview2 is by default enabled and there is no way to disable it. Some developers may want to disable this functionality in their applications. To allow for this, we add a new API to provide developers with the capability to disable the external drag & drop functionality. 3 | 4 | # Description 5 | We add a new `AllowExternalDrop` property in `CoreWebView2Controller`. 6 | This API allows end developers to toggle the external drag & drop functionality easily. 7 | If it's disabled, dragging objects from outside the bounds of the WebView and dropping into the WebView will be disallowed. 8 | To be more specific, some behaviors listed below will be impacted by the toggle of this property. 9 | 10 | * Drag&Drop files on disk to webview2 11 | * Drag&Drop hyperlinks from browser to webview2 12 | * Drag&Drop hyperlinks from one webview2 to another webview2 13 | 14 | Some behaviors are not impacted by the toggle of this property like dragging and dropping selected text to webview2. That means toggle of this property has no impact on the expected behavior of this action. 15 | 16 | By default, AllowExternalDrop is enabled to keep consistent with the behavior we had before the API is added. 17 | 18 | Please note that drag and drop anything from webview2 to external(outside the bounds of the WebView) will not be impacted by this property. 19 | 20 | # Examples 21 | ## C++ 22 | 23 | ```cpp 24 | // This hypothetical app allows dropping external content 25 | // only on the AttachReceipts page. 26 | wil::com_ptr m_controller; 27 | BOOL m_allowExternalDropOnNavigationCompleted; 28 | HRESULT OnNavigationStarting(ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) 29 | { 30 | // Disable external drop while navigating. 31 | auto controller4 = m_controller.try_query(); 32 | if (controller4) 33 | { 34 | CHECK_FAILURE(controller4->put_AllowExternalDrop(FALSE)); 35 | } 36 | 37 | // Decide whether to enable external drop when we finish navigating. 38 | // Enable it only when AttachReceipts page is navigated. 39 | wil::unique_cotaskmem_string uri; 40 | CHECK_FAILURE(args->get_Uri(&uri)); 41 | m_allowExternalDropOnNavigationCompleted = uri_equal(uri.get(), L"myapp://AttachReceipts.html"); 42 | } 43 | 44 | HRESULT OnNavigationCompleted(ICoreWebView2* sender, ICoreWebView2NavigationCompletedEventArgs* args) 45 | { 46 | auto controller4 = m_controller.try_query(); 47 | if (controller4) 48 | { 49 | CHECK_FAILURE(controller4->put_AllowExternalDrop(m_allowExternalDropOnNavigationCompleted)); 50 | } 51 | } 52 | ``` 53 | 54 | ## C# 55 | ```c# 56 | // This hypothetical app allows dropping external content 57 | // only on the AttachReceipts page. 58 | private CoreWebView2Controller controller; 59 | private bool allowExternalDropOnNavigationCompleted; 60 | void OnNavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs args) 61 | { 62 | // Disable external drop while navigating. 63 | if (controller != null) 64 | { 65 | controller.AllowExternalDrop = false; 66 | } 67 | 68 | // Decide whether to enable external drop when we finish navigating. 69 | // Enable it only when AttachReceipts page is navigated. 70 | string uri = args.Uri; 71 | allowExternalDropOnNavigationCompleted = uri.Equals("myapp://AttachReceipts.html"); 72 | } 73 | 74 | void OnNavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs args) 75 | { 76 | if (controller != null) 77 | { 78 | controller.AllowExternalDrop = allowExternalDropOnNavigationCompleted; 79 | } 80 | } 81 | ``` 82 | 83 | # Remarks 84 | 85 | # API Notes 86 | See [API Details](#api-details) section below for API reference. 87 | 88 | # API Details 89 | 90 | ## Win32 C++ 91 | ```c# 92 | // This is the ICoreWebView2Controller4 interface. 93 | [uuid(320613e2-990f-4272-bf90-d243a4ff1b8a), object, pointer_default(unique)] 94 | interface ICoreWebView2Controller4 : ICoreWebView2Controller3 { 95 | /// Gets the `AllowExternalDrop` property which is used to configure the 96 | /// capability that dragging objects from outside the bounds of webview2 and 97 | /// dropping into webview2 is allowed or disallowed. The default value is 98 | /// TRUE. 99 | [propget] HRESULT AllowExternalDrop([ out, retval ] BOOL * value); 100 | /// Sets the `AllowExternalDrop` property which is used to configure the 101 | /// capability that dragging objects from outside the bounds of webview2 and 102 | /// dropping into webview2 is allowed or disallowed. 103 | [propput] HRESULT AllowExternalDrop([in] BOOL value); 104 | } 105 | ``` 106 | 107 | ## .NET and WinRT 108 | ```c# 109 | namespace Microsoft.Web.WebView2.Core 110 | { 111 | public class CoreWebView2Controller 112 | { 113 | // 114 | // Summary: 115 | // Gets or sets the WebView AllowExternalDrop property. 116 | // 117 | // Remarks: 118 | // The AllowExternalDrop is to configure the capability that dragging objects from 119 | // outside the bounds of webview2 and dropping into webview2 is allowed or disallowed. 120 | // The default value is true. 121 | public bool AllowExternalDrop { get; set; } 122 | } 123 | } 124 | ``` 125 | -------------------------------------------------------------------------------- /specs/AllowHostInputProcessing.md: -------------------------------------------------------------------------------- 1 | # Background 2 | WebView2 .NET developers often encounter issues where certain default events are not raised in the WebView2 .NET control. 3 | 4 | This issue occurs because user inputs are directly delivered to the browser, and the host application does not receive the corresponding messages. 5 | 6 | This causes some default event handling API of .NET control not to work, such as PreProcessMessage and ProcessCmdKey in WinForms. 7 | 8 | It also prevents some keys from reaching Key Event realated APIs such as OnKeyDown and ToolStripMenuItem. 9 | 10 | In order to solve this type of issue, we provide an api which allows user inputs pass through the browser to the host app. 11 | 12 | # Description 13 | `AllowHostInputProcessing` allows user input messages(keyboard, mouse, touch, and pen) to pass through the browser window to be received by an app process window. 14 | 15 | The messages can be received by Win32 API ::GetMessage() or ::PeekMessage(). This provides the host app a chance to handle the message before dispatching to the WebView2 HWND. 16 | 17 | If the host app does not handle input, it is forwarded to the browser process on the user's behalf. This API does not introduce any requirement for the developer to forward all input as is the case with visual hosting. This API should not be used with visual hosting, and has no effect when using CreateCoreWebView2CompositionControllerWithOptions to create the controller. 18 | 19 | Setting `AllowHostInputProcessing` to `TRUE` makes `AcceleratorKeyPressed`(all platforms) and `OnKeyDown`(WinForms only) event asynchronous. 20 | 21 | # Examples 22 | ## Win32 C++ 23 | ```cpp 24 | // We assume WebView2 is hosted in a MFC application. CMFCApplicationApp is a CWinApp. 25 | // This function can not be triggered by default when focus is in WebView. 26 | // It can be triggered by setting 'AllowHostInputProcessing' to true. 27 | BOOL CMFCApplicationApp::PreTranslateMessage(MSG* pMsg) { 28 | if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP || 29 | pMsg->message == WM_SYSKEYDOWN || pMsg->message == WM_SYSKEYUP && webview_has_focus_) 30 | // Prehandle the message. The message will not be sent to WebView if return TRUE. 31 | return HandleMsgBeforeWebView(pMsg); 32 | return FALSE; 33 | } 34 | 35 | // Create a ControllerOptions and set 'AllowHostInputProcessing' to TRUE. 36 | HRESULT CreateControllerWithInputPassthrough() 37 | { 38 | auto webViewEnvironment10 = m_webViewEnvironment.try_query(); 39 | if (!webViewEnvironment10) 40 | { 41 | FeatureNotAvailable(); 42 | return S_OK; 43 | } 44 | 45 | wil::com_ptr options; 46 | CHECK_FAILURE(webViewEnvironment4->CreateCoreWebView2ControllerOptions(options.GetAddressOf())); 47 | 48 | wil::com_ptr webView2ControllerOptions3; 49 | if (SUCCEEDED(options->QueryInterface(IID_PPV_ARGS(&webView2ControllerOptions3)))) 50 | { 51 | CHECK_FAILURE(webView2ControllerOptions3->put_AllowHostInputProcessing(TRUE)); 52 | } 53 | 54 | CHECK_FAILURE(webViewEnvironment10->CreateCoreWebView2ControllerWithOptions( 55 | m_mainWindow, options.get(), 56 | Callback( 57 | this, &AppWindow::OnCreateCoreWebView2ControllerCompleted) 58 | .Get())); 59 | 60 | return S_OK; 61 | } 62 | ``` 63 | 64 | ### .NET, WinRT 65 | ```c# 66 | 67 | partial class BrowserForm 68 | { 69 | // This function can not be triggered by default when focus is in WebView. 70 | // It can be triggered by setting 'AllowHostInputProcessing' to true. 71 | protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 72 | { 73 | //DoSomething(); 74 | return base.ProcessCmdKey(ref msg, keyData); 75 | } 76 | 77 | // ... 78 | private Microsoft.Web.WebView2.WinForms.WebView2 webView2Control; 79 | } 80 | 81 | CoreWebView2Environment _webViewEnvironment; 82 | public CreateWebView2Controller(IntPtr parentWindow) 83 | { 84 | CoreWebView2ControllerOptions controllerOptions = _webViewEnvironment.CreateCoreWebView2ControllerOptions(); 85 | controllerOptions.AllowHostInputProcessing = true; 86 | 87 | CoreWebView2Controller controller = null; 88 | 89 | controller = await _webViewEnvironment.CreateCoreWebView2ControllerAsync(parentWindow, controllerOptions); 90 | 91 | //... 92 | } 93 | ``` 94 | 95 | # API Details 96 | ## Win32 C++ 97 | ```IDL 98 | interface ICoreWebView2ControllerOptions3; 99 | 100 | interface ICoreWebView2ControllerOptions3 : IUnknown { 101 | /// `AllowHostInputProcessing` property is to enable/disable input passing through 102 | /// the app before being delivered to the WebView2. This property is only applicable 103 | /// to controllers created with `CoreWebView2Environment.CreateCoreWebView2ControllerAsync` and not 104 | /// composition controllers created with `CoreWebView2Environment.CreateCoreWebView2CompositionControllerAsync`. 105 | /// By default the value is `FALSE`. 106 | [propget] HRESULT AllowHostInputProcessing([out, retval] BOOL* value); 107 | /// Sets the `AllowHostInputProcessing` property. 108 | /// Setting this property has no effect when using visual hosting. 109 | [propput] HRESULT AllowHostInputProcessing([in] BOOL value); 110 | } 111 | ``` 112 | 113 | ## .NET, WinRT 114 | ```c# 115 | namespace Microsoft.Web.WebView2.Core 116 | { 117 | runtimeclass CoreWebView2ControllerOptions; 118 | runtimeclass CoreWebView2Environment; 119 | runtimeclass CoreWebView2; 120 | runtimeclass CoreWebView2Profile; 121 | 122 | runtimeclass CoreWebView2ControllerOptions 123 | { 124 | // ... 125 | 126 | Boolean AllowHostInputProcessing { get; set; }; 127 | } 128 | } 129 | ``` 130 | -------------------------------------------------------------------------------- /specs/AreBrowserAcceleratorKeysEnabled.md: -------------------------------------------------------------------------------- 1 | # AreBrowserAcceleratorKeysEnabled 2 | 3 | ## Background 4 | In general, CoreWebView2 tries to behave as much like the browser as possible. 5 | This includes allowing accelerator key access to features such as printing and 6 | navigation. However, in many apps these features are unnecessary or even 7 | intrusive. These accelerator keys can be disabled by handling the 8 | `AcceleratorKeyPressed` event on `ICoreWebView2Controller`, but then the burden 9 | is on the developer to correctly block the keys that trigger browser commands, 10 | such as Ctrl-P, and not basic editing and movement keys such as Ctrl-C and the 11 | arrow keys. After that, if the underlying browser ever changes its set of 12 | accelerator keys, apps may not be able to respond to those changes. 13 | 14 | This illustrates the need for a single setting to disable all keyboard shortcuts 15 | that correspond to browser-specific functionality, without disabling things like 16 | copy and paste and movement. 17 | 18 | In this document we describe the new setting. We'd appreciate your feedback. 19 | 20 | 21 | ## Description 22 | When this setting is set to false, it disables all accelerator keys that access 23 | features specific to the browser, including but not limited to: 24 | - Ctrl-F and F3 for Find on Page 25 | - Ctrl-P for Print 26 | - Ctrl-R and F5 for Reload 27 | - Ctrl-Plus and Ctrl-Minus for zooming 28 | - Ctrl-Shift-C and F12 for DevTools 29 | - Special keys for browser functions, such as Back, Forward, and Search 30 | 31 | It does not disable accelerator keys related to movement and text editing, such 32 | as: 33 | - Home, End, Page Up, and Page Down 34 | - Ctrl-X, Ctrl-C, Ctrl-V 35 | - Ctrl-A for Select All 36 | - Ctrl-Z for Undo 37 | 38 | This setting has no effect on the `AcceleratorKeyPressed` event. The event will 39 | be fired for all accelerator keys, whether they are enabled or not. 40 | 41 | Those accelerator keys will always be enabled unless they are handled in the 42 | `AcceleratorKeyPressed` event. 43 | 44 | The default value for AreBrowserAcceleratorKeysEnabled is true. 45 | 46 | ## Examples 47 | ```c# 48 | privagte WebView2 _webView; 49 | void ToggleBrowserKeysEnabled() 50 | { 51 | var settings = _webView.CoreWebView2.Settings; 52 | settings.AreBrowserAcceleratorKeysEnabled = !settings.AreBrowserAcceleratorKeysEnabled; 53 | } 54 | ``` 55 | 56 | ```cpp 57 | void SettingsComponent::ToggleBrowserKeysEnabled() 58 | { 59 | BOOL enabled; 60 | CHECK_FAILURE(_coreWebView2Settings->get_AreBrowserAcceleratorKeysEnabled(&enabled)); 61 | CHECK_FAILURE(_coreWebView2Settings->put_AreBrowserAcceleratorKeysEnabled(enabled ? FALSE : TRUE)); 62 | } 63 | ``` 64 | 65 | 66 | ## Remarks 67 | Some accelerator keys that don't make sense for WebViews are always disabled 68 | regardless of this setting. This includes things like opening and closing tabs, 69 | viewing bookmarks and history, and selecting the location bar. 70 | 71 | This setting will not prevent commands from being run through the context menu. 72 | To disable the context menu, use `AreDefaultContextMenusEnabled`. 73 | 74 | 75 | ## API Details 76 | ``` 77 | [uuid(9aab8652-d89f-408d-8b2c-1ade3ab51d6d), object, pointer_default(unique)] 78 | interface ICoreWebView2Settings2 : ICoreWebView2Settings { 79 | /// When this setting is set to FALSE, it disables all accelerator keys 80 | /// that access features specific to the browser, including but not limited to: 81 | /// - Ctrl-F and F3 for Find on Page 82 | /// - Ctrl-P for Print 83 | /// - Ctrl-R and F5 for Reload 84 | /// - Ctrl-Plus and Ctrl-Minus for zooming 85 | /// - Ctrl-Shift-C and F12 for DevTools 86 | /// - Special keys for browser functions, such as Back, Forward, and Search 87 | /// 88 | /// It does not disable accelerator keys related to movement and text editing, 89 | /// such as: 90 | /// - Home, End, Page Up, and Page Down 91 | /// - Ctrl-X, Ctrl-C, Ctrl-V 92 | /// - Ctrl-A for Select All 93 | /// - Ctrl-Z for Undo 94 | /// 95 | /// 96 | /// This setting has no effect on the `AcceleratorKeyPressed` event. The event 97 | /// will be fired for all accelerator keys, whether they are enabled or not. 98 | /// 99 | /// Those accelerator keys will always be enabled unless they are handled in the 100 | /// `AcceleratorKeyPressed` event. 101 | /// 102 | /// The default value for AreBrowserAcceleratorKeysEnabled is TRUE. 103 | [propget] HRESULT AreBrowserAcceleratorKeysEnabled( 104 | [out, retval] BOOL* areBrowserAcceleratorKeysEnabled); 105 | 106 | /// Sets the `AreBrowserAcceleratorKeysEnabled` property. 107 | [propput] HRESULT AreBrowserAcceleratorKeysEnabled( 108 | [in] BOOL areBrowserAcceleratorKeysEnabled); 109 | } 110 | ``` 111 | 112 | ```c# (but actually midl3) 113 | runtimeclass CoreWebView2Settings { 114 | // ... 115 | 116 | Boolean AreBrowserAcceleratorKeysEnabled { get; set; }; 117 | } 118 | ``` 119 | -------------------------------------------------------------------------------- /specs/Autofill.md: -------------------------------------------------------------------------------- 1 | # Background 2 | The WebView2 team has been asked for an API to allow end developers to set the autofill preferences. We are exposing two of the autofill preferences that will allow enabling and disabling general autofill and password autosave. General autofill includes things like email addresses, shipping addresses, phone numbers, and names. Password autosave includes things like usernames and passwords for login. Password information is not included in general autofill. 3 | 4 | In this document we describe the updated API. We'd appreciate your feedback. 5 | 6 | 7 | # Description 8 | 9 | The components of autofill/autosave are as follows: 10 | * Auto-populate - Populate the corresponding form fields automatically on page load. 11 | * Suggest - When the user clicks on the form field, drop down suggestions of previously saved forms will be displayed. 12 | * Populate - When clicking on one of the suggestions, the form data will populate the respective fields. 13 | * Save/Update prompt - After submitting password information, if IsPasswordAutosaveEnabled is true, a prompt will popup that allows the user to give permission to save or update their password information. 14 | 15 | The general autofill setting and password autosave setting behave independently. Their behavior differs as well. 16 | 17 | The default behavior for the general autofill setting is enabled. 18 | The default behavior for the password autosave setting is disabled. 19 | 20 | | Behavior | IsPasswordAutosaveEnabled = false | IsGeneralAutofillEnabled = false | IsPasswordAutoSaveEnabled = true | IsGeneralAutofillEnabled = true | 21 | |-|-|-|-|-| 22 | | Populate on accepted suggestion | Yes | No | Yes | Yes | 23 | | Suggest | Yes | No | Yes | Yes | 24 | | Auto-populate | Yes | No | Yes | No | 25 | | Save/Update prompt | No | N/A | Yes | N/A | 26 | | Input saved | No | No | Yes | Yes | 27 | 28 | The information that is autofilled, auto-populated, or suggested when the IsPasswordAutosaveEnabled is false is previously saved information when the IsPasswordAutosaveEnabled property has been set to true. 29 | 30 | # Examples 31 | 32 | ## Win32 C++ 33 | ```cpp 34 | void SettingsComponent::TogglePasswordAutofill() { 35 | wil::com_ptr settings; 36 | CHECK_FAILURE(webView->get_Settings(&settings)); 37 | wil::com_ptr settings4 = settings.try_query(); 38 | if (settings4) 39 | { 40 | bool enabled; 41 | CHECK_FAILURE(settings4->get_IsPasswordAutofillEnabled(&enabled)); 42 | CHECK_FAILURE(settings4->put_IsPasswordAutofillEnabled(!enabled)); 43 | } 44 | } 45 | 46 | void SettingsComponent::ToggleGeneralAutofill() { 47 | wil::com_ptr settings; 48 | CHECK_FAILURE(webView->get_Settings(&settings)); 49 | wil::com_ptr settings4 = settings.try_query(); 50 | if (settings4) 51 | { 52 | bool enabled; 53 | CHECK_FAILURE(settings4->get_IsGeneralAutofillEnabled(&enabled)); 54 | CHECK_FAILURE(settings4->put_IsGeneralAutofillEnabled(!enabled)); 55 | } 56 | } 57 | ``` 58 | 59 | ## .NET, WinRT 60 | ```c# 61 | 62 | // This demonstrates a scenario in which a button triggers TogglePasswordAutofill or 63 | // ToggleGeneralAutofill. 64 | 65 | private void TogglePasswordAutofill(CoreWebView2 sender, CoreWebView2NavigationStartingEventArgs e) 66 | { 67 | var settings = webView2Control.CoreWebView2.Settings; 68 | settings.IsPasswordAutofillEnabled = !settings.IsPasswordAutofillEnabled; 69 | } 70 | 71 | private void ToggleGeneralAutofill(CoreWebView2 sender, CoreWebView2NavigationStartingEventArgs e) 72 | { 73 | var settings = webView2Control.CoreWebView2.Settings; 74 | settings.IsGeneralAutofillEnabled = !settings.IsGeneralAutofillEnabled; 75 | } 76 | 77 | ``` 78 | 79 | 80 | # API Notes 81 | See [API Details](#api-details) section below for API reference. 82 | 83 | 84 | # API Details 85 | ```IDL 86 | interface ICoreWebView2Settings4 87 | 88 | /// A continuation of the ICoreWebView2Settings interface. 89 | [uuid(cb56846c-4168-4d53-b04f-03b6d6796ff2), object, pointer_default(unique)] 90 | interface ICoreWebView2Settings4 : ICoreWebView2Settings3 { 91 | /// IsPasswordAutosaveEnabled controls whether autosave for password 92 | /// information is enabled. The IsPasswordAutosaveEnabled property behaves 93 | /// independently of the IsGeneralAutofillEnabled property. When IsPasswordAutosaveEnabled is 94 | /// false, no new password data is saved and no Save/Update Password prompts are displayed. 95 | /// However, if there was password data already saved before disabling this setting, 96 | /// then that password information is auto-populated, suggestions are shown and clicking on 97 | /// one will populate the fields. 98 | /// When IsPasswordAutosaveEnabled is true, password information is auto-populated, 99 | /// suggestions are shown and clicking on one will populate the fields, new data 100 | /// is saved, and a Save/Update Password prompt is displayed. 101 | /// The default value is `FALSE`. 102 | [propget] HRESULT IsPasswordAutosaveEnabled([out, retval] BOOL* value); 103 | /// Set the IsPasswordAutosaveEnabled property. 104 | [propput] HRESULT IsPasswordAutosaveEnabled([in] BOOL value); 105 | 106 | /// IsGeneralAutofillEnabled controls whether autofill for information 107 | /// like names, street and email addresses, phone numbers, and arbitrary input 108 | /// is enabled. This excludes password and credit card information. When 109 | /// IsGeneralAutofillEnabled is false, no suggestions appear, and no new information 110 | /// is saved. When IsGeneralAutofillEnabled is true, information is saved, suggestions 111 | /// appear and clicking on one will populate the form fields. 112 | /// The default value is `TRUE`. 113 | [propget] HRESULT IsGeneralAutofillEnabled([out, retval] BOOL* value); 114 | /// Set the IsGeneralAutofillEnabled property. 115 | [propput] HRESULT IsGeneralAutofillEnabled([in] BOOL value); 116 | } 117 | ``` 118 | 119 | ## .NET and WinRT 120 | ```c# 121 | namespace Microsoft.Web.WebView2.Core 122 | { 123 | public partial class CoreWebView2Settings 124 | { 125 | public bool IsPasswordAutofillEnabled { get; set; }; 126 | public bool IsGeneralAutofillEnabled {get; set; }; 127 | } 128 | } 129 | 130 | ``` -------------------------------------------------------------------------------- /specs/AutomationProvider.md: -------------------------------------------------------------------------------- 1 | # Background 2 | WebView has two hosting modes, windowed (which uses the ICoreWebView2Controller) and visual (which uses the ICoreWebView2CompositionController). Accessibility for the windowed WebView is able to walk the HWND tree to know where to place the WebView in the accessibility tree. For visual hosting, accessibility is not able to know where within the accessibility tree to place the WebView. This results in a WebView being a sibling to the rest of the app content. 3 | 4 | In this document we describe the updated API so visual-hosted WebViews are correctly managed by accessibility. We'd appreciate your feedback. 5 | 6 | 7 | # Description 8 | To give apps using the ICoreWebView2CompositionController more control over how the WebView is positioned in the accessibility tree, we are adding new APIs to let the app retrieve the automation provider for the WebView. This let's the app return the automation provider as part of its accessibility tree. 9 | 10 | While traversing child elements, when the app reaches the WebView, it can use the `UIAProvider` property to get the automation provider for the WebView and return it. 11 | 12 | When accessibility is traversing parent elements, the app needs to implement IRawElementProviderHwndOverride. The HWND parameter from GetOverrideProviderForHwnd can be passed to `GetProviderForHwnd` to get the automation provider for the corresponding WebView. 13 | 14 | # Examples 15 | ```cpp 16 | HRESULT WebView2AutomationPeer::GetRawElementProviderSimple(IRawElementProviderSimple** value) 17 | { 18 | wil::com_ptr provider; 19 | CHECK_FAILURE(m_controller->get_AutomationProvider(&provider)); 20 | return provider->QueryInterface(IID_PPV_ARGS(value)); 21 | } 22 | 23 | // Find the WebView2AutomationPeer for the HWND from 24 | // IRawElementProviderHwndOverride::GetOverrideProviderForHwnd 25 | bool WebView2AutomationPeer::IsAutomationPeerForWindow(HWND window) 26 | { 27 | wil::com_ptr provider; 28 | CHECK_FAILURE(m_controller->get_AutomationProvider(&provider)); 29 | 30 | wil::com_ptr providerForWindow; 31 | CHECK_FAILURE(m_environment->GetAutomationProviderForWindow(window, &providerForWindow)); 32 | 33 | return (provider == providerForWindow); 34 | } 35 | ``` 36 | 37 | # API Notes 38 | See [API Details](#api_details) section below for API reference. 39 | 40 | # API Details 41 | ## Win32 C++ 42 | ``` c# 43 | interface ICoreWebView2Environment4 : ICoreWebView2Environment3 { 44 | /// Returns the Automation Provider for the WebView that matches the provided window. 45 | /// Host apps are expected to implement IRawElementProviderHwndOverride. When GetOverrideProviderForHwnd 46 | /// is called, the app can pass the HWND to GetAutomationProviderForWindow to find the matching WebView 47 | /// automation provider. 48 | HRESULT GetAutomationProviderForWindow([in] HWND window, 49 | [out, retval] IUnknown** provider); 50 | } 51 | 52 | interface ICoreWebView2CompositionController2 : ICoreWebView2CompositionController { 53 | /// Returns the Automation Provider for the WebView. This object implements IRawElementProviderSimple. 54 | [propget] HRESULT AutomationProvider([out, retval] IUnknown** provider); 55 | } 56 | ``` 57 | ## .Net and WinRT 58 | API is not natively supported in .Net and WinRT. The Win32 COM API is exposed using an interop interface. 59 | -------------------------------------------------------------------------------- /specs/BackgroundColor.md: -------------------------------------------------------------------------------- 1 | # Background 2 | WebView2 developers have provided feedback that there is a 'white flicker' when navigating between pages. This flicker comes from WebView briefly showing its default background color for when no web page is loaded. Developers should be able to set a custom background color for the WebView that matches the color scheme of their app and avoids this flicker. We have also received feedback requesting the ability to set the WebView's background color transparent. This way developers can create a seamless UI experience where the WebView displays web content directly over host app content. The DefaultBackgroundColor API addresses this need. 3 | 4 | 5 | # Description 6 | The `DefaultBackgroundColor` property enables a smoother UI experience. Developers can choose the color that shows between loading pages and eliminate any 'white flash.' For websites with no specified background color, developers can display web contents over a color of their choosing. They can also do away with the background color entirely with transparency and have the 'in between pages color' just be hosting content, or have hosting app content be the backdrop for webpages without a background color specified. 7 | 8 | # Examples 9 | ## Win32 C++ 10 | The fields of COREWEBVIEW2_COLOR can be set with integer values between 0 and 255. In the following example, we see the app reading color values from a COLORREF (which are integers under the covers) into a COREWEBVIEW2_COLOR. It then sets the COREWEBVIEW2_COLOR.A value to 0 or 255. Once the COREWEBVIEW2_COLOR value is filled out, it is passed to the controller's put_DefaultBackgroundColor API. 11 | ```cpp 12 | void ViewComponent::SetBackgroundColor(COLORREF color, bool transparent) 13 | { 14 | COREWEBVIEW2_COLOR wvColor; 15 | wvColor.R = GetRValue(color); 16 | wvColor.G = GetGValue(color); 17 | wvColor.B = GetBValue(color); 18 | wvColor.A = transparent ? 0 : 255; 19 | m_controller->put_DefaultBackgroundColor(wvColor); 20 | } 21 | ``` 22 | ## WinRT 23 | ```c# 24 | private void SetBackgroundColor(Windows.UI.Color color) 25 | { 26 | _coreWebView2Controller.DefaultBackgroundColor = color; 27 | } 28 | ``` 29 | 30 | 31 | # Remarks 32 | Currently only colors with an A set to 0 or 255 are supported by the API. The work to support semi-transparent colors is being tracked and will be added later 33 | 34 | 35 | # API Details 36 | ## Win32 C++ 37 | ```cpp 38 | // This is the ICoreWebView2Controller2 interface 39 | interface ICoreWebView2Controller2 : ICoreWebView2Controller { 40 | 41 | /// The `DefaultBackgroundColor` property allows developers to set the color 42 | /// that shows when WebView has not loaded any web content and when a webpage 43 | /// does not specify a background color. Color is specified by the 44 | /// COREWEBVIEW2_COLOR value meaning the background color can also be 45 | /// transparent. 46 | /// The WebView background color will show before the initial navigation, 47 | /// between navigations before the next page has rendered, and for pages with 48 | /// no `background` style properties set. To clarify the latter case, WebView 49 | /// will always honor a webpage's background content. `DefaultBackgroundColor` 50 | /// will only show in the absence of css `background` style properties. In 51 | /// that case, WebView will render web content over the 52 | /// `DefaultBackgroundColor` color. For a transparent background, web content 53 | /// will render over hosting app content. WebView's default background color 54 | /// is white to resemble the browser experience. 55 | /// It is important to note that while COREWEBVIEW2_COLOR has `A` an alpha 56 | /// value, semi-transparent colors are not supported by this API and setting 57 | /// `DefaultBackgroundColor` to a semi-transparent color will fail with 58 | /// E_INVALIDARG. The only supported alpha values are 0 and 255, all other 59 | /// values will result in E_INVALIDARG. 60 | /// `DefaultBackgroundColor` can only be an opaque color or transparent. 61 | /// 62 | /// The `DefaultBackgroundColor` property enables a smoother UI experience. 63 | /// Developers can choose the color that shows between loading pages and 64 | /// eliminate any 'white flash.' For websites with no specified 65 | /// background color, developers can display web contents over a color of 66 | /// their choosing. They can also do away with the background color entirely 67 | /// with transparency and have the 'in between pages color' just be hosting 68 | /// content, or have hosting app content be the backdrop for webpages without 69 | /// a background color specified. 70 | /// 71 | /// \snippet ViewComponent.cpp DefaultBackgroundColor 72 | 73 | [propget] HRESULT DefaultBackgroundColor( 74 | [out, retval] COREWEBVIEW2_COLOR* backgroundColor); 75 | 76 | /// Sets the `DefaultBackgroundColor` property. 77 | 78 | [propput] HRESULT DefaultBackgroundColor( 79 | [in] COREWEBVIEW2_COLOR backgroundColor); 80 | } 81 | 82 | 83 | /// A value representing RGBA color (Red, Green, Blue, Alpha) for WebView2. 84 | /// Each component takes a value from 0 to 255, with 0 being no intensity 85 | /// and 255 being the highest intensity. 86 | 87 | typedef struct COREWEBVIEW2_COLOR { 88 | 89 | /// Specifies the intensity of the Alpha ie. opacity value. 0 is transparent, 90 | /// 255 is opaque. 91 | 92 | BYTE A; 93 | 94 | /// Specifies the intensity of the Red color 95 | 96 | BYTE R; 97 | 98 | /// Specifies the intensity of the Green color 99 | 100 | BYTE G; 101 | 102 | /// Specifies the intensity of the Blue color 103 | 104 | BYTE B; 105 | } COREWEBVIEW2_COLOR; 106 | ``` 107 | ## WinRT 108 | ```c# 109 | unsealed runtimeclass CoreWebView2Controller 110 | { 111 | // .. 112 | Windows.UI.Color DefaultBackgroundColor { get; set; }; 113 | } 114 | ``` 115 | -------------------------------------------------------------------------------- /specs/BrowserTaskManager.md: -------------------------------------------------------------------------------- 1 | # Background 2 | The WebView2 team has been asked to provide an API to expose the Browser Task 3 | Manager. The Browser Task Manager is a window helpful for debugging that 4 | displays the different processes associated with the current browser process and 5 | what they're used for. For instance, it could denote that a particular process 6 | is a renderer process and would show the different web pages rendered by that 7 | process. In a chromium browser it can be opened by the end user by pressing 8 | `Shift+Esc` or from the DevTools window's title bar's context menu entry 9 | `Browser task manager`. For WebView2 applications, we block the 10 | `Shift+Esc` shortcut, but the task manager can still be opened via the 11 | `Browser task manager` entry. 12 | 13 | At the current time, it is expected that the user will close the Task 14 | Manager manually, so we do not need to provide an API to close it. 15 | 16 | In this document we describe the updated API. We'd appreciate your feedback. 17 | 18 | # Description 19 | We propose extending `CoreWebView2` to provide an `OpenTaskManagerWindow` 20 | method. This method will open a new window containing the task manager. 21 | If the task manager is already opened, this method will do nothing. 22 | 23 | # Examples 24 | ## C++: Open Task Manager 25 | 26 | ``` cpp 27 | wil::com_ptr m_webview; 28 | 29 | // This method could be called from a menu bar item, such as 30 | // [Script -> Open Task Manager Window]. 31 | void ScriptComponent::OpenTaskManagerWindow() 32 | { 33 | auto webview5 = m_webview.try_query(); 34 | if (webview5) 35 | { 36 | CHECK_FAILURE(webview5->OpenTaskManagerWindow()); 37 | } 38 | } 39 | 40 | // Assume OpenTaskManagerWindow is available if the WebView supports ICoreWebView2_5. 41 | bool ScriptComponent::ShouldShowOpenTaskManagerWindowMenuItem() 42 | { 43 | return m_webview.try_query(); 44 | } 45 | ``` 46 | 47 | ## C#: Open Task Manager 48 | ```c# 49 | private WebView2 m_webview; 50 | 51 | // This method could be called from a menu bar item, such as 52 | // [Script -> Open Task Manager Window]. 53 | void OpenTaskManagerWindow() 54 | { 55 | m_webview.CoreWebView2.OpenTaskManagerWindow(); 56 | } 57 | ``` 58 | 59 | # API Details 60 | ## C++ 61 | ``` 62 | /// This is a continuation of the `ICoreWebView2_4` interface 63 | [uuid(20d02d59-6df2-42dc-bd06-f98a694b1302), object, pointer_default(unique)] 64 | interface ICoreWebView2_5 : ICoreWebView2_4 { 65 | /// Opens the Browser Task Manager view as a new window in the foreground. 66 | /// If the Browser Task Manager is already open, this will bring it into 67 | /// the foreground. WebView2 currently blocks the `Shift+Esc` shortcut for 68 | /// opening the task manager. An end user can open the browser task manager 69 | /// manually via the `Browser task manager` entry of the DevTools window's 70 | /// title bar's context menu. 71 | HRESULT OpenTaskManagerWindow(); 72 | } 73 | ``` 74 | 75 | ## C# 76 | ```c# 77 | namespace Microsoft.Web.WebView2.Core 78 | { 79 | runtimeclass CoreWebView2 80 | { 81 | // There are many methods and properties of ICoreWebView2_* which I am 82 | // not including here for simplicity. 83 | 84 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2_5")] 85 | { 86 | // ICoreWebView2_5 members 87 | void OpenTaskManagerWindow(); 88 | } 89 | } 90 | } 91 | ``` 92 | -------------------------------------------------------------------------------- /specs/CoreWebView2.CreateFromCOMObject.md: -------------------------------------------------------------------------------- 1 | CoreWebView2.CreateFromComICoreWebView2 2 | === 3 | 4 | # Background 5 | The new [Unity WebView2](https://learn.microsoft.com/windows/mixed-reality/develop/advanced-concepts/webview2-unity-plugin) 6 | control creates and uses C++ COM to create and manage the 7 | ICoreWebView2* objects. However, Unity developers are often interacting with the Unity WebView2 8 | control using C#/.NET. The Unity WebView2 control doesn't expose the CoreWebView2 directly to devs 9 | using the Unity WebView2 control, so when devs want to call an API on CoreWebView2, they 10 | have to rely on that API being exposed on the Unity WebView2 control, which then internally calls 11 | into CoreWebView2. This is in contrast to our other controls (like WPF WebView2 and Winforms 12 | WebView2 controls) which directly give access to their [CoreWebView2 object](https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.winforms.webview2.corewebview2?view=webview2-dotnet-1.0.2088.41), 13 | allowing devs to call any API that exists or gets 14 | added to the CoreWebView2/ICoreWebView2_*. The Unity WebView2 control can't do this today, 15 | as they are unable to create a CoreWebView2 object that wraps an already existing COM object. 16 | To help implement this for Unity, we are adding a new static factory function on CoreWebView2 .NET 17 | class that will allow it to wrap an existing ICoreWebView2 COM object, instead of creating a new 18 | one. 19 | 20 | To round out the more general scenario of interoperating between libraries written in different 21 | languages, we add the ability to convert a CoreWebView2 to and from .NET and COM, as well as 22 | to and from WinRT and COM. 23 | 24 | # Examples 25 | 26 | ## COM to .NET 27 | 28 | ```c# 29 | public class MyWebView2Control 30 | { 31 | ... // Regular control code 32 | 33 | CoreWebView2 _myCoreWebView2 = null; 34 | 35 | [DllImport(DLL_NAME, CallingConvention = CallingConvention.StdCall)] 36 | public static extern ComNativePointer GetNativePointer(WebViewInstancePtr instanceId); 37 | 38 | // This is the CoreWebView2 property which allows developers to access CoreWebView2 APIs directly. 39 | public CoreWebView2 CoreWebView2 40 | { 41 | get 42 | { 43 | if (!_myCoreWebView2) 44 | { 45 | IntPtr comPtr = WebViewNative.GetNativePointer(InstanceId); 46 | 47 | _myCoreWebView2 = CoreWebView2.CreateFromComICoreWebView2(comPtr); 48 | } 49 | return _myCoreWebView2; 50 | } 51 | } 52 | 53 | } 54 | ``` 55 | 56 | ## WinRT to COM 57 | 58 | ```c++ 59 | winrt::com_ptr GetComICoreWebView2FromCoreWebView2( 60 | winrt::Microsoft::Web::WebView2::Core::CoreWebView2 coreWebView2WinRT) 61 | { 62 | // Get the COM interop interface from the WinRT CoreWebView2. 63 | auto interop = coreWebView2WinRT.as(); 64 | 65 | // Get the COM ICoreWebView2 object from the COM interop interface. 66 | winrt::com_ptr coreWebView2Com; 67 | winrt::check_hresult(interop->GetComICoreWebView2(coreWebView2Com.put())); 68 | 69 | return coreWebView2Com; 70 | } 71 | ``` 72 | 73 | ## COM to WinRT 74 | 75 | ```c++ 76 | winrt::Microsoft::Web::WebView2::Core::CoreWebView2 CreateCoreWebView2FromComICoreWebView2( 77 | winrt::com_ptr coreWebView2Com) 78 | { 79 | auto factory = winrt::get_activation_factory< 80 | winrt::Microsoft::Web::WebView2::Core::CoreWebView2>(); 81 | 82 | // Get the COM interop interface from the WinRT factory. 83 | auto interop = factory.try_as(); 84 | 85 | // Get the WinRT CoreWebView2 object from the COM interop interface as 86 | // its ABI interface. 87 | winrt::com_ptr coreWebView2WinRTAsIUnknown; 88 | winrt::check_hresult(interop->CreateFromComICoreWebView2( 89 | coreWebView2Com.get(), coreWebView2WinRTAsIUnknown.put())); 90 | 91 | // Convert from the WinRT CoreWebView2 object API interface to C++/WinRT type 92 | return coreWebView2WinRTAsIUnknown.as< 93 | winrt::Microsoft::Web::WebView2::Core::CoreWebView2>(); 94 | } 95 | ``` 96 | 97 | 98 | # API Details 99 | 100 | ## .NET API 101 | 102 | ```c# 103 | namespace Microsoft.Web.WebView2.Core 104 | { 105 | public class CoreWebView2 106 | { 107 | /// 108 | /// Creates a CoreWebView2 object that wraps an existing COM ICoreWebView2 object. 109 | /// This allows interacting with the WebView2 control using .NET, 110 | /// even if the control was originally created using COM. 111 | /// 112 | /// Pointer to a COM object that implements the ICoreWebView2 COM interface. 113 | /// Returns a .NET CoreWebView2 object that wraps the COM object. 114 | /// Thrown when the provided COM pointer is null. 115 | /// Thrown when the value is not an ICoreWebView2 COM object and cannot be wrapped. 116 | public static CoreWebView2 CreateFromComICoreWebView2(IntPtr value); 117 | 118 | /// 119 | /// Returns the existing COM ICoreWebView2 object underlying this .NET CoreWebView2 object. 120 | /// This allows interacting with the WebView2 control using COM APIs, 121 | /// even if the control was originally created using .NET. 122 | /// 123 | /// Pointer to a COM object that implements the ICoreWebView2 COM interface. 124 | public IntPtr GetComICoreWebView2(); 125 | } 126 | } 127 | ``` 128 | 129 | ## WinRT COM Interop API 130 | 131 | ```c# (but really COM IDL) 132 | /// Interop interface for the CoreWebView2 WinRT object to allow WinRT end 133 | /// developers to be able to use COM interfaces as parameters for some methods. 134 | /// This interface is implemented by the Microsoft.Web.WebView2.Core.CoreWebView2 135 | /// runtime class. 136 | [uuid(B151AD7C-CFB0-4ECF-B9B2-AFCA868581A6), object, pointer_default(unique)] 137 | interface ICoreWebView2Interop2 : IUnknown { 138 | /// Get a COM ICoreWebView2 interface corresponding to this WinRT CoreWebView2 139 | /// object. 140 | HRESULT GetComICoreWebView2([out, retval] ICoreWebView2** coreWebView2); 141 | } 142 | 143 | /// Interop interface for the CoreWebView2 WinRT activation factory object to allow 144 | /// WinRT end developers to be able to use COM interfaces as parameters for some 145 | /// methods. 146 | /// This interface is implemented by the Microsoft.Web.WebView2.Core.CoreWebView2 147 | /// activation factory runtime class. 148 | [uuid(BABBED43-D40E-40CF-B106-8ED65FAE2E7C), object, pointer_default(unique)] 149 | interface ICoreWebView2ActivationFactoryInterop : IUnknown { 150 | /// Creates a CoreWebView2 WinRT object that wraps an existing COM ICoreWebView2 object. 151 | /// This allows interacting with the WebView2 control using WinRT, 152 | /// even if the control was originally created using COM. 153 | HRESULT CreateFromComICoreWebView2([in] ICoreWebView2* coreWebView2Com, 154 | [out, retval] IUnknown** coreWebView2WinRt); 155 | } 156 | 157 | ``` 158 | 159 | # Appendix 160 | We have a couple of other options to accomplish this, including moving the "CreateFromComICoreWebView2" function to the 161 | CoreWebView2Controller class instead. CoreWebView2Controller could then be used to get the CoreWebView2 through 162 | its CoreWebView2 property which already exists. Or we could expose a new constructor on CoreWebView2/CoreWebView2Controller, 163 | instead of a factory method. 164 | 165 | We decided on using the CoreWebView2 due to it being the class most likely to be exposed and used 166 | in .NET, and which is the same across different C# frameworks. 167 | We decided on a factory method to not give the impression that a new constructor is the default 168 | one (we don't currently have any public constructors), and to make the intent and usage of 169 | the method more obvious. 170 | -------------------------------------------------------------------------------- /specs/CoreWebView2ControllerOptions.DefaultBackgroundColor.md: -------------------------------------------------------------------------------- 1 | CoreWebView2ControllerOptions.DefaultBackgroundColor 2 | === 3 | # Background 4 | 5 | Previously, there was a fix to address an issue where the background color controller property 6 | was applied too late, causing a disruptive white flash during the WebView2 loading process. 7 | 8 | This fix required using an environment variable. However, this workaround was not meant to be 9 | a long-term solution. Therefore, we need to add this setting to `ICoreWebView2ControllerOptions` 10 | to apply the color early in the loading process. 11 | 12 | # Description 13 | 14 | This interface extends the `ICoreWebView2ControllerOptions` to expose the `DefaultBackgroundColor` 15 | property as an option. 16 | The `CoreWebView2ControllerOptions.DefaultBackgroundColor` API allows users to set the 17 | `DefaultBackgroundColor` property at initialization. 18 | 19 | This is useful when setting it using the existing [`CoreWebView2Controller.DefaultBackgroundColor API`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2controller.defaultbackgroundcolor?view=webview2-dotnet-1.0.2792.45) 20 | applies the color too late. 21 | 22 | 23 | 24 | # Examples 25 | 26 | ## Win32 C++ 27 | ```cpp 28 |  HRESULT AppWindow::CreateControllerWithOptions() 29 | { 30 | wil::com_ptr options; 31 | HRESULT hr = m_environment->CreateCoreWebView2ControllerOptions(&options); 32 | 33 | if (hr == E_INVALIDARG) 34 | { 35 | ShowFailure(hr, L"Invalid profile name."); 36 | return S_OK; 37 | } 38 | 39 | wil::com_ptr options4; 40 | auto result = options->QueryInterface(IID_PPV_ARGS(&options4)); 41 | 42 | if (SUCCEEDED(result)) 43 | { 44 | COREWEBVIEW2_COLOR wvColor{255, 85, 0, 225}; 45 | options4->put_DefaultBackgroundColor(wvColor); 46 | } 47 | 48 | m_environment->CreateCoreWebView2ControllerWithOptions( 49 | m_mainWindow, 50 | options.Get(), 51 | Callback( 52 | this, &AppWindow::OnCreateCoreWebView2ControllerCompleted).Get()); 53 | 54 | return S_OK; 55 | 56 | } 57 | ``` 58 | 59 | 60 | 61 | ## C# 62 | ```c# 63 | public MainWindow() 64 | { 65 | InitializeComponent(); 66 | SetDefaultBackgroundColor(); 67 | } 68 | 69 | private async Task 70 | SetDefaultBackgroundColor() 71 | { 72 | CoreWebView2Environment environment = await 73 | CoreWebView2Environment.CreateAsync(); 74 | CoreWebView2ControllerOptions options = environment.CreateCoreWebView2ControllerOptions(); 75 | options.DefaultBackgroundColor = Color.FromArgb(255, 85, 0, 255); 76 | await WebView2.EnsureCoreWebView2Async(environment, options); 77 | } 78 | 79 | ``` 80 | 81 | 82 | 83 | # API Details 84 | 85 | ## Win32 C++ 86 | ```cpp 87 | /// This interface extends the ICoreWebView2ControllerOptions interface to expose 88 | /// DefaultBackgroundColor property. It is encouraged to transition away from the 89 | /// environment variable and use this API solution to apply the property. 90 | 91 | [uuid(df9cb70b-8d87-5bca-ae4b-6f23285e8d94), object, pointer_default(unique)] 92 | interface ICoreWebView2ControllerOptions4 : ICoreWebView2ControllerOptions3 { 93 | 94 | /// This API allows users to initialize the `DefaultBackgroundColor` early, 95 | /// preventing a white flash that can occur while WebView2 is loading when 96 | /// the background color is set to something other than white. With early 97 | /// initialization, the color remains consistent from the start. After 98 | /// initialization, `ICoreWebView2Controller2::get_DefaultBackgroundColor` 99 | /// will return the value set using this API. 100 | /// 101 | /// The `DefaultBackgroundColor` is the color that renders underneath all web 102 | /// content. This means WebView renders this color when there is no web 103 | /// content loaded. When no background color is defined in WebView2, it uses 104 | /// the `DefaultBackgroundColor` property to render the background. 105 | /// By default, this color is set to white. 106 | /// 107 | /// This API only supports opaque colors and full transparency. It will 108 | /// fail for colors with alpha values that don't equal 0 or 255. 109 | /// When WebView2 is set to be fully transparent, it does not render a background, 110 | /// allowing the content from windows behind it to be visible. 111 | 112 | [propget] HRESULT DefaultBackgroundColor([out, retval] COREWEBVIEW2_COLOR* value); 113 | [propput] HRESULT DefaultBackgroundColor([in] COREWEBVIEW2_COLOR value); 114 | 115 | } 116 | ``` 117 | 118 | 119 | 120 | ## .NET WinRT 121 | 122 | ```cpp 123 | namespace Microsoft.Web.WebView2.Core 124 | { 125 | runtimeclass CoreWebView2ControllerOptions 126 | { 127 | // ... 128 | [interface_name("ICoreWebView2ControllerOptions4")] 129 | { 130 | Windows.UI.Color DefaultBackgroundColor { get; set; }; 131 | } 132 | } 133 | } 134 | } 135 | 136 | ``` 137 | -------------------------------------------------------------------------------- /specs/CustomDefaultDownloadLocation.md: -------------------------------------------------------------------------------- 1 | Custom Default Download Location 2 | === 3 | 4 | # Background 5 | This API allows you to set a custom default download location per profile. The 6 | user can still change the path through the Save As dialog. 7 | 8 | In this document we describe the updated API. We'd appreciate your feedback. 9 | 10 | # Examples 11 | ```cpp 12 | HRESULT AppWindow::OnCreateCoreWebView2ControllerCompleted( 13 | HRESULT result, ICoreWebView2Controller* controller) 14 | { 15 | if (result == S_OK) 16 | { 17 | if (!m_webviewOption.downloadPath.empty()) 18 | { 19 | Microsoft::WRL::ComPtr profile2; 20 | CHECK_FAILURE(m_profile->QueryInterface(IID_PPV_ARGS( 21 | &profile2))); 22 | CHECK_FAILURE(profile2->put_DefaultDownloadFolderPath( 23 | m_webviewOption.downloadPath.c_str())); 24 | } 25 | } 26 | } 27 | ``` 28 | ```c# 29 | void WebView_CoreWebView2InitializationCompleted(object sender, 30 | CoreWebView2InitializationCompletedEventArgs e) 31 | { 32 | if (e.IsSuccess) 33 | { 34 | if (!string.IsNullOrEmpty(_downloadPath)) 35 | { 36 | WebViewProfile.DefaultDownloadFolderPath = _downloadPath; 37 | } 38 | } 39 | } 40 | ``` 41 | # API Details 42 | ```c# 43 | /// This is a continuation of the `ICoreWebView2Profile` interface. 44 | [uuid(DAF8B1F9-276D-410C-B481-58CBADF85C9C), object, pointer_default(unique)] 45 | interface ICoreWebView2Profile2 : ICoreWebView2Profile { 46 | /// Gets the `DefaultDownloadFolderPath` property. The default value is the 47 | /// system default download folder path for the user. 48 | [propget] HRESULT DefaultDownloadFolderPath([out, retval] LPWSTR* value); 49 | 50 | /// Sets the `DefaultDownloadFolderPath` property. The default download folder 51 | /// path is persisted in the user data folder across sessions. The value 52 | /// should be an absolute path to a folder that the user and application can 53 | /// write to. Returns `E_INVALIDARG` if the value is invalid, and the default 54 | /// download folder path is not changed. Otherwise the path is changed 55 | /// immediately. If the directory does not yet exist, it is created at the 56 | /// time of the next download. If the host application does not have 57 | /// permission to create the directory, then the user is prompted to provide a 58 | /// new path through the Save As dialog. The user can override the default 59 | /// download folder path for a given download by choosing a different path in 60 | /// the Save As dialog. 61 | [propput] HRESULT DefaultDownloadFolderPath([in] LPCWSTR value); 62 | } 63 | ``` 64 | ```c# 65 | namespace Microsoft.Web.WebView2.Core 66 | { 67 | runtimeclass CoreWebView2Profile 68 | { 69 | // The following properties already exist. 70 | // String ProfileName { get; }; 71 | // Boolean IsInPrivateModeEnabled { get; }; 72 | // String ProfilePath { get; }; 73 | 74 | // The following method already exists. 75 | // Windows.Foundation.IAsyncOperation ClearBrowsingDataAsync( 76 | // UInt64 dataKinds, Double startTime, Double endTime); 77 | 78 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Profile2")] 79 | { 80 | String DefaultDownloadFolderPath { get; set; }; 81 | } 82 | } 83 | } 84 | ``` 85 | -------------------------------------------------------------------------------- /specs/CustomScrollbar.md: -------------------------------------------------------------------------------- 1 | Custom ScrollBar Style 2 | === 3 | 4 | # Background 5 | Developers would like to be able to set the ScrollBar to Windows fluent overlay style and 6 | match the Windows theme. Some customers have used browser flags but they change names and behavior and are not reliable. Thus we want 7 | to provide an extendable API that allows developers to set ScrollBar style. Currently, 8 | only Windows fluent overlay are supported, adding new styles in the future will not introduce 9 | any breaking changes. 10 | 11 | # Examples 12 | ## WinRT and .NET 13 | ```c# 14 | // Create WebView Environment with option 15 | async void CreateEnvironmentWithOption() 16 | { 17 | CoreWebView2EnvironmentOptions options = new CoreWebView2EnvironmentOptions(); 18 | options.ScrollBarStyle = ScrollBarStyle.FluentOverlay; 19 | CoreWebView2Environment environment = await CoreWebView2Environment.CreateAsync(options: options); 20 | webview.EnsureCoreWebView2Async(environment); 21 | } 22 | ``` 23 | 24 | ## Win32 C++ 25 | ```cpp 26 | void AppWindow::InitializeWebView() 27 | { 28 | auto options = Microsoft::WRL::Make(); 29 | COREWEBVIEW2_SCROLLBAR_STYLE style = COREWEBVIEW2_SCROLLBAR_STYLE_FLUENT_OVERLAY; 30 | CHECK_FAILURE(options->put_ScrollBarStyle(style)); 31 | 32 | // ... other option properties 33 | 34 | // ... CreateCoreWebView2EnvironmentWithOptions 35 | } 36 | ``` 37 | 38 | # API Notes 39 | 40 | See [API Details](#api-details) section below for API reference. 41 | 42 | # API Details 43 | ## Win32 C++ 44 | 45 | ```IDL 46 | interface ICoreWebView2EnvironmentOptions7; 47 | 48 | [v1_enum] 49 | typedef enum COREWEBVIEW2_SCROLLBAR_STYLE { 50 | /// Browser default ScrollBar style 51 | COREWEBVIEW2_SCROLLBAR_STYLE_DEFAULT, 52 | /// Window style fluent overlay scroll bar 53 | /// Please see [Fluent UI](https://developer.microsoft.com/en-us/fluentui#/) 54 | /// for more details on fluent UI. 55 | COREWEBVIEW2_SCROLLBAR_STYLE_FLUENT_OVERLAY 56 | } COREWEBVIEW2_SCROLLBAR_STYLE; 57 | 58 | /// Additional options used to create WebView2 Environment. 59 | [uuid(9c8ac95a-6b5f-4efb-b5f6-98bb33469759), object, pointer_default(unique)] 60 | interface ICoreWebView2EnvironmentOptions7 : ICoreWebView2EnvironmentOptions6 { 61 | /// Get the ScrollBar style being set on the WebView2 Environment. 62 | [propget] HRESULT ScrollBarStyle([out, retval] COREWEBVIEW2_SCROLLBAR_STYLE* value); 63 | /// Set ScrollBar style to be used. The default is `COREWEBVIEW2_SCROLLBAR_STYLE_DEFAULT` 64 | /// which specifies the default browser ScrollBar style. 65 | /// CSS styles that modify the ScrollBar applied on top of native ScrollBar styling 66 | /// that is selected with `ScrollBarStyle`. 67 | [propput] HRESULT ScrollBarStyle([in] COREWEBVIEW2_SCROLLBAR_STYLE value); 68 | } 69 | ``` 70 | 71 | ## .NET and WinRT 72 | 73 | ```c# 74 | namespace Microsoft.Web.WebView2.Core 75 | { 76 | 77 | enum ScrollBarStyle 78 | { 79 | Default = 0, 80 | FluentOverlay = 1, 81 | }; 82 | 83 | // ... 84 | runtimeclass CoreWebView2EnvironmentOptions 85 | { 86 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2EnvironmentOptions7")] 87 | { 88 | // Set ScrollBar style 89 | ScrollBarStyle ScrollBarStyle { get; set; }; 90 | } 91 | } 92 | 93 | // ... 94 | } 95 | ``` -------------------------------------------------------------------------------- /specs/DOMContentLoaded.md: -------------------------------------------------------------------------------- 1 | # Background 2 | 3 | In response to consumers' requests for an event similar to the old [WebView DOMContentLoaded](https://learn.microsoft.com/microsoft-edge/hosting/webview#mswebviewdomcontentloaded), the WebView2 team has introduced DOMContentLoaded API which indicates that the main DOM elements have finished loading. 4 | In this document we describe the new API. We'd appreciate your feedback. 5 | 6 | # Description 7 | We propose adding DOMContentLoaded to CoreWebView2. This allows the developer to have an event that fires when the DOM is loaded after the WebView2 navigates to a page. 8 | 9 | # Examples 10 | ## Win32 C++ 11 | ``` 12 | ScenarioDOMContentLoaded::ScenarioDOMContentLoaded(SampleAppWindow* sampleAppWindow) 13 | : m_sampleAppWindow(sampleAppWindow), m_webView(sampleAppWindow->GetWebView()) 14 | { 15 | //! [DOMContentLoaded] 16 | // Register a handler for the DOMContentLoaded event. 17 | // Event is raised when the DOM content is loaded 18 | CHECK_FAILURE(m_webView->add_DOMContentLoaded( 19 | Callback( 20 | [this](ICoreWebView2* sender, ICoreWebView2DOMContentLoadedEventArgs* args) 21 | -> HRESULT { 22 | m_webView->ExecuteScript( 23 | LR"~( 24 | let content=document.createElement("h2"); 25 | content.style.color='blue'; 26 | content.textContent="This text was added by the host app"; 27 | document.body.appendChild(content); 28 | )~", 29 | Callback( 30 | [](HRESULT error, PCWSTR result) -> HRESULT { return S_OK; }) 31 | .Get()); 32 | return S_OK; 33 | }) 34 | .Get(), 35 | &m_DOMContentLoadedToken)); 36 | //! [DOMContentLoaded] 37 | ``` 38 | 39 | ## C# 40 | ``` 41 | webView.CoreWebView2.DOMContentLoaded += (object sender, CoreWebView2DOMContentLoadedEventArgs arg) => 42 | { 43 | _ = webView.ExecuteScriptAsync("let " + 44 | "content=document.createElement(\"h2\");content.style.color=" + 45 | "'blue';content.textContent= \"This text was added by the " + 46 | "host app\";document.body.appendChild(content);"); 47 | }; 48 | webView.NavigateToString(@"

DOMContentLoaded sample page

The content below will be added after DOM content is loaded

"); 49 | 50 | ``` 51 | 52 | # API Notes 53 | 54 | See [API Details](#api-details) section below for API reference. 55 | # API Details 56 | 57 | ## Win32 C++ 58 | 59 | ```IDL 60 | interface ICoreWebView2_2; 61 | interface ICoreWebView2DOMContentLoadedEventArgs; 62 | interface ICoreWebView2DOMContentLoadedEventHandler; 63 | 64 | [uuid(9810c82b-8483-4f1c-b2f4-6244f1010c05), object, pointer_default(unique)] 65 | interface ICoreWebView2_2 : ICoreWebView2 { 66 | /// Add an event handler for the DOMContentLoaded event. 67 | /// DOMContentLoaded is raised when the initial html document has been parsed. 68 | /// This aligns with the the document's DOMContentLoaded event in html 69 | /// 70 | /// \snippet ScenarioDOMContentLoaded-Staging.cpp 71 | HRESULT add_DOMContentLoaded( 72 | [in] ICoreWebView2StagingDOMContentLoadedEventHandler* eventHandler, 73 | [out] EventRegistrationToken* token); 74 | /// Remove an event handler previously added with add_DOMContentLoaded. 75 | HRESULT remove_DOMContentLoaded( 76 | [in] EventRegistrationToken token); 77 | } 78 | 79 | /// Event args for the DOMContentLoaded event. 80 | [uuid(E8BA4206-D6F8-42F1-9A6D-43C8A99C1F39), object, pointer_default(unique)] 81 | interface ICoreWebView2DOMContentLoadedEventArgs : IUnknown { 82 | /// The ID of the navigation which corresponds to other navigation ID properties on other navigation events. 83 | [propget] HRESULT NavigationId([out, retval] UINT64* navigationId); 84 | } 85 | 86 | /// The caller implements this interface to receive the DOMContentLoaded 87 | /// event. 88 | [uuid(1E649181-785D-40B2-B4AE-AFACD3C6B8DD), object, pointer_default(unique)] 89 | interface ICoreWebView2DOMContentLoadedEventHandler : IUnknown { 90 | /// Called to provide the implementer with the event args for the 91 | /// corresponding event. 92 | HRESULT Invoke( 93 | [in] ICoreWebView2* sender, 94 | [in] ICoreWebView2DOMContentLoadedEventArgs* args); 95 | } 96 | ``` 97 | 98 | ## .NET and WinRT 99 | 100 | ```c# 101 | namespace Microsoft.Web.WebView2.Core 102 | { 103 | runtimeclass CoreWebView2DOMContentLoadedEventArgs; 104 | 105 | runtimeclass CoreWebView2DOMContentLoadedEventArgs 106 | { 107 | // CoreWebView2DOMContentLoadedEventArgs 108 | UInt64 NavigationId { get; }; 109 | } 110 | 111 | runtimeclass CoreWebView2 112 | { 113 | // CoreWebView2 114 | event Windows.Foundation.TypedEventHandler DOMContentLoaded; 115 | } 116 | 117 | 118 | } 119 | ``` 120 | -------------------------------------------------------------------------------- /specs/DisableCrashReporting.md: -------------------------------------------------------------------------------- 1 | Custom Crash Reports 2 | === 3 | 4 | # Background 5 | If any WebView2 process crashes, one or multiple minidump files will be created and sent to Microsoft for diagnosis. This document covers new APIs to allow the end developer to customize crash reporting to help when running diagnostics and doing analysis. They can set the `CoreWebView2EnvironmentOptions.IsCustomCrashReportingEnabled` property to true to prevent crash dumps from being sent to Microsoft and use the `CoreWebView2Environment.CrashDumpFolderPath` property to locate crash dumps and do customization with them instead. 6 | 7 | # Examples 8 | ## WinRT and .NET 9 | ```c# 10 | 11 | /// Create WebView Environment with option 12 | 13 | void CreateEnvironmentWithOption() 14 | { 15 | CoreWebView2EnvironmentOptions options = new CoreWebView2EnvironmentOptions(); 16 | options.CustomizeFailureReporting = true; 17 | CoreWebView2Environment environment = await CoreWebView2Environment.CreateAsync(BrowserExecutableFolder, UserDataFolder, options); 18 | } 19 | 20 | void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) 21 | { 22 | webView.CoreWebView2.ProcessFailed += WebView_ProcessFailed; 23 | } 24 | 25 | var _processed_dump_files = new HashSet(); 26 | 27 | void WebView_ProcessFailed(object sender, CoreWebView2ProcessFailedEventArgs e) 28 | { 29 | // When process failed, do custom parsing with dumps 30 | string failureReportFolder = webView.CoreWebView2.Environment.FailureReportFolderPath; 31 | string[] dump_files = Directory.GetFiles(failureReportFolder); 32 | foreach (string dump_file in dump_files) { 33 | if (!_processed_dump_files.Contains(dump_file)) { 34 | _processed_dump_files.Add(dump_file); 35 | ProcessNewCrashDumps(dump_file); 36 | } 37 | } 38 | } 39 | 40 | ``` 41 | ## Win32 C++ 42 | ```cpp 43 | #include 44 | using namespace std; 45 | namespace fs = std::filesystem; 46 | 47 | void AppWindow::InitializeWebView() 48 | { 49 | auto options = Microsoft::WRL::Make(); 50 | CHECK_FAILURE(options->put_CustomizeFailureReporting(TRUE)); 51 | // ... other option properties 52 | 53 | // ... CreateCoreWebView2EnvironmentWithOptions 54 | 55 | // Set up handler 56 | wil::com_ptr environment; 57 | CHECK_FAILURE(m_webView->get_Environment(&environment)); 58 | wil::com_ptr environment11; 59 | CHECK_FAILURE(environment->QueryInterface(IID_PPV_ARGS(&environment11)); 60 | wil::unique_cotaskmem_string failureReportFolder; 61 | CHECK_FAILURE(environment11->get_FailureReportFolderPath(&failureReportFolder)); 62 | 63 | std::set processed_dump_files; 64 | 65 | // Register a handler for the ProcessFailed event. 66 | CHECK_FAILURE(m_webView->add_ProcessFailed( 67 | Callback( 68 | [this, processed_dump_files, 69 | failureReportFolder = std::move(failureReportFolder)]( 70 | ICoreWebView2* sender, 71 | ICoreWebView2ProcessFailedEventArgs* argsRaw) -> HRESULT 72 | { 73 | for (const auto& entry: fs::directory_iterator(failureReportFolder.get())) 74 | { 75 | auto dump_file = entry.path().filename(); 76 | if (processed_dump_files.count(dump_file) == 0) 77 | { 78 | processed_dump_files.insert(dump_file); 79 | ProcessNewCrashDumps(dump_file); 80 | } 81 | } 82 | return S_OK; 83 | }) 84 | .Get(), 85 | &m_processFailedToken)); 86 | } 87 | ``` 88 | 89 | # API Details 90 | ``` 91 | interface ICoreWebView2Environment11; 92 | interface ICoreWebView2EnvironmentOptions3; 93 | 94 | /// A continuation of the ICoreWebView2Environment interface for 95 | /// getting the crash dump folder path 96 | [uuid(F619312E-0399-4520-B700-30818441785A), object, pointer_default(unique)] 97 | interface ICoreWebView2Environment11 : ICoreWebView2Environment10 { 98 | /// `FailureReportFolderPath` get the folder path of where minidump files is written. 99 | /// Whenever a WebView2 process crashes, a crash dump file will be created in the crash dump folder. 100 | /// A crash dump format is minidump files, please see 101 | /// https://learn.microsoft.com/windows/win32/debug/minidump-files for detailed documentation. 102 | /// Normally when a single child process failed, a minidump will be generated and written to disk, 103 | /// then `ProcessFailed` event is raised. But for unexpected crashes, minidump might not be generated 104 | /// at all, despite whether `ProcessFailed` event is raised. For times, that there are multiple 105 | /// processes failed, multiple minidump files could be generated. Thus `FailureReportFolderPath` 106 | /// could contain old minidump files that are not associated with a specific `ProcessFailed` event. 107 | /// `FailureReportFolderPath` remains the same for the lifetime of the environment. 108 | // MSOWNERS: xiaqu@microsoft.com 109 | [propget] HRESULT FailureReportFolderPath([out, retval] LPWSTR* value); 110 | } 111 | 112 | /// Additional options used to create WebView2 Environment. 113 | [uuid(3FB94506-58AB-4171-9082-E7D683471A48), object, pointer_default(unique)] 114 | interface ICoreWebView2EnvironmentOptions3 : ICoreWebView2EnvironmentOptions2 { 115 | 116 | /// When `CustomizeFailureReporting` is set to `TRUE`, Windows won't send crash data to Microsoft endpoint. 117 | /// `CustomizeFailureReporting` is default to be `FALSE`, in this case, WebView respect OS consent. 118 | // MSOWNERS: xiaqu@microsoft.com 119 | [propget] HRESULT CustomizeFailureReporting([out, retval] BOOL* value); 120 | 121 | /// Sets the `CustomizeFailureReporting` property. 122 | // MSOWNERS: xiaqu@microsoft.com 123 | [propput] HRESULT CustomizeFailureReporting([in] BOOL value); 124 | } 125 | ``` 126 | 127 | ```c# (but really MIDL3) 128 | namespace Microsoft.Web.WebView2.Core 129 | { 130 | 131 | // ... 132 | runtimeclass CoreWebView2EnvironmentOptions 133 | { 134 | // ... 135 | Boolean CustomizeFailureReporting { get; set; }; 136 | } 137 | 138 | runtimeclass CoreWebView2Environment 139 | { 140 | String FailureReportFolderPath { get; }; 141 | } 142 | 143 | // ... 144 | } 145 | ``` 146 | 147 | -------------------------------------------------------------------------------- /specs/DisableNavigatingBackAndForward.md: -------------------------------------------------------------------------------- 1 | # API spec for disable navigating back/forward 2 | 3 | # Background 4 | This problem was first identified by a developer on GitHub, who wants to prevent users navigating 5 | back or forward using any of the built-in shortcut keys or special mouse buttons. 6 | 7 | Afterwards, Teams made similar demands. They wanted a mechanism which could support them in 8 | controlling the behaviors of `go back` and `go forward` freely, like disabling them. 9 | 10 | @Haichao Zhu has already finished some work on letting application developers handle all input and 11 | decide whether to suppress. 12 | 13 | This should be solvable in a generic way. However, this feature hasn’t been released yet, and it might 14 | be better if we could provide a simpler and more direct way. 15 | 16 | Therefore, our job is to provide a mechanism for developers to disable navigating back and forward 17 | without excessive effort. 18 | 19 | 20 | # Examples 21 | #### Win32 C++ 22 | 23 | ##### Use `ICoreWebView2NavigationStartingEventArgs3` in `add_NavigationStarting` 24 | 25 | ```c++ 26 | //! [NavigationStarting] 27 | // Register a handler for the NavigationStarting event. 28 | // This handler will check the navigation status, and if the navigation is 29 | // `GoBack` or `GoForward`, it will be canceled. 30 | CHECK_FAILURE(m_webView->add_NavigationStarting( 31 | Callback( 32 | [this](ICoreWebView2* sender, ICoreWebView2NavigationStartingEventArgs* args) 33 | -> HRESULT { 34 | wil::com_ptr args3; 35 | if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args3)))) 36 | { 37 | COREWEBVIEW2_NAVIGATION_KIND kind; 38 | CHECK_FAILURE(args3->get_NavigationKind(&kind)); 39 | // disable navigation if it is back/forward 40 | if (kind == COREWEBVIEW2_NAVIGATION_KIND_BACK_OR_FORWARD) 41 | { 42 | CHECK_FAILURE(args->put_Cancel(true)); 43 | } 44 | } 45 | return S_OK; 46 | }) 47 | .Get(), 48 | &m_navigationStartingToken)); 49 | //! [NavigationStarting] 50 | ``` 51 | 52 | #### .NET and WinRT 53 | 54 | #### Use `CoreWebView2NavigationStartingEventArgs` in `NavigationStarting` 55 | 56 | ```c# 57 | // Register a handler for the NavigationStarting event. 58 | // This handler will check the navigation status, and if the navigation is 59 | // `GoBack` or `GoForward`, it will be canceled. 60 | void WebView_NavigationStarting(object sender, CoreWebView2NavigationStartingEventArgs e) 61 | { 62 | if (e.NavigationKind == CoreWebView2NavigationKind.BackOrForward) 63 | { 64 | e.Cancel = true; 65 | } 66 | } 67 | ``` 68 | 69 | # API Details 70 | #### Win32 C++ 71 | 72 | ```c++ 73 | // Enums and structs 74 | [v1_enum] 75 | typedef enum COREWEBVIEW2_NAVIGATION_KIND { 76 | /// A navigation caused by CoreWebView2.Reload(), location.reload(), the end user 77 | /// using F5 or other UX, or other reload mechanisms to reload the current document 78 | /// without modifying the navigation history. 79 | COREWEBVIEW2_NAVIGATION_KIND_RELOAD, 80 | /// A navigation back or forward to a different entry in the session navigation history. 81 | /// For example via CoreWebView2.Back(), location.back(), the end user pressing Alt+Left 82 | /// or other UX, or other mechanisms to navigate forward or backward in the current 83 | /// session navigation history. 84 | COREWEBVIEW2_NAVIGATION_KIND_BACK_OR_FORWARD, 85 | /// A navigation to a different document. This can be caused by CoreWebView2.Navigate(), 86 | /// window.location.href = '...', or other WebView2 or DOM APIs that navigate to a specific URI. 87 | COREWEBVIEW2_NAVIGATION_KIND_DIFFERENT_DOCUMENT, 88 | } COREWEBVIEW2_NAVIGATION_KIND; 89 | 90 | /// Extend `NavigationStartingEventArgs` by adding more information. 91 | [uuid(39A27807-2365-470B-AF28-885502121049), object, pointer_default(unique)] 92 | interface ICoreWebView2NavigationStartingEventArgs3 : ICoreWebView2NavigationStartingEventArgs2 { 93 | 94 | /// Indicates if this navigation is reload, back/forward or navigating to a different document 95 | [propget] HRESULT NavigationKind( 96 | [out, retval] COREWEBVIEW2_NAVIGATION_KIND* kind); 97 | } 98 | } 99 | ``` 100 | 101 | #### .NET and WinRT 102 | 103 | ```c# (but really MIDL3) 104 | namespace Microsoft.Web.WebView2.Core 105 | { 106 | enum CoreWebView2NavigationKind 107 | { 108 | Reload = 0, 109 | BackOrForward = 1, 110 | DifferentDocument = 2, 111 | }; 112 | // .. 113 | runtimeclass CoreWebView2NavigationStartingEventArgs 114 | { 115 | // ICoreWebView2NavigationStartingEventArgs members 116 | // .. 117 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2NavigationStartingEventArgs3")] 118 | { 119 | // ICoreWebView2NavigationStartingEventArgs3 members 120 | CoreWebView2NavigationKind NavigationKind { get; }; 121 | } 122 | } 123 | } 124 | ``` 125 | 126 | 127 | # Appendix 128 | Relative scenario could be found here: https://dev.azure.com/microsoft/Edge/_workitems/edit/42081893. 129 | 130 | Design doc and reviews could be found here: https://microsoftapc-my.sharepoint.com/:w:/g/personal/pengyuanwang_microsoft_com/Ecu4x6kcjqxNrmvqQW7jr0QBCbHzd1PJ7M3h895rt_l_lg?e=ydF6ez. 131 | -------------------------------------------------------------------------------- /specs/ExclusiveUserDataFolderAccess.md: -------------------------------------------------------------------------------- 1 | # Background 2 | WebViews which use the same user data folder can share browser processes. The `ExclusiveUserDataFolderAccess` property specifies that the WebView environment obtains exclusive access to the user data folder. If the user data folder is already being used by another WebView environment, the WebView creation will fail. Setting exclusive data folder access therefore has the effect of preventing the browser processes from being shared with WebViews associated with other WebView environments. 3 | 4 | # Description 5 | The `ExclusiveUserDataFolderAccess` property specifies whether other WebViews can be created with the same user data folder. Setting exclusive access prevents the WebView browser processes from being shared with those belonging to other environments because sharing occurs only between instances that use the same user data folder and the same exclusive access setting. 6 | Default is FALSE. 7 | 8 | # Examples 9 | ## Win32 C++ 10 | ```cpp 11 | auto options = Microsoft::WRL::Make(); 12 | // Don't allow any other WebView environments to use the same user data folder. 13 | // This prevents other processes from sharing WebView browser process instances with our WebView. 14 | CHECK_FAILURE(options->put_ExclusiveUserDataFolderAccess(TRUE)); 15 | HRESULT hr = CreateCoreWebView2EnvironmentWithOptions( 16 | nullptr, m_userDataFolder.c_str(), options.Get(), 17 | Callback( 18 | this, &AppWindow::OnCreateEnvironmentCompleted).Get()); 19 | ``` 20 | ## WinRT and .NET 21 | ```c# 22 | auto options = new CoreWebView2EnvironmentOptions(); 23 | options.ExclusiveUserDataFolderAccess = true; 24 | auto environment = await CoreWebView2Environment.CreateAsync(BrowserExecutableFolder, UserDataFolder, options); 25 | ``` 26 | 27 | # Remarks 28 | See API details. 29 | 30 | # API Details 31 | ## Win32 C++ 32 | ```cpp 33 | interface ICoreWebView2EnvironmentOptions_2 : IUnknown 34 | { 35 | 36 | /// Whether other processes can create WebView2 from WebView2Environment created with the 37 | /// same user data folder and therefore sharing the same WebView browser process instance. 38 | /// Default is FALSE. 39 | [propget] HRESULT ExclusiveUserDataFolderAccess([out, retval] BOOL* value); 40 | 41 | /// Sets the `ExclusiveUserDataFolderAccess` property. 42 | /// The `ExclusiveUserDataFolderAccess` property specifies that the WebView environment 43 | /// obtains exclusive access to the user data folder. 44 | /// If the user data folder is already being used by another WebView environment with 45 | /// different value for `ExclusiveUserDataFolderAccess` property, the creation of WebView2Controller 46 | /// using the environmen object will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`. 47 | /// When set as TRUE, no other WebView can be created from other process using WebView2Environment 48 | /// objects with the same UserDataFolder. This prevents other processes from creating WebViews 49 | /// which share the same browser process instance, since sharing is performed among 50 | /// WebViews that have the same UserDataFolder. When another process tries to create 51 | /// WebView2Controller from an WebView2Environment object created with the same user data folder, 52 | /// it will fail with `HRESULT_FROM_WIN32(ERROR_INVALID_STATE)`. 53 | /// Exclusive data folder access also opens optimization opportunities, such as more aggressive 54 | /// CPU reduction for suspended WebViews. 55 | [propput] HRESULT ExclusiveUserDataFolderAccess([in] BOOL value); 56 | 57 | } 58 | 59 | ``` 60 | ## WinRT and .NET 61 | ```c# 62 | unsealed runtimeclass CoreWebView2EnvironmentOptions 63 | { 64 | // .. 65 | bool ExclusiveUserDataFolderAccess { get; set; }; 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /specs/ExtendedNewWindowRequested.md: -------------------------------------------------------------------------------- 1 | # Background 2 | WebView2 raises the `NewWindowRequested` event when web content in the WebView2 tries to open a new window. The WebView2 team has been asked to include the name of the new window 3 | being created as a parameter of `NewWindowRequestedEventArgs`. This window name is the name given to the window when it is opened 4 | using `window.open(url, windowName)` or via html such as `...` or ``. 5 | 6 | In this document we describe the updated API. We'd appreciate your feedback. 7 | 8 | # Description 9 | We propose extending the `NewWindowRequestedEventArgs` to provide access to the `Name` property. 10 | The `Name` property will return the name of the new window being created. 11 | 12 | # Examples 13 | ## C++: Get name of window 14 | 15 | ``` cpp 16 | wil::com_ptr m_webviewEventSource; 17 | EventRegistrationToken m_newWindowRequestedToken = {}; 18 | 19 | m_webviewEventSource->add_NewWindowRequested( 20 | Callback( 21 | [this](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) 22 | -> HRESULT 23 | { 24 | wil::com_ptr args2; 25 | 26 | if(SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args2)))) 27 | { 28 | wil::unique_cotaskmem_string name; 29 | CHECK_FAILURE(args2->get_Name(&name)); 30 | 31 | wil::unique_cotaskmem_string uri; 32 | CHECK_FAILURE(args->get_Uri(&uri)); 33 | 34 | // Example usage of how the customer would use the window name to pass 35 | // additional context from their web content to their webview2 event handler. 36 | if (wcscmp(name.get(), L"openInNewBrowser") == 0) 37 | { 38 | ShellExecute(NULL, "open", uri.get(), 39 | NULL, NULL, SW_SHOWNORMAL); 40 | args->put_Handled(true); 41 | } 42 | else 43 | { 44 | HandleNewWindow(args); // App specific handling of opening a new window 45 | } 46 | } 47 | 48 | return S_OK; 49 | }) 50 | .Get(), 51 | &m_newWindowRequestedToken); 52 | ``` 53 | 54 | ## C#: Get name of window 55 | ```c# 56 | webView.CoreWebView2.NewWindowRequested += WebView_NewWindowRequested; 57 | 58 | void WebView_NewWindowRequested(object sender, CoreWebView2NewWindowRequestedEventArgs e) 59 | { 60 | string newWindowName = e.Name; 61 | 62 | // Example usage of how the customer would use the window name to pass 63 | // additional context from their web content to their webview2 event handler. 64 | if (newWindowName == "openInNewBrowser") 65 | { 66 | Process.Start(e.Uri); 67 | e.Handled = true; 68 | } 69 | else 70 | { 71 | HandleNewWindow(e); // App specific handling of opening a new window 72 | } 73 | } 74 | ``` 75 | 76 | # API Details 77 | ## C++ 78 | ``` 79 | /// This is a continuation of the `ICoreWebView2NewWindowRequestedEventArgs` interface. 80 | [uuid(9bcea956-6e1f-43bc-bf02-0a360d73717b), object, pointer_default(unique)] 81 | interface ICoreWebView2NewWindowRequestedEventArgs2 : ICoreWebView2NewWindowRequestedEventArgs { 82 | /// Gets the name of the new window. This window can be created via `window.open(url, windowName)`, 83 | /// where the windowName parameter corresponds to `Name` property. 84 | /// If no windowName is passed to `window.open`, then the `Name` property 85 | /// will be set to an empty string. Additionally, if window is opened through other means, 86 | /// such as `...` or ``, 87 | /// then the `Name` property will be set accordingly. In the case of target=_blank, 88 | /// the `Name` property will be an empty string. 89 | /// Opening a window via ctrl+clicking a link would result in the `Name` property 90 | /// being set to an empty string. 91 | [propget] HRESULT Name([out, retval] LPWSTR* value); 92 | } 93 | ``` 94 | 95 | ## C# 96 | ```c# 97 | namespace Microsoft.Web.WebView2.Core 98 | { 99 | runtimeclass CoreWebView2NewWindowRequestedEventArgs 100 | { 101 | // The following properties already exist in the CoreWebView2NewWindowRequestedEventArgs 102 | // ICoreWebView2NewWindowRequestedEventArgs members 103 | // String Uri { get; }; 104 | // CoreWebView2 NewWindow { get; set; }; 105 | // Boolean Handled { get; set; }; 106 | // Boolean IsUserInitiated { get; }; 107 | // CoreWebView2WindowFeatures WindowFeatures { get; }; 108 | 109 | String Name { get; }; 110 | 111 | // The following already exists in the CoreWebView2NewWindowRequestedEventArgs 112 | // Windows.Foundation.Deferral GetDeferral(); 113 | } 114 | } 115 | ``` 116 | -------------------------------------------------------------------------------- /specs/GetEnvironment.md: -------------------------------------------------------------------------------- 1 | # Background 2 | When the WebView2 team was making design changes to the [WebResourceRequested API](https://github.com/MicrosoftEdge/WebView2Feedback/wiki/WebResourceRequested-API-Review-Spec) for .NET, we realized several caveats. It was not ideal to force all end developers to keep references back to the CoreWebView2Environment from their CoreWebView2 event handlers, and also in the case of WPF, WinForms and WinUI3.0 the UI framework can create the CoreWebView2Environment internally with no easy way for the end developers to obtain a reference to it. Thus providing a reference to the CoreWebView2Environment off of the CoreWebView2 solves both of those problems. 3 | 4 | # Description 5 | Get the `CoreWebView2Environment` used to create the `CoreWebView2` from that `CoreWebView2`'s `Environment` property 6 | 7 | 8 | # Examples 9 | 10 | The following code snippet demonstrates how the environment APIs can be use: 11 | 12 | ## Win32 C++ 13 | 14 | ```cpp 15 | // Turn on or off image blocking by adding or removing a WebResourceRequested handler 16 | // which selectively intercepts requests for images. 17 | void SettingsComponent::SetBlockImages(bool blockImages) 18 | { 19 | if (blockImages != m_blockImages) 20 | { 21 | m_blockImages = blockImages; 22 | if (m_blockImages) 23 | { 24 | m_webView->AddWebResourceRequestedFilter(L"*", COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE); 25 | CHECK_FAILURE(m_webView->add_WebResourceRequested( 26 | Callback( 27 | [this]( 28 | ICoreWebView2* sender, 29 | ICoreWebView2WebResourceRequestedEventArgs* args) { 30 | COREWEBVIEW2_WEB_RESOURCE_CONTEXT resourceContext; 31 | CHECK_FAILURE( 32 | args->get_ResourceContext(&resourceContext)); 33 | // Ensure that the type is image 34 | if (resourceContext != COREWEBVIEW2_WEB_RESOURCE_CONTEXT_IMAGE) 35 | { 36 | return E_INVALIDARG; 37 | } 38 | // Override the response with an empty one to block the image. 39 | // If put_Response is not called, the request will continue as normal. 40 | wil::com_ptr response; 41 | // Environment Usage 42 | wil::com_ptr environment; 43 | CHECK_FAILURE(m_webView->get_Environment(&environment)); 44 | CHECK_FAILURE(environment->CreateWebResourceResponse( 45 | nullptr, 403 /*NoContent*/, L"Blocked", L"", &response)); 46 | CHECK_FAILURE(args->put_Response(response.get())); 47 | return S_OK; 48 | }) 49 | .Get(), 50 | &m_webResourceRequestedTokenForImageBlocking)); 51 | } 52 | else 53 | { 54 | CHECK_FAILURE(m_webView->remove_WebResourceRequested( 55 | m_webResourceRequestedTokenForImageBlocking)); 56 | } 57 | } 58 | } 59 | ``` 60 | 61 | ## .NET and WinRT 62 | 63 | ```c# 64 | private void CoreWebView2_WebResourceRequested(CoreWebView2 sender, CoreWebView2WebResourceRequestedEventArgs e) 65 | { 66 | // Create response object for custom response and set it 67 | var environment = webView2Control.CoreWebView2.Environment; 68 | CoreWebView2WebResourceResponse response = environment.CreateWebResourceResponse(null, 403, "Blocked", ""); 69 | e.Response = response; 70 | 71 | // statusCode will now be accessible and equal to 403 72 | var code = e.Response.StatusCode; 73 | } 74 | ``` 75 | 76 | # API Notes 77 | 78 | See [API Details](#api-details) section below for API reference. 79 | 80 | # API Details 81 | 82 | ## Win32 C++ 83 | 84 | ```IDL 85 | interface ICoreWebView2; 86 | interface ICoreWebView2_2; 87 | 88 | [uuid(76eceacb-0462-4d94-ac83-423a6793775e), object, pointer_default(unique)] 89 | interface ICoreWebView2_2 : ICoreWebView2 { 90 | /// Exposes the CoreWebView2Environment used to create this CoreWebView2. 91 | [propget] HRESULT Environment([out, retval] ICoreWebView2Environment** environment); 92 | } 93 | ``` 94 | 95 | ## .NET and WinRT 96 | 97 | ```c# 98 | namespace Microsoft.Web.WebView2.Core 99 | { 100 | public partial class CoreWebView2 101 | { 102 | // There are other API in this interface that we are not showing 103 | public CoreWebView2Environment Environment { get; }; 104 | } 105 | } 106 | ``` 107 | -------------------------------------------------------------------------------- /specs/HiddenPdfToolbarItems.md: -------------------------------------------------------------------------------- 1 | # Background 2 | When opening a PDF file in Edge, there will be a toolbar at the top. The toolbar provides functionality like print, save and adding annotations. 3 | This PDF viewer is also available in WebView2. And we provide this new API to enable end developers to customize the PDF toolbar. 4 | 5 | 6 | # Description 7 | We add a new `HiddenPdfToolbarItems` property in `CoreWebView2Settings`. This API allows end developers to hide buttons on the PDF toolbar. 8 | Currently, this API can hide the _save button_, _save as button_, and _print button_. 9 | By default, `HiddenPdfToolbarItems` is equal to `None` which means no button will be hidden. 10 | 11 | # Examples 12 | ## C++ 13 | 14 | ```cpp 15 | wil::com_ptr webView; 16 | void SettingsComponent::ToggleHidePdfToolbarButtons() 17 | { 18 | // Get webView's current settings 19 | wil::com_ptr coreWebView2Settings; 20 | CHECK_FAILURE(webView->get_Settings(&coreWebView2Settings)); 21 | 22 | COREWEBVIEW2_PDF_TOOLBAR_ITEMS hiddenPdfToolbarItems; 23 | CHECK_FAILURE(coreWebView2Settings->get_HiddenPdfToolbarItems(&hiddenPdfToolbarItems)); 24 | 25 | if (hiddenPdfToolbarItems == COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE) 26 | { 27 | CHECK_FAILURE(coreWebView2Settings->put_HiddenPdfToolbarItems( 28 | COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PRINT | 29 | COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE)); 30 | } 31 | else 32 | { 33 | CHECK_FAILURE(coreWebView2Settings->put_HiddenPdfToolbarItems( 34 | COREWEBVIEW2_PDF_TOOLBAR_ITEMS::COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE)); 35 | } 36 | } 37 | ``` 38 | 39 | ## C# 40 | ```c# 41 | private WebView2 _webView; 42 | void ToggleHidePdfToolbarButtons(object target, ExecutedRoutedEventArgs e) 43 | { 44 | var coreWebView2Settings = _webView.CoreWebView2.Settings; 45 | if(coreWebView2Settings.HiddenPdfToolbarItems.HasFlag(CoreWebView2PdfToolbarItems.Save | CoreWebView2PdfToolbarItems.Print)) 46 | { 47 | WebViewSettings.HiddenPdfToolbarItems = CoreWebView2PdfToolbarItems.None; 48 | } 49 | else 50 | { 51 | WebViewSettings.HiddenPdfToolbarItems = CoreWebView2PdfToolbarItems.Save; 52 | } 53 | } 54 | ``` 55 | 56 | # API Notes 57 | See [API Details](#api-details) section below for API reference. 58 | 59 | # API Details 60 | ## Win32 C++ 61 | ```c# 62 | /// Specifies the PDF toolbar item types used for the `ICoreWebView2StagingSettings::put_HiddenPdfToolbarItems` method. 63 | [v1_enum] 64 | typedef enum COREWEBVIEW2_PDF_TOOLBAR_ITEMS { 65 | 66 | /// No item 67 | 68 | COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE = 0x0, 69 | 70 | /// The save button 71 | 72 | COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE = 0x0001, 73 | 74 | /// The print button 75 | 76 | COREWEBVIEW2_PDF_TOOLBAR_ITEMS_PRINT = 0x0002, 77 | 78 | /// The save as button 79 | 80 | COREWEBVIEW2_PDF_TOOLBAR_ITEMS_SAVE_AS = 0x0004, 81 | 82 | 83 | } COREWEBVIEW2_PDF_TOOLBAR_ITEMS; 84 | cpp_quote("DEFINE_ENUM_FLAG_OPERATORS(COREWEBVIEW2_PDF_TOOLBAR_ITEMS);") 85 | 86 | [uuid(183e7052-1d03-43a0-ab99-98e043b66b39), object, pointer_default(unique)] 87 | interface ICoreWebView2Settings6 : ICoreWebView2Settings5 { 88 | /// `HiddenPdfToolbarItems` is used to customize the PDF toolbar items. By default, it is COREWEBVIEW2_PDF_TOOLBAR_ITEMS_NONE and so it displays all of the items. 89 | /// Changes to this property apply to all CoreWebView2s in the same environment and using the same profile. 90 | /// Changes to this setting apply only after the next navigation. 91 | /// \snippet SettingsComponent.cpp ToggleHidePdfToolbarItems 92 | 93 | [propget] HRESULT HiddenPdfToolbarItems([out, retval] COREWEBVIEW2_PDF_TOOLBAR_ITEMS* hidden_pdf_toolbar_items); 94 | 95 | [propput] HRESULT HiddenPdfToolbarItems([in] COREWEBVIEW2_PDF_TOOLBAR_ITEMS hidden_pdf_toolbar_items); 96 | } 97 | 98 | ``` 99 | 100 | 101 | ## .NET and WinRT 102 | 103 | ```c# 104 | namespace Microsoft.Web.WebView2.Core 105 | { 106 | // 107 | // Summary: 108 | // Specifies the PDF toolbar item types used for the 109 | [Flags] 110 | public enum CoreWebView2PdfToolbarItems 111 | { 112 | // 113 | // Summary: 114 | // No item. By default the `CoreWebView2Settings.HiddenPdfToolbarItems` equal to this value. 115 | None = 0, 116 | 117 | // 118 | // Summary: 119 | // The save button on PDF toolbar. 120 | Save = 1, 121 | 122 | // 123 | // Summary: 124 | // The print button on PDF toolbar. 125 | Print = 2, 126 | 127 | // 128 | // Summary: 129 | // The save as button on PDF toolbar. 130 | SaveAs = 4 131 | } 132 | } 133 | 134 | namespace Microsoft.Web.WebView2.Core 135 | { 136 | public partial class CoreWebView2Settings 137 | { 138 | // 139 | // Summary: 140 | // Used to customize the PDF toolbar items. 141 | // 142 | // Remarks: 143 | // By default, it equal to `CoreWebView2PdfToolbarItems.None` which means displays all of the items. 144 | public CoreWebView2PdfToolbarItems HiddenPdfToolbarItems { get; set; } 145 | } 146 | } 147 | ``` 148 | -------------------------------------------------------------------------------- /specs/HttpStatusCode.md: -------------------------------------------------------------------------------- 1 | # Background 2 | In the `NavigationCompleted` event, the `WebErrorStatus` property provides information about why a 3 | navigation may have failed. However, this is more geared toward network failures, and doesn't 4 | provide a comprehensive mapping of HTTP status codes. And even if it did provide an enum value 5 | for every common HTTP status code, it is still possible for a server to respond with a custom 6 | status code, which an application might want to recognize and handle. 7 | 8 | The `WebResourceResponseReceived` event does provide information about the response, including 9 | its HTTP status, but it is difficult to correlate a `WebResourceResponse` with a given navigation. 10 | 11 | There are various ways the API could be improved to provide this information, but for now we are 12 | going with the simplest approach, and adding a new property that provides an HTTP status code in 13 | the NavigationCompleted event. 14 | 15 | # Description 16 | The `NavigationCompletedEventArgs` interface will be given a new property, `HttpStatusCode`, which 17 | has the HTTP status code of the navigation if it involved an HTTP request. For instance, this will 18 | usually be 200 if the request was successful, 404 if a page was not found, etc. See 19 | https://developer.mozilla.org/en-US/docs/Web/HTTP/Status for a list of common status codes. 20 | 21 | The `HttpStatusCode` property will be 0 in the following cases: 22 | * The navigation did not involve an HTTP request. For instance, if it was a navigation to a 23 | file:// URL, or if it was a same-document navigation. 24 | * The navigation failed before a response was received. For instance, if the hostname was not 25 | found, or if there was a network error. 26 | 27 | In those cases, you can get more information from the `IsSuccess` and `WebErrorStatus` properties. 28 | 29 | If the navigation receives a successful HTTP response, but the navigated page calls 30 | `window.stop()` before it finishes loading, then `HttpStatusCode` may contain a success code like 31 | 200, but `IsSuccess` will be false and `WebErrorStatus` will be `ConnectionAborted`. 32 | 33 | Since WebView2 handles HTTP continuations and redirects automatically, it is unlikely for 34 | `HttpStatusCode` to ever be in the 1xx or 3xx ranges. 35 | 36 | # Examples 37 | ## Win32 C++ 38 | ```c++ 39 | void NavigationCompletedSample() 40 | { 41 | m_webview->add_NavigationCompleted( 42 | Callback( 43 | [this]( 44 | ICoreWebView2* sender, 45 | ICoreWebView2NavigationCompletedEventArgs* args) 46 | { 47 | wil::com_ptr args2; 48 | args->QueryInterface(IID_PPV_ARGS(&args2)); 49 | if (args2) 50 | { 51 | int status_code; 52 | args2->get_HttpStatusCode(&status_code); 53 | if (status_code == 403) 54 | { 55 | ReportForbidden(); 56 | } 57 | else if (status_code == 404) 58 | { 59 | ReportNotFound(); 60 | } 61 | else if (status_code >= 500 && status_code <= 599) 62 | { 63 | ReportServerError(status_code); 64 | } 65 | } 66 | return S_OK; 67 | }).Get(), nullptr); 68 | } 69 | ``` 70 | 71 | ## .NET C# 72 | ```c# 73 | void NavigationCompletedSample() 74 | { 75 | _webview.NavigationCompleted += (object sender, CoreWebView2NavigationCompletedEventArgs args) => 76 | { 77 | int statusCode = args.HttpStatusCode; 78 | if (status_code == 403) 79 | { 80 | ReportForbidden(); 81 | } 82 | else if (status_code == 404) 83 | { 84 | ReportNotFound(); 85 | } 86 | else if (status_code >= 500 && status_code <= 599) 87 | { 88 | ReportServerError(status_code); 89 | } 90 | }; 91 | } 92 | ``` 93 | 94 | # API Details 95 | ## MIDL 96 | ``` 97 | [uuid(6ECF0A0D-D45D-4279-B17E-6E5DC496BA38), object, pointer_default(unique)] 98 | interface ICoreWebViewNavigationCompletedEventArgs2 : ICoreWebView2NavigationCompletedEventArgs { 99 | /// The HTTP status code of the navigation if it involved an HTTP request. 100 | /// For instance, this will usually be 200 if the request was successful, 404 101 | /// if a page was not found, etc. See 102 | /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status for a list of 103 | /// common status codes. 104 | /// 105 | /// The `HttpStatusCode` property will be 0 in the following cases: 106 | /// * The navigation did not involve an HTTP request. For instance, if it was 107 | /// a navigation to a file:// URL, or if it was a same-document navigation. 108 | /// * The navigation failed before a response was received. For instance, if 109 | /// the hostname was not found, or if there was a network error. 110 | /// 111 | /// In those cases, you can get more information from the `IsSuccess` and 112 | /// `WebErrorStatus` properties. 113 | /// 114 | /// If the navigation receives a successful HTTP response, but the navigated 115 | /// page calls `window.stop()` before it finishes loading, then `HttpStatusCode` 116 | /// may contain a success code like 200, but `IsSuccess` will be FALSE and 117 | /// `WebErrorStatus` will be `COREWEBVIEW2_WEB_ERROR_STATUS_CONNECTION_ABORTED`. 118 | /// 119 | /// Since WebView2 handles HTTP continuations and redirects automatically, it 120 | /// is unlikely for `HttpStatusCode` to ever be in the 1xx or 3xx ranges. 121 | 122 | [propget] HRESULT HttpStatusCode([out, retval] INT* http_status_code); 123 | } 124 | ``` 125 | 126 | ## MIDL3 127 | ```c# (but really MIDL3) 128 | namespace Microsoft.Web.WebView2.Core 129 | { 130 | runtimeclass CoreWebView2NavigationCompletedEventArgs 131 | { 132 | // ... 133 | 134 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2NavigationCompletedEventArgs2")] 135 | { 136 | int HttpStatusCode { get; }; 137 | } 138 | } 139 | } 140 | ``` 141 | -------------------------------------------------------------------------------- /specs/IsPinchZoomEnabled.md: -------------------------------------------------------------------------------- 1 | # Background 2 | 3 | There are two types of zoom in Chromium: Browser Zoom and Pinch-Zoom: 4 | - Browser zoom, referred to as “Page Zoom” or “Zoom” more generally, is what we get by using Ctrl + +(plus) or – (minus) or Ctrl + Mousewheel. This changes the size of a CSS pixel relative to a device independent pixel and so it will cause page layout to change. End developers can programmatically change browser Zoom properties including [IsZoomControlEnabled](https://learn.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2settings?view=webview2-1.0.774.44#get_iszoomcontrolenabled) and [ZoomFactor](https://learn.microsoft.com/microsoft-edge/webview2/reference/win32/icorewebview2controller?view=webview2-1.0.774.44#get_zoomfactor). Setting ZoomFactor property causes the layout to change and enables scroll bar which lets users interact with the zoomed in content using mouse. 5 | - Pinch-zoom, referred to as “Page Scale” zoom, is performed as a post-rendering step, it changes the page scale factor property and scales the surface the web page is rendered onto when user perfoms a pinch zooming action. It does not change the layout but rather changes the viewport and clips the web content, the content outside of the viewport isn't visible onscreen and users can't reach this content using mouse. 6 | 7 | Currently, the first type of zoom control is supported in WebView2 and modifying it has no effect on page scale zoom. 8 | 9 | In response to customer requests to be able to change the current functionality of page scale zoom in WebView2, the WebView2 team has introduced this Pinch Zoom API which allows end developers to disable or enable page scale zoom control via a setting. 10 | 11 | In this document we describe the new setting. We'd appreciate your feedback. 12 | 13 | 14 | # Description 15 | The default value for `IsPinchZoomEnabled` is `true`. 16 | When this setting is set to `false`, it disables the ability of the end users to use pinching motions on touch input enabled devices to scale the web content in the WebView2 and users cannot pinch zoom. 17 | Disabling/Enabling `IsPinchZoomEnabled` does not take effect until the next navigation, it only affects the end user's ability to use pinch motions and does not change the page scale factor. 18 | 19 | 20 | # Examples 21 | ```cpp 22 | wil::com_ptr webView; 23 | void SettingsComponent::TogglePinchZooomEnabled() 24 | { 25 | // Get webView's current settings 26 | wil::com_ptr coreWebView2Settings; 27 | CHECK_FAILURE(webView->get_Settings(&coreWebView2Settings)); 28 | wil::com_ptr coreWebView2Settings4; 29 | coreWebView2Settings4 = coreWebView2Settings.try_query(); 30 | if(coreWebView2Settings4) 31 | { 32 | BOOL enabled; 33 | CHECK_FAILURE(coreWebView2Settings4->get_IsPinchZoomEnabled(&enabled)); 34 | CHECK_FAILURE(coreWebView2Settings4->put_IsPinchZoomEnabled(enabled ? FALSE : TRUE)); 35 | } 36 | } 37 | ``` 38 | 39 | ```c# 40 | private WebView2 _webView; 41 | void TogglePinchZoomEnabled() 42 | { 43 | var coreWebView2Settings = _webView.CoreWebView2.Settings; 44 | coreWebView2Settings.IsPinchZoomEnabled = !coreWebView2Settings.IsPinchZoomEnabled; 45 | } 46 | ``` 47 | 48 | # Remarks 49 | When `IsPinchZoomEnabled` is set to `false`, pinch zooming is disabled in WebView. This however doesn't modify the underlying page scale factor of page scale zoom. 50 | 51 | # API Notes 52 | 53 | See [API Details](#api-details) section below for API reference. 54 | 55 | # API Details 56 | 57 | ## Win32 C++ 58 | ```cpp 59 | [uuid(B625A89E-368F-43F5-BCBA-39AA6234CCF8), object, pointer_default(unique)] 60 | interface ICoreWebView2Settings4 : ICoreWebView2Settings3 { 61 | /// The IsPinchZoomEnabled property enables or disables the ability of 62 | /// the end user to use a pinching motion on touch input enabled devices 63 | /// to scale the web content in the WebView2. It defaults to TRUE. 64 | /// When set to FALSE, the end user cannot pinch zoom. 65 | /// This API only affects the Page Scale zoom and has no effect on the 66 | /// existing browser zoom properties (IsZoomControlEnabled and ZoomFactor) 67 | /// or other end user mechanisms for zooming. 68 | /// 69 | /// \snippet SettingsComponent.cpp TogglePinchZooomEnabled 70 | [propget] HRESULT IsPinchZoomEnabled([out, retval] BOOL* enabled); 71 | /// Set the IsPinchZoomEnabled property 72 | [propput] HRESULT IsPinchZoomEnabled([in] BOOL enabled); 73 | } 74 | ``` 75 | 76 | ## .NET and WinRT 77 | 78 | ```c# 79 | namespace Microsoft.Web.WebView2.Core 80 | { 81 | public partial class CoreWebView2Settings 82 | { 83 | /// 84 | public bool IsPinchZoomEnabled { get; set; }; 85 | 86 | } 87 | } 88 | 89 | ``` 90 | -------------------------------------------------------------------------------- /specs/IsSmartScreenRequired.md: -------------------------------------------------------------------------------- 1 | # Background 2 | 3 | [Edge SmartScreen](https://support.microsoft.com/en-us/microsoft-edge/how-can-smartscreen-help-protect-me-in-microsoft-edge-1c9a874a-6826-be5e-45b1-67fa445a74c8) helps end users identify reported phishing and malware websites, and also helps end users make informed decisions about downloads. 4 | 5 | Currently, developers can use `options->put_AdditionalBrowserArguments(L"--disable-features=msSmartScreenProtection")` to disable SmartScreen in the WebView2 application. It is a startup parameter of the browser process and applies to all WebView2 instances using the same user data folder. It must be determined when the WebView2Environment is created, and it cannot be modified at runtime. 6 | 7 | To support more flexibility we introduce a new API. 8 | 9 | We have CoreWebView2Settings.IsReputationCheckingRequired. Each WebView2 declares if it requires SmartScreen. Some WebView2s may be used to display app content and don't require SmartScreen and others may be rendering arbitrary web content and do need SmartScreen. Having SmartScreen on unnecessarily for app content is a detriment to performance but otherwise not a problem. Having SmartScreen off for arbitrary web content is an issue. We have to turn SmartScreen on or off for all WebView2 using the same user data folder so if any WebView2 requires SmartScreen then we turn it on for all of them. If WebView2 settings change or WebView2s are closed and then all WebView2s using the same user data folder don't require SmartScreen, then we can turn SmartScreen off. 10 | 11 | It is much easier to indicate if individual WebView2s require SmartScreen than to have an end developer explicitly manage if SmartScreen should be enabled as a whole, especially when its different sets of WebView2s in different processes (like Excel's set of WebView2s and Word's set of WebView2s) all sharing the same user data folder. 12 | In this document we describe the new setting. 13 | 14 | 15 | # Description 16 | You can use CoreWebView2Settings.IsReputationCheckingRequired to control SmartScreen. SmartScreen is enabled or disabled per browser process, so all WebView2 applications sharing the same user data folder path also share SmartScreen being enabled or disabled. 17 | If CoreWebView2Setting.IsReputationCheckingRequired is true for any CoreWebView2 using the same user data folder, then SmartScreen is enabled. If CoreWebView2Setting.IsReputationCheckingRequired is false for all CoreWebView2 using the same user data folder, then SmartScreen is disabled. 18 | The default value for `IsReputationCheckingRequired` is true. When creating a new CoreWebVIew2, if it is not set CoreWebView2Settings.IsReputationCheckingRequired, the SmartScreen state of all CoreWebView2s using the same user data folder will be reset to true when the new CoreWebView2 is navigated or downloaded. 19 | 20 | Changes to `IsReputationCheckingRequired` take effect on the next navigation or download. 21 | 22 | If the option `--disable-features=msSmartScreenProtection` is specified when CoreWebView2Environment is created, then SmartScreen cannot be set through CoreWebView2Settings.IsReputationCheckingRequired. In this scenario, SmartScreen is always turned off. 23 | 24 | 25 | # Examples 26 | ```cpp 27 | // member variable 28 | wil::com_ptr m_webViewSettings; 29 | 30 | // isLocalContent is TRUE if the page is navigated to content that is completely 31 | // app-provided, with no user-provided content or web-served content. 32 | // Note that we must update the property before navigating to the content. 33 | void SettingsComponent::UpdateSmartScreenRequirementBeforeNavigating(bool isLocalContent) 34 | { 35 | wil::com_ptr coreWebView2Settings11; 36 | coreWebView2Settings11 = 37 | m_webViewSettings.try_query(); 38 | if(coreWebView2Settings11) 39 | { 40 | CHECK_FAILURE(coreWebView2Settings11->put_IsReputationCheckingRequired(!isLocalContent)); 41 | } 42 | } 43 | ``` 44 | 45 | ```c# 46 | void UpdateSmartScreenRequirementBeforeNavigating(bool isLocalContent) 47 | { 48 | var settings = webView2Control.CoreWebView2.Settings; 49 | settings.IsReputationCheckingRequired = !isLocalContent; 50 | } 51 | ``` 52 | 53 | # Remarks 54 | 55 | # API Notes 56 | 57 | See [API Details](#api-details) section below for API reference. 58 | 59 | # API Details 60 | 61 | ## Win32 C++ 62 | ```cpp 63 | [uuid(d667d3a7-c1b7-479f-8833-db7547df6687), object, pointer_default(unique)] 64 | interface ICoreWebView2Settings11 : ICoreWebView2Settings10 { 65 | /// SmartScreen helps webviews identify reported phishing and malware websites and 66 | /// also helps users make informed decisions about downloads. 67 | /// `IsReputationCheckingRequired` is used to control whether SmartScreen enabled or not. 68 | /// SmartScreen is enabled or disabled for all CoreWebView2s using the same user data folder. 69 | /// If CoreWebView2Setting.IsReputationCheckingRequired is true for any CoreWebView2 using the same 70 | /// user data folder, then SmartScreen is enabled. If CoreWebView2Setting.IsReputationCheckingRequired 71 | /// is false for all CoreWebView2 using the same user data folder, then SmartScreen is disabled. 72 | /// When it is changed, the change will be applied to all WebViews using the 73 | /// same user data folder on the next navigation or download. 74 | /// The default value for `IsReputationCheckingRequired` is true. When a new CoreWebview2 75 | /// is created, the SmartScreens of all CoreWebviews using the same user data folder are reset to true. 76 | [propget] HRESULT IsReputationCheckingRequired([out, retval] BOOL* value); 77 | 78 | /// Sets whether this webview2 instance needs SmartScreen protection for its content. 79 | /// Set the `IsReputationCheckingRequired` property. 80 | [propput] HRESULT IsReputationCheckingRequired([in] BOOL value); 81 | } 82 | ``` 83 | 84 | ```c# (really MIDL3) 85 | namespace Microsoft.Web.WebView2.Core 86 | { 87 | runtimeclass CoreWebView2Settings 88 | { 89 | // ... 90 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Settings11")] 91 | { 92 | Boolean IsReputationCheckingRequired { get; set; }; 93 | } 94 | } 95 | } 96 | ``` 97 | 98 | # Appendix 99 | 100 | We initially considered an API like `CoreWebView2Environment.IsReputationCheckingRequired` that would directly change the value for all the processes. The problem is this is not easy to do for apps like Office who have multiple apps connected to the same browser process. In their case each app has IsReputationCheckingRequiredxf and its hard for the browser process to know which change to the property should win. 101 | -------------------------------------------------------------------------------- /specs/LoaderDllFolderPath.md: -------------------------------------------------------------------------------- 1 | # Background 2 | The WebView2 loader code is what knows where to find and start or connect to already running WebView2 runtimes. This can either be statically linked for C based projects, or is also available as a standalone DLL. For .NET projects they must use the DLL since the loader code is native and we don't have a way to merge the native code into a managed module. Before this change the .NET WebView2 API module would look for the WebView2Loader.dll in the its same folder. But some .NET projects have requirements about where they can place DLLs and so this property is introduced to allow end developers to place the WebView2Loader.dll in any folder and specify the path of 'WebView2Loader.dll' explicitly. 3 | So we add an API to enable them to specify the path, so that they can use 'WebView2Loader.dll' from any path. 4 | 5 | # Description 6 | We add new static `SetLoaderDllFolderPath` function in `CoreWebView2Environment` class. 7 | The function allow the end developers to specify the folder's path containing `WebView2Loader.dll`. 8 | 9 | # Examples 10 | ## C# 11 | ``` c# 12 | // Use default path 13 | Task CreateEnvironmentAsync() 14 | { 15 | // To use default path, just do not call SetLoaderDllFolderPath function or give a empty string:CoreWebView2Environment.SetLoaderDllFolderPath("") will use the default path; 16 | // The default search path logic is the same as loadlibrary 17 | return CoreWebView2Environment.CreateAsync(); 18 | } 19 | 20 | // Specify a absolute path 21 | Task CreateEnvironmentAsync() 22 | { 23 | // Specify a absolute path 'D:\\folder', and there should be a 'WebView2Loader.dll' file in the folder. 24 | CoreWebView2Environment.SetLoaderDllFolderPath("D:\\folder"); 25 | return CoreWebView2Environment.CreateAsync(); 26 | } 27 | 28 | // Specify a relative path 29 | Task CreateEnvironmentAsync() 30 | { 31 | // Specify a relative path 'sub/sub'. The absolute folder path is '%Microsoft.Web.WebView2.Core.dll%\sub\sub', and there should be a 'WebView2Loader.dll' file in the folder. 32 | CoreWebView2Environment.SetLoaderDllFolderPath("sub\\sub"); 33 | return CoreWebView2Environment.CreateAsync(); 34 | } 35 | ``` 36 | 37 | # Remarks 38 | This function allows you to set the path of the folder containing the `WebView2Loader.dll`. This should be the path of a folder containing `WebView2Loader.dll` and not a path to the `WebView2Loader.dll` file itself. 39 | Note that the WebView2 SDK contains multiple `WebView2Loader.dll` files for different CPU architectures. When specifying folder path, you must specify one containing a `WebView2Loader.dll` module with a CPU architecture matching the current process CPU architecture. 40 | This function is used to load the `WebView2Loader.dll` module during calls to any other static methods on `CoreWebView2Environment`. So, the path should be specified before any other API is called in `CoreWebView2Environment` class. Once `WebView2Loader.dll` is successfully loaded this function will throw an InvalidOperationException exception. 41 | The path can be relative or absolute. Relative paths are relative to the path of the `Microsoft.Web.WebView2.Core.dll` module. 42 | If the `WebView2Loader.dll` file does not exist in that path or LoadLibrary cannot load the file, or LoadLibrary fails for any other reason, an exception corresponding to the LoadLibrary failure is thrown when any other API is called in `CoreWebView2Environment` class. For instance, if the file cannot be found a `DllNotFoundException` exception will be thrown. 43 | 44 | # API Notes 45 | See [API Details](#api-details) section below for API reference. 46 | 47 | # API Details 48 | ## .NET and WinRT 49 | ```c# 50 | namespace Microsoft.Web.WebView2.Core 51 | { 52 | /// 53 | /// Set the path of the folder containing the `WebView2Loader.dll`. 54 | /// 55 | /// The path of the folder containing the `WebView2Loader.dll`. 56 | /// 57 | /// Thrown when `WebView2Loader.dll` has been successfully loaded. 58 | /// 59 | /// 60 | /// This function allows you to set the path of the folder containing the `WebView2Loader.dll`. This should be the path of a folder containing `WebView2Loader.dll` and not a path to the `WebView2Loader.dll` file itself. 61 | /// Note that the WebView2 SDK contains multiple `WebView2Loader.dll` files for different CPU architectures. When specifying folder path, you must specify one containing a `WebView2Loader.dll` module with a CPU architecture matching the current process CPU architecture. 62 | /// This function is used to load the `WebView2Loader.dll` module during calls to any other static methods on `CoreWebView2Environment`. So, the path should be specified before any other API is called in `CoreWebView2Environment` class. Once `WebView2Loader.dll` is successfully loaded this function will throw an InvalidOperationException exception. 63 | /// The path can be relative or absolute. Relative paths are relative to the path of the `Microsoft.Web.WebView2.Core.dll` module. 64 | /// If the `WebView2Loader.dll` file does not exist in that path or LoadLibrary cannot load the file, or LoadLibrary fails for any other reason, an exception corresponding to the LoadLibrary failure is thrown when any other API is called in `CoreWebView2Environment` class. For instance, if the file cannot be found a `DllNotFoundException` exception will be thrown. 65 | /// 66 | public static void SetLoaderDllFolderPath(string folderPath); 67 | } 68 | ``` 69 | -------------------------------------------------------------------------------- /specs/MemoryUsageTargetLevel.md: -------------------------------------------------------------------------------- 1 | # Background 2 | Some WebView2 apps want to continue to run scripts while inactive and therefore cannot make usage of `TrySuspend` and `Resume` APIs to reduce resource consumption. 3 | We are introducing WebView2 API to reduce memory usage only for this type of inactive WebViews. 4 | 5 | # Description 6 | You may set the `MemoryUsageTargetLevel` property to have the WebView2 consume less memory and going back to normal usage. This is useful when your Win32 app becomes invisible, 7 | but still wants to have script running or monitoring requests from network. 8 | 9 | # Examples 10 | ## .NET, WinRT 11 | ```c# 12 | async protected void OnBecomingInactive() 13 | { 14 | // CanSuspendWebView() uses app specific logic to check whether the current web contents in the WebView2 can be suspended. 15 | if (CanSuspendWebView()) 16 | { 17 | await webView.CoreWebView2.TrySuspendAsync(); 18 | } 19 | else 20 | { 21 | webView.CoreWebView2.MemoryUsageTargetLevel = CoreWebView2MemoryUsageTargetLevel.Low; 22 | } 23 | } 24 | async protected void OnBecomingActive() 25 | { 26 | if (webView.CoreWebView2.IsSuspended) 27 | { 28 | webView.CoreWebView2.Resume(); 29 | } 30 | else if (webView.CoreWebView2.MemoryUsageTargetLevel == CoreWebView2MemoryUsageTargetLevel.Low) 31 | { 32 | webView.CoreWebView2.MemoryUsageTargetLevel = CoreWebView2MemoryUsageTargetLevel.Normal; 33 | } 34 | } 35 | ``` 36 | ## Win32 C++ 37 | ```cpp 38 | bool ViewComponent::HandleWindowMessage( 39 | HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT* result) 40 | { 41 | if (message == WM_SYSCOMMAND) 42 | { 43 | if (wParam == SC_MINIMIZE) 44 | { 45 | OnBecomingInactive(); 46 | } 47 | else if (wParam == SC_RESTORE) 48 | { 49 | OnBecomingActive(); 50 | } 51 | } 52 | } 53 | 54 | void ViewComponent::OnBecomingInactive() 55 | { 56 | // CanSuspendWebView() uses app specific logic to check whether the current web contents in the WebView2 can be suspended. 57 | if (CanSuspendWebView()) 58 | { 59 | CHECK_FAILURE(m_webView->TrySuspend(nullptr)); 60 | } 61 | else 62 | { 63 | CHECK_FAILURE(m_webView->put_MemoryUsageTargetLevel(COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_LOW); 64 | } 65 | } 66 | 67 | void ViewComponent::OnBecomingActive() 68 | { 69 | BOOL isSuspended = FALSE; 70 | CHECK_FAILURE(m_webview->get_IsSuspended(&isSuspended)); 71 | if (isSuspended) 72 | { 73 | CHECK_FAILURE(m_webView->Resume()); 74 | } 75 | else 76 | { 77 | COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL memoryUsageTargetLevel = COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_LOW; 78 | CHECK_FAILURE(m_webview->get_MemoryUsageTargetLevel(&memoryUsageTargetLevel)); 79 | if (memoryUsageTargetLevel == COREWEBVIEW2_MEMORY_USAGE_LEVEL_LOW) 80 | { 81 | CHECK_FAILURE(m_webView->put_MemoryUsageTargetLevel(COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_NORMAL)); 82 | } 83 | } 84 | } 85 | ``` 86 | 87 | # Remarks 88 | See [API Details](#api-details) section below for more details. 89 | 90 | # API Notes 91 | See [API Details](#api-details) section below for API reference. 92 | 93 | # API Details 94 | 95 | ## Win32 C++ 96 | ```IDL 97 | /// Specifies memory usage target level of WebView. 98 | [v1_enum] 99 | typedef enum COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL 100 | { 101 | /// Specifies normal memory usage target level. 102 | COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_NORMAL, 103 | 104 | /// Specifies low memory usage target level. 105 | /// Used for inactivate WebView for reduced memory consumption. 106 | COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_LOW, 107 | 108 | } COREWEBVIEW2_MEMORY_USAGE_LEVEL; 109 | 110 | interface ICoreWebView2_6 : ICoreWebView2 111 | { 112 | 113 | /// `MemoryUsageTargetLevel` indicates desired memory comsumption level of WebView. 114 | [propget] HRESULT MemoryUsageTargetLevel( 115 | [out, retval] COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL* level); 116 | 117 | /// An app may set `MemoryUsageTargetLevel` to indicate desired memory 118 | /// comsumption level of WebView. Scripts will not be impacted and continue to run. 119 | /// This is useful for inactive apps that still want to run scripts and/or keep 120 | /// network connections alive and therefore could not call `TrySuspend` and `Resume` 121 | /// to reduce memory consumption. 122 | /// These apps can set memory usage target level to `COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_LOW` when 123 | /// the app becomes inactive, and set back to `COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_NORMAL` when 124 | /// the app becomes active. 125 | /// It is not neccesary to set CoreWebView2Controller's IsVisible property to false when calling the API. 126 | /// It is a best effort operation to change memory usage level, and the API will return before the operation completes. 127 | /// Setting the level to `COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_LOW` could potentially cause 128 | /// memory for some WebView browser processes to be swapped out to disk when needed. 129 | /// It is a best effort to reduce memory usage as much as possible. If script runs after we swapped 130 | /// related memory out, we will swap the memory in to ensure script can still run. But performance might 131 | /// be impacted. 132 | /// Therefore, it is important for the app to set the level back to `COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL_NORMAL` 133 | /// when the app becomes active again to have a smooth user experience. 134 | /// Setting memory usage target level back to normal will not happen automatically. 135 | /// An app should choose to use either the combination of `TrySuspend` and `Resume` or the combination 136 | /// of setting `MemoryUsageTargetLevel` to low and normal. It is not advisable to mix them. 137 | /// Trying to set `MemoryUsageTargetLevel` while suspended will be ignored. 138 | /// The TrySuspend and Resume methods will change the MemoryUsageTargetLevel. 139 | /// TrySuspend will automatically set MemoryUsageTargetLevel to low while Resume on suspended WebView 140 | /// will automatically set MemoryUsageTargetLevel to normal. 141 | /// Calling `Resume` when the WebView is not suspended would not change MemoryUsageTargetLevel. 142 | [propput] HRESULT MemoryUsageTargetLevel([in] COREWEBVIEW2_MEMORY_USAGE_TARGET_LEVEL level); 143 | } 144 | 145 | ``` 146 | 147 | ## .NET WinRT 148 | ```c# 149 | namespace Microsoft.Web.WebView2.Core 150 | { 151 | public enum CoreWebView2MemoryUsageTargetLevel 152 | { 153 | /// 154 | Normal = 0, 155 | /// 156 | Low = 1, 157 | } 158 | public partial class CoreWebView2 159 | { 160 | // There are other API in this interface that we are not showing 161 | public CoreWebView2MemoryUsageTargetLevel MemoryUsageTargetLevel { get; set; }; 162 | } 163 | } 164 | ``` 165 | -------------------------------------------------------------------------------- /specs/NavigateWithWebResourceRequest.md: -------------------------------------------------------------------------------- 1 | 2 | # Background 3 | Consumers of the old WebBrowser control that relied on the [Navigate](https://learn.microsoft.com/previous-versions/aa752133(v=vs.85)) API that allowed them to specify HTTP POST data and extra headers as part of navigation, [requested](https://github.com/MicrosoftEdge/WebViewFeedback/issues/69) same ability in WebView2. 4 | 5 | # Description 6 | We propose adding NavigateWithWebResourceRequest to CoreWebView2 as the API that allows a WebView2 to navigate with a specified [CoreWebView2WebResourceRequest](https://learn.microsoft.com/microsoft-edge/webview2/reference/dotnet/0-9-628/microsoft-web-webview2-core-corewebview2). This allows the developer to specify extra headers and POST data as part of their request for navigation. 7 | We also propose adding a CreateWebResourceRequest API to [CoreWebView2Environment](https://learn.microsoft.com/microsoft-edge/webview2/reference/dotnet/0-9-515/microsoft-web-webview2-core-corewebview2environment) so that developers can create the WebResourceRequest object they'd like to use with NavigateWithWebResourceRequest. 8 | 9 | # Examples 10 | 11 | ```cpp 12 | // Need to convert post data to UTF-8 as required by the application/x-www-form-urlencoded Content-Type 13 | std::wstring postData = std::wstring(L"input=Hello"); 14 | int sizeNeededForMultiByte = WideCharToMultiByte( 15 | CP_UTF8, 0, postData.c_str(), postData.size(), nullptr, 16 | 0, nullptr, nullptr); 17 | 18 | std::unique_ptr postDataBytes = std::make_unique(sizeNeededForMultiByte); 19 | WideCharToMultiByte( 20 | CP_UTF8, 0, postData.c_str(), postData.size(), postDataBytes.get(), 21 | sizeNeededForMultiByte, nullptr, nullptr); 22 | 23 | wil::com_ptr webResourceRequest; 24 | wil::com_ptr postDataStream = SHCreateMemStream( 25 | reinterpret_cast(postDataBytes.get()), sizeNeededForMultiByte); 26 | 27 | // This acts as a HTML form submit to https://www.w3schools.com/action_page.php 28 | CHECK_FAILURE(webviewEnvironment->CreateWebResourceRequest( 29 | L"https://www.w3schools.com/action_page.php", L"POST", postDataStream.get(), 30 | L"Content-Type: application/x-www-form-urlencoded", &webResourceRequest)); 31 | CHECK_FAILURE(webview->NavigateWithWebResourceRequest(webResourceRequest.get())); 32 | ``` 33 | 34 | ```csharp 35 | UTF8Encoding utfEncoding = new UTF8Encoding(); 36 | byte[] postData = utfEncoding.GetBytes("input=Hello"); 37 | 38 | MemoryStream postDataStream = new MemoryStream(postData.Length); 39 | postDataStream.Write(postData, 0, postData.Length); 40 | postDataStream.Seek(0, SeekOrigin.Begin); 41 | CoreWebView2WebResourceRequest webResourceRequest = 42 | environment.CreateWebResourceRequest( 43 | "https://www.w3schools.com/action_page.php", 44 | "POST", 45 | postDataStream, 46 | "Content-Type: application/x-www-form-urlencoded"); 47 | webView.CoreWebView2.NavigateWithWebResourceRequest(webResourceRequest); 48 | 49 | ``` 50 | 51 | # Remarks 52 | 53 | 54 | 58 | 59 | # API Notes 60 | 65 | 66 | 68 | 69 | # API Details 70 | 71 | ```idl 72 | [uuid(7fbad153-fb94-452e-acab-3cbb9ab341ec), object, pointer_default(unique)] 73 | interface ICoreWebView2_2 : ICoreWebView2 { 74 | .... 75 | /// Navigate using a constructed WebResourceRequest object. This lets you 76 | /// provide post data or additional request headers during navigation. 77 | /// The headers in the WebResourceRequest override headers 78 | /// added by WebView2 runtime except for Cookie headers. 79 | /// Method can only be either "GET" or "POST". Provided post data will only 80 | /// be sent only if the method is "POST" and the uri scheme is HTTP(S). 81 | /// \snippet ScenarioNavigateWithWebResourceRequest.cpp NavigateWithWebResourceRequest 82 | HRESULT NavigateWithWebResourceRequest([in] ICoreWebView2WebResourceRequest* request); 83 | } 84 | 85 | [uuid(1c11735a-d57d-4614-a9e1-8b48d81da38c), object, pointer_default(unique)] 86 | interface ICoreWebView2Environment_2 : ICoreWebView2Environment { 87 | /// Create a new web resource request object. 88 | /// URI parameter must be absolute URI. 89 | /// The headers string is the raw request header string delimited by CRLF 90 | /// (optional in last header). 91 | /// It's also possible to create this object with null headers string 92 | /// and then use the ICoreWebView2HttpRequestHeaders to construct the headers 93 | /// line by line. 94 | /// For information on other parameters see ICoreWebView2WebResourceRequest. 95 | /// 96 | /// \snippet ScenarioNavigateWithWebResourceRequest.cpp NavigateWithWebResourceRequest 97 | HRESULT CreateWebResourceRequest([in] LPCWSTR uri, 98 | [in] LPCWSTR method, 99 | [in] IStream* postData, 100 | [in] LPCWSTR headers, 101 | [out, retval] ICoreWebView2WebResourceRequest** request); 102 | } 103 | ``` 104 | 105 | ```c# 106 | namespace Microsoft.Web.WebView2.Core 107 | { 108 | runtimeclass CoreWebView2Environment 109 | { 110 | ... 111 | /// Create a new web resource request object. 112 | /// URI parameter must be absolute URI. 113 | /// The headers string is the raw request header string delimited by CRLF 114 | /// (optional in last header). 115 | /// It's also possible to create this object with null headers string 116 | /// and then use the CoreWebView2HttpRequestHeaders to construct the headers 117 | /// line by line. 118 | /// For information on other parameters see ICoreWebView2WebResourceRequest. 119 | /// 120 | public CoreWebView2WebResourceRequest CreateWebResourceRequest(String uri, 121 | String method, 122 | Stream postData, 123 | String headers); 124 | } 125 | runtimeclass CoreWebView2 126 | { 127 | ... 128 | /// Navigate using a constructed WebResourceRequest object. This let's you 129 | /// provide post data or additional request headers during navigation. 130 | /// The headers in the WebResourceRequest override headers 131 | /// added by WebView2 runtime except for Cookie headers. 132 | /// Method can only be either "GET" or "POST". Provided post data will only 133 | /// be sent only if the method is "POST" and the uri scheme is HTTP(S). 134 | public void NavigateWithWebResourceRequest(CoreWebView2WebResourceRequest request); 135 | } 136 | } 137 | ``` 138 | 139 | # Appendix 140 | 143 | -------------------------------------------------------------------------------- /specs/NewWindowSourceFrameInfo.md: -------------------------------------------------------------------------------- 1 | Source Frame Info for New Window Requested 2 | === 3 | 4 | # Background 5 | Currently there is no way to determine the source frame of a new window request. This information 6 | can be useful when deciding how to open the content. For example, you may want to open requests 7 | that originate in a 3rd party frame in the default browser instead of in a new WebView. The 8 | WebView2 team is extending `NewWindowRequestedEventArgs` with an `OriginalSourceFrameInfo` property 9 | to make this easier. Here we described the updated API. 10 | 11 | # Examples 12 | ## OriginalSourceFrameInfo on NewWindowRequestedEventArgs 13 | ```c# 14 | // Register a handler for the NewWindowRequested event. 15 | // This handler will check the source frame info to determine how to open the 16 | // request. Depending on the source frame URI, it will provide a new app window 17 | // or open using the default browser. 18 | webView.CoreWebView2.NewWindowRequested += delegate ( 19 | object webView, CoreWebView2NewWindowRequestedEventArgs args) 20 | { 21 | // The host can decide how to open based on source frame info, 22 | // such as URI. For example, if the source is a 3rd party frame, open using 23 | // the default browser. 24 | bool useDefaultBrowser = IsThirdPartySource( 25 | args.OriginalSourceFrameInfo.Source); 26 | if (useDefaultBrowser) 27 | { 28 | ProcessStartInfo startInfo = new ProcessStartInfo 29 | { 30 | FileName = args.OriginalSourceFrameInfo.Source, 31 | // Open the URI in the default browser. 32 | UseShellExecute = true 33 | }; 34 | Process.Start(startInfo); 35 | args.Handled = true; 36 | } 37 | else 38 | { 39 | CoreWebView2Deferral deferral = args.GetDeferral(); 40 | MainWindow main_window = new MainWindow( 41 | webView.CreationProperties, args.Uri); 42 | main_window.OnWebViewFirstInitialized = () => 43 | { 44 | using (deferral) 45 | { 46 | args.Handled = true; 47 | args.NewWindow = main_window.webView.CoreWebView2; 48 | } 49 | }; 50 | main_window.Show(); 51 | } 52 | }; 53 | ``` 54 | ```cpp 55 | // Register a handler for the NewWindowRequested event. 56 | // This handler will check the source frame info to determine how to open the 57 | // request. Depending on the source frame URI, it will provide a new app window 58 | // or open using the default browser. 59 | CHECK_FAILURE(m_webView->add_NewWindowRequested( 60 | Callback( 61 | [this](ICoreWebView2* sender, ICoreWebView2NewWindowRequestedEventArgs* args) 62 | { 63 | bool useDefaultBrowser = false; 64 | Microsoft::WRL::ComPtr args3; 65 | if (SUCCEEDED(args->QueryInterface(IID_PPV_ARGS(&args3)))) 66 | { 67 | Microsoft::WRL::ComPtr frame_info; 68 | if (SUCCEEDED(args3->get_OriginalSourceFrameInfo(&frame_info)) 69 | && frame_info) 70 | { 71 | // The host can decide how to open based on source frame info, 72 | // such as URI. For example, if the source is a 3rd party frame, 73 | // open using the default browser. 74 | wil::unique_cotaskmem_string source; 75 | CHECK_FAILURE(frame_info->get_Source(&source)); 76 | useDefaultBrowser = IsThirdPartySource(source.get()); 77 | } 78 | } 79 | if (useDefaultBrowser) 80 | { 81 | // Open the URI in the default browser. 82 | ShellExecute( 83 | nullptr, L"open", source.get(), nullptr, nullptr, SW_SHOWNORMAL); 84 | CHECK_FAILURE(args->put_Handled(TRUE)); 85 | } 86 | else 87 | { 88 | Microsoft::WRL::ComPtr deferral; 89 | CHECK_FAILURE(args->GetDeferral(&deferral)); 90 | AppWindow* newAppWindow = new AppWindow( 91 | m_creationModeId, GetWebViewOption(), L"none", m_userDataFolder, 92 | false, nullptr, true, windowRect, !!shouldHaveToolbar); 93 | newAppWindow->m_onWebViewFirstInitialized = 94 | [args, deferral, newAppWindow]() 95 | { 96 | CHECK_FAILURE(args->put_NewWindow(newAppWindow->m_webView.get())); 97 | CHECK_FAILURE(args->put_Handled(TRUE)); 98 | CHECK_FAILURE(deferral->Complete()); 99 | }; 100 | } 101 | return S_OK; 102 | }) 103 | .Get(), 104 | nullptr)); 105 | ``` 106 | 107 | # API Details 108 | 109 | ``` 110 | /// This is a continuation of the `ICoreWebView2NewWindowRequestedEventArgs` interface. 111 | [uuid(92f08d94-70bd-4d2b-8332-18bd7d3b2b7c), object, pointer_default(unique)] 112 | interface ICoreWebView2NewWindowRequestedEventArgs3 : 113 | ICoreWebView2NewWindowRequestedEventArgs2 { 114 | /// The frame info of the frame where the new window request originated. The 115 | /// `OriginalSourceFrameInfo` is a snapshot of frame information at the time when the 116 | /// new window was requested. See `ICoreWebView2FrameInfo` for details on frame 117 | /// properties. 118 | [propget] HRESULT OriginalSourceFrameInfo([out, retval] ICoreWebView2FrameInfo** frameInfo); 119 | } 120 | ``` 121 | 122 | ```c# 123 | namespace Microsoft.Web.WebView2.Core 124 | { 125 | runtimeclass CoreWebView2NewWindowRequestedEventArgs 126 | { 127 | // ... 128 | 129 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2NewWindowRequestedEventArgs3")] 130 | { 131 | // The frame info of the frame where the new window request originated. The 132 | // `OriginalSourceFrameInfo` is a snapshot of frame information at the time when the 133 | // new window was requested. See `CoreWebView2FrameInfo` for details on frame 134 | // properties. 135 | CoreWebView2FrameInfo OriginalSourceFrameInfo { get; }; 136 | } 137 | } 138 | } 139 | ``` 140 | -------------------------------------------------------------------------------- /specs/PreferredColorScheme.md: -------------------------------------------------------------------------------- 1 | Preferred Color Scheme API 2 | === 3 | 4 | # Background 5 | This API's main use is to set the preferred color scheme for WebView2's which are associated with a profile. The options are similar to Edge: auto - which match the OS's default color scheme, change to light color scheme, or change to dark color scheme. This sets the color scheme for WebView2 UI like dialogs, prompts, and context menus by setting the ['prefers-color-scheme'](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) [media feature](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#media_features). Websites typically query for this setting in order to set CSS themes for light/dark. 6 | 7 | Please note this API will only set the overall appearance, but not theme as defined in the Edge browser. 8 | For reference, in the screenshot below, this API is meant to expose the Overall Appearance section as a WebView2 API. 9 | 10 | ![Edge Settings Appearance Page](https://github.com/MicrosoftEdge/WebView2Feedback/blob/api-appearance/specs/images/EdgeSettingsAppearance.png) 11 | 12 | # Description 13 | We propose extending `CoreWebView2Profile` to include a `PreferredColorScheme` property. This property will apply 14 | to any WebView2's which are associated with this profile. 15 | 16 | # Examples 17 | 18 | ## C++ 19 | 20 | ```cpp 21 | wil::com_ptr m_webView; 22 | 23 | void ViewComponent::SetPreferredColorScheme(COREWEBVIEW2_PREFERRED_COLOR_SCHEME value) 24 | { 25 | wil::com_ptr webView7; 26 | webView7 = m_webView.try_query(); 27 | 28 | if (webView7) 29 | { 30 | wil::com_ptr profile; 31 | CHECK_FAILURE(webView7->get_Profile(&profile)); 32 | 33 | auto profile3 = profile.try_query(); 34 | if (profile3) 35 | { 36 | profile3->put_PreferredColorScheme(value); 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | ## C# 43 | 44 | ```c# 45 | 46 | private CoreWebView2 m_webView; 47 | 48 | void SetPreferredColorScheme(CoreWebView2PreferredColorScheme value) 49 | { 50 | m_webView.Profile.PreferredColorScheme = value; 51 | } 52 | 53 | ``` 54 | 55 | # API Details 56 | ## C++ 57 | ```cpp 58 | [uuid(5f817cce-5d36-4cd0-a1d5-aaaf95c8685f), object, pointer_default(unique)] 59 | interface ICoreWebView2Profile3 : ICoreWebView2Profile2 { 60 | /// The PreferredColorScheme property sets the overall color scheme of the WebView2's associated 61 | /// with this profile. This sets the color scheme for WebView2 UI like dialogs, 62 | /// prompts, and context menus by setting the 63 | /// ['prefers-color-scheme'](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme) 64 | /// CSS media feature for websites to respond to. 65 | /// 66 | /// The default value for this is COREWEBVIEW2_PREFERRED_COLOR_SCHEME_AUTO, which will 67 | /// follow whatever color scheme the OS is currently set to. 68 | /// 69 | /// \snippet ViewComponent.cpp SetPreferredColorScheme 70 | /// Returns the value of the `PreferredColorScheme` property. 71 | [propget] HRESULT PreferredColorScheme( 72 | [out, retval] COREWEBVIEW2_PREFERRED_COLOR_SCHEME* value); 73 | 74 | /// Sets the `PreferredColorScheme` property. 75 | [propput] HRESULT PreferredColorScheme( 76 | [in] COREWEBVIEW2_PREFERRED_COLOR_SCHEME value); 77 | } 78 | 79 | /// An enum to represent the options for WebView2 Color Scheme: auto, light, or dark. 80 | [v1_enum] 81 | typedef enum COREWEBVIEW2_PREFERRED_COLOR_SCHEME { 82 | /// Auto color scheme 83 | COREWEBVIEW2_PREFERRED_COLOR_SCHEME_AUTO, 84 | 85 | /// Light color scheme 86 | COREWEBVIEW2_PREFERRED_COLOR_SCHEME_LIGHT, 87 | 88 | /// Dark color scheme 89 | COREWEBVIEW2_PREFERRED_COLOR_SCHEME_DARK 90 | } COREWEBVIEW2_PREFERRED_COLOR_SCHEME; 91 | ``` 92 | 93 | ### C# 94 | ```c# 95 | namespace Microsoft.Web.WebView2.Core 96 | { 97 | [doc_string("An enum to represent the options for WebView2 Preferred Color Scheme: auto, light, or dark.")] 98 | enum CoreWebView2PreferredColorScheme 99 | { 100 | [doc_string("Auto color scheme.")] 101 | Auto = 0, 102 | [doc_string("Light color scheme.")] 103 | Light = 1, 104 | [doc_string("Dark color scheme.")] 105 | Dark = 2, 106 | }; 107 | 108 | [doc_string("Multiple profiles can be created under a single user data directory but with separated cookies, user preference settings, and various data storage etc..")] 109 | runtimeclass CoreWebView2Profile 110 | { 111 | // ... 112 | 113 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Profile3")] 114 | { 115 | [doc_string("The PreferredColorScheme property sets the overall color scheme of the WebView2's associated with this profile. This sets the color scheme for WebView2 UI like dialogs, prompts, and context menus by setting the prefers-color-scheme CSS media feature for websites to respond to. The default value for this is CoreWebView2PreferredColorScheme.Auto, which will follow whatever color scheme the OS is currently set to.")] 116 | CoreWebView2PreferredColorScheme PreferredColorScheme { get; set }; 117 | } 118 | } 119 | } 120 | ``` 121 | -------------------------------------------------------------------------------- /specs/RestartRequested.md: -------------------------------------------------------------------------------- 1 | Restart Requested 2 | === 3 | 4 | # Background 5 | There are often times when WebView2 needs to be restarted to apply certain updates or change 6 | configuration. The purpose of this API is to detect whether such a restart is requested and 7 | to provide the urgency of the restart. WebView2 developers can listen to this event for version 8 | updates, version downgrades, or important configuration changes to determine if they need to 9 | prompt the user for a restart to apply those updates. 10 | 11 | # Examples 12 | ## WinRT and .NET 13 | ```c# 14 | void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) 15 | { 16 | if (e.IsSuccess) 17 | { 18 | // ... 19 | webView.CoreWebView2.Environment.RestartRequested += WebView_RestartRequested; 20 | } 21 | } 22 | 23 | void WebView_RestartRequested(CoreWebView2Environment sender, CoreWebView2RestartRequestedEventArgs e) 24 | { 25 | if (e.Priority <= CoreWebView2RestartRequestedPriority.Normal) 26 | { 27 | // Depending on your app experience, you should remind the user 28 | // to restart on normal cadence. 29 | RemindToRestartForUpdate(); 30 | } 31 | else 32 | { 33 | // Depending on your app experience, you should prompt 34 | // the user to save their current state and restart or otherwise more urgently restart the WebView2. 35 | RestartIfSelectedByUser(); 36 | } 37 | } 38 | ``` 39 | 40 | ## Win32 C++ 41 | ```cpp 42 | wil::com_ptr m_webViewEnvironment; 43 | void CoreWebView2InitializationCompleted() { 44 | auto env10 = m_webViewEnvironment.try_query(); 45 | if (env10) { 46 | CHECK_FAILURE(env10->add_RestartRequested( 47 | Callback( 48 | [this](ICoreWebView2Environment* sender, ICoreWebView2RestartRequestedEventArgs* args) -> HRESULT 49 | { 50 | COREWEBVIEW2_RESTART_REQUESTED_PRIORITY priority; 51 | CHECK_FAILURE(args->get_Priority(&priority)); 52 | if (priority <= COREWEBVIEW2_RESTART_REQUESTED_PRIORITY_NORMAL) 53 | { 54 | // Depending on your app experience, you should remind user 55 | // to restart on normal cadence. 56 | RemindToRestartForUpdate(); 57 | } 58 | else 59 | { 60 | // Depending on your app experience, you should prompt 61 | // user to save their current state and restart. 62 | RestartIfSelectedByUser(); 63 | } 64 | return S_OK; 65 | }) 66 | .Get(), 67 | nullptr)); 68 | } 69 | } 70 | ``` 71 | 72 | # API Notes 73 | 74 | See [API Details](#api-details) section below for API reference. 75 | 76 | # API Details 77 | ## Win32 C++ 78 | 79 | ```IDL 80 | interface ICoreWebView2Environment10; 81 | interface ICoreWebView2RestartRequestedEventHandler; 82 | interface ICoreWebView2RestartRequestedEventArgs; 83 | 84 | /// Specifies the restart requested priority from 85 | /// `ICoreWebView2RestartRequestedEventArgs` interface. 86 | [v1_enum] 87 | typedef enum COREWEBVIEW2_RESTART_REQUESTED_PRIORITY { 88 | /// Developer should remind user to restart. 89 | COREWEBVIEW2_RESTART_REQUESTED_PRIORITY_NORMAL = 1000, 90 | /// Developer should prompt user to restart as soon as possible. 91 | COREWEBVIEW2_RESTART_REQUESTED_PRIORITY_HIGH = 2000, 92 | } COREWEBVIEW2_RESTART_REQUESTED_PRIORITY; 93 | 94 | [uuid(62cb67c6-b6a9-4209-8a12-72ca093b9547), object, pointer_default(unique)] 95 | interface ICoreWebView2RestartRequestedEventHandler : IUnknown { 96 | /// Provides the event args for the corresponding event. 97 | HRESULT Invoke( 98 | [in] ICoreWebView2Environment* sender, 99 | [in] ICoreWebView2RestartRequestedEventArgs* args); 100 | } 101 | 102 | /// Event args for the `RestartRequested` event. 103 | [uuid(6dbfe971-a69e-4338-9b6e-b0ec9f12424f), object, pointer_default(unique)] 104 | interface ICoreWebView2RestartRequestedEventArgs : IUnknown { 105 | /// Get the restart requested priority. 106 | [propget] HRESULT Priority([out, retval] COREWEBVIEW2_RESTART_REQUESTED_PRIORITY* value); 107 | } 108 | 109 | [uuid(ef7632ec-d86e-46dd-9d59-e6ffb5c87878), object, pointer_default(unique)] 110 | interface ICoreWebView2Environment10 : IUnknown { 111 | /// Add an event handler for the `RestartRequested` event. 112 | /// `RestartRequested` event is raised when there is a need to restart WebView2 process 113 | /// in order to apply certain beneifical updates. 114 | /// 115 | /// `RestartRequested` gives developers the awareness of these necessary WebView2 restarts, 116 | /// allowing developers to resolve issues faster than waiting for end users to restart the app. 117 | /// Developer might want to give end users the ability to save their state before restarting. 118 | /// For apps with multiple processes that host WebView2s that share the same user data folder you 119 | /// need to make sure all WebView2 instances are closed and the associated WebView2 Runtime 120 | /// browser process exits. See `BrowserProcessExited` for more details. 121 | // MSOWNERS: xiaqu@microsoft.com 122 | HRESULT add_RestartRequested( 123 | [in] ICoreWebView2RestartRequestedEventHandler* eventHandler, 124 | [out] EventRegistrationToken* token); 125 | 126 | /// Remove an event handler previously added with `add_RestartRequested`. 127 | // MSOWNERS: xiaqu@microsoft.com 128 | HRESULT remove_RestartRequested( 129 | [in] EventRegistrationToken token); 130 | } 131 | ``` 132 | s 133 | ## .NET and WinRT 134 | 135 | ```c# 136 | namespace Microsoft.Web.WebView2.Core 137 | { 138 | enum CoreWebView2RestartRequestedPriority 139 | { 140 | Normal = 1000, 141 | High = 2000, 142 | }; 143 | 144 | runtimeclass CoreWebView2RestartRequestedEventArgs 145 | { 146 | CoreWebView2RestartRequestedPriority Priority { get; }; 147 | } 148 | 149 | runtimeclass CoreWebView2Environment 150 | { 151 | // ... 152 | event Windows.Foundation.TypedEventHandler RestartRequested; 153 | } 154 | } 155 | ``` -------------------------------------------------------------------------------- /specs/StatusBarMessage.md: -------------------------------------------------------------------------------- 1 | 7 | # Background 8 | The browser has a Status bar that displays text when hovering over a link, or performing some activity. Currently, 9 | developers are able to opt in to disable showing the status bar through the browser 10 | settings. 11 | 12 | Developers would also like to be able to opt in to intercept the text which would 13 | normally be displayed by the Status bar, and show it using their own custom UI. 14 | # Description 15 | We propose a new event for WebView2 that would allow developers to 16 | listen for Status bar updates which are triggered by activity on the WebView, and then handle those updates however they want in their applications. 17 | 18 | Developers will be able to register an event handler for changes to the status bar text. 19 | # Examples 20 | ## Win32 C++ Registering a listener for status bar text changes 21 | ``` 22 | CHECK_FAILURE(m_webView->add_StatusBarTextChanged( 23 | Microsoft::WRL::Callback( 24 | [this](ICoreWebView2* sender, ICoreWebView2StatusBarTextChangedEventArgs* args) -> HRESULT 25 | { 26 | 27 | Microsoft::WRL::ComPtr webview5; 28 | CHECK_FAILURE(sender->QueryInterface(IID_PPV_ARGS(&webview5))); 29 | 30 | wil::unique_cotaskmem_string value; 31 | CHECK_FAILURE(webview5->get_StatusBarText(&value)); 32 | 33 | if (wcslen(value) != 0) 34 | { 35 | 36 | m_statusBar.show(value); 37 | } else { 38 | 39 | m_statusBar.hide(); 40 | } 41 | 42 | return S_OK; 43 | } 44 | ).Get(), 45 | &m_statusBarTextChangedToken)); 46 | ``` 47 | ## .NET / WinRT Registering a listener for status bar text changes 48 | ``` 49 | webView.CoreWebView2.StatusBarTextChanged += (CoreWebView2 sender, Object arg) => 50 | { 51 | string value = sender.StatusBarText; 52 | // Handle status bar text in value 53 | if (value.Length != 0) { 54 | statusBar.show(value); 55 | } else { 56 | statusBar.hide(); 57 | } 58 | 59 | }; 60 | ``` 61 | # API Notes 62 | See [API Details](#api-details) Section below for API reference 63 | # API Details 64 | ## Win32 C++ 65 | ``` 66 | /// Interface for the status bar text changed event handler 67 | [uuid(85c8b75a-ceac-11eb-b8bc-0242ac130003), object, pointer_default(unique)] 68 | interface ICoreWebView2StatusBarTextChangedEventHandler : IUnknown { 69 | /// Called to provide the implementer with the event args for the 70 | /// corresponding event. 71 | HRESULT Invoke( 72 | [in] ICoreWebView2* sender, 73 | [in] ICoreWebView2StatusBarTextChangedEventArgs* args); 74 | } 75 | 76 | /// Interface for status bar text change event args 77 | [uuid(2B9CAB1C-BE29-4FC8-BFDD-20AF170ACA7F), object, pointer_default(unique)] 78 | interface ICoreWebView2StatusBarTextChangedEventArgs : IUnknown { 79 | 80 | } 81 | 82 | [uuid(b2c01782-ceaf-11eb-b8bc-0242ac130003), object, pointer_default(unique)] 83 | interface ICoreWebView2_5 : ICoreWebView2_4 { 84 | /// Add an event handler for the `StatusBarTextChanged` event. 85 | /// `StatusBarTextChanged` runs when the WebView statusbar content changes 86 | /// status bar 87 | HRESULT add_StatusBarTextChanged( 88 | [in] ICoreWebView2StatusBarTextChangedEventHandler* eventHandler, 89 | [out] EventRegistrationToken* token); 90 | 91 | /// Removing the event handler for `StatusBarTextChanged` event 92 | HRESULT remove_StatusBarTextChanged( 93 | [in] EventRegistrationToken token); 94 | 95 | /// used to access the current value of the status bar text 96 | [propget] HRESULT StatusBarText([out, retval] LPWSTR* value); 97 | } 98 | ``` 99 | ## .Net/ WinRT 100 | ``` 101 | namespace Microsoft.Web.WebView2.Core { 102 | 103 | /// Interface for the status bar text changed event handler 104 | runtimeclass CoreWebView2 { 105 | event Windows.Foundation.TypedEventHandler StatusBarTextChanged; 106 | string StatusBarText {get;}; 107 | } 108 | } 109 | ``` 110 | # Appendix 111 | 116 | See here for more details about the Status bar: Here 117 | -------------------------------------------------------------------------------- /specs/SystemCursorId.md: -------------------------------------------------------------------------------- 1 | # Background 2 | 3 | When an app is using composition hosting to host WebView, the current cursor 4 | image cannot be determined easily by the hosting application. For example, if 5 | the cursor over the WebView is also over a textbox inside of the WebView, the 6 | cursor should usually be IDC_IBEAM. And by default, the cursor is IDC_ARROW. 7 | Currently, the `ICoreWebView2CompositionController.Cursor` property returns what 8 | the cursor should be as an HCURSOR object, which the hosting application can 9 | then use the to change the current cursor to the correct image. 10 | 11 | However, Office already has a well established way of using cursors internally 12 | by using IDC_* values and there is no easy way to convert the HCURSOR object we 13 | are returning into an IDC value after it's been created. 14 | 15 | This new API is to enable hosting applications like Office to get the current 16 | IDC value of the cursor instead of the HCURSOR as an option. 17 | 18 | Note that this is a COM and .NET spec as WinRT uses a separate enum structure to 19 | identify cursor IDs. 20 | 21 | 22 | # Description 23 | 24 | The `SystemCursorId` property will return the current system cursor ID reported 25 | by the underlying rendering engine for WebView2. It is not meant to return a 26 | value for any custom cursors, such as those defined by CSS. 27 | 28 | It can be used at any time but will only change after a `CursorChanged` event. 29 | 30 | Note that developers should generally use the `Cursor` property to support cases 31 | where there may be custom cursors. 32 | 33 | 34 | # Examples 35 | 36 | ```cpp 37 | // Handler for WM_SETCURSOR window message. 38 | bool OnSetCursor() 39 | { 40 | POINT point; 41 | if (m_compositionController && GetCursorPos(&point)) 42 | { 43 | // Calculate if the point lies in the WebView visual for composition hosting 44 | // as it may not cover the whole HWND it's under. 45 | if (PtInRect(&m_webViewBounds, point)) 46 | { 47 | HCURSOR cursor; 48 | UINT32 cursorId; 49 | wil::com_ptr compositionController2 = 50 | m_compositionController.query(); 51 | CHECK_FAILURE(compositionController2->get_SystemCursorId(&cursorId)); 52 | cursor = ::LoadCursor(nullptr, MAKEINTRESOURCE(cursorId)); 53 | 54 | if (cursor) 55 | { 56 | ::SetCursor(cursor); 57 | return true; 58 | } 59 | } 60 | } 61 | return false; 62 | } 63 | 64 | CHECK_FAILURE(m_compositionController->add_CursorChanged( 65 | Callback( 66 | [this](ICoreWebView2CompositionController* sender, IUnknown* args) 67 | -> HRESULT { 68 | // No need to do hit testing here as the WM_SETCURSOR handler will have 69 | // to calculate if the point is within the WebView anyways. 70 | SendMessage(m_appWindow->GetMainWindow(), WM_SETCURSOR, 71 | (WPARAM)m_appWindow->GetMainWindow(), MAKELPARAM(HTCLIENT, WM_MOUSEMOVE)); 72 | return S_OK; 73 | }) 74 | .Get(), 75 | &m_cursorChangedToken)); 76 | 77 | 78 | # API Notes 79 | 80 | See [API Details](#api-details) section below for API reference. 81 | 82 | 83 | # API Details 84 | 85 | ```cpp 86 | /// This interface is continuation of the 87 | /// ICoreWebView2CompositionController interface. 88 | [uuid(279ae616-b7cb-4946-8da3-dc853645d2ba), object, pointer_default(unique)] 89 | interface ICoreWebView2CompositionController2 : ICoreWebView2CompositionController { 90 | /// The current system cursor ID reported by the underlying rendering engine 91 | /// for WebView. For example, most of the time, when the cursor is over text, 92 | /// this will return the int value for IDC_IBEAM. The systemCursorId is only 93 | /// valid if the rendering engine reports a default Windows cursor resource 94 | /// value. See: 95 | /// https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-loadcursorw 96 | /// Otherwise, if custom CSS cursors are being used, this will return 0. 97 | /// To actually use systemCursorId in LoadCursor or LoadImage, 98 | /// MAKEINTRESOURCE must be called on it first. 99 | /// If possible, use the Cursor property rather than the SystemCursorId 100 | /// property because the Cursor property can express custom CSS cursors. 101 | /// 102 | /// \snippet ViewComponent.cpp SystemCursorId 103 | [propget] HRESULT SystemCursorId([out, retval] UINT32* systemCursorId); 104 | } 105 | ``` 106 | 107 | ```c# 108 | namespace Microsoft.Web.WebView2.Core 109 | { 110 | // 111 | // Summary: 112 | // This class is an extension of the CoreWebView2CompositionController class to support composition 113 | // hosting. 114 | public class CoreWebView2CompositionController2 115 | { 116 | // 117 | // Summary: 118 | // The current system cursor ID that WebView thinks it should be. 119 | // 120 | // Remarks: 121 | // The current system cursor ID reported by the underlying rendering engine 122 | // for WebView. For example, most of the time, when the cursor is over text, 123 | // this will return the int value for IDC_IBEAM. The SystemCursorId is only 124 | // valid if the rendering engine reports a default Windows cursor resource 125 | // value. See: 126 | // https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-loadcursorw 127 | // Otherwise, if custom CSS cursors are being used, this will return 0. 128 | // To create a Cursor object, create an IntPtr from the returned uint to 129 | // pass into the constructor 130 | // If possible, use the Cursor property rather than the SystemCursorId 131 | // property because the Cursor property can express custom CSS cursors. 132 | public Uint32 SystemCursorId { get; } 133 | } 134 | } 135 | ``` 136 | 137 | # Appendix 138 | 139 | I expect that most apps will use the get_Cursor API which returns an HCURSOR (Or 140 | the UWP equivalent that will be implemented in the future that will return a 141 | CoreCursor) outside of Office as HCURSOR is more comprehensive and covers the 142 | scenarios in which custom cursors are used. 143 | -------------------------------------------------------------------------------- /specs/UserAgent.md: -------------------------------------------------------------------------------- 1 | # Background 2 | 3 | Currently, a developer can pass the --user-agent browser args to the CreateWebView2EnvironmentWithDetails function. 4 | 5 | Ex. CreateWebView2EnvironmentWithDetails(nullptr, nullptr, L"--user-agent=\\"myUA\\"", ...); 6 | 7 | For more info about the ‘--user-agent’ flag visit: https://peter.sh/experiments/chromium-command-line-switches/#user-agent. 8 | 9 | However, there are a couple limitations to this workaround-- it is not an API that is easy to use or discover, you cannot modify a command line switch at runtime, and you cannot change the User Agent per WebView. In this document we describe the new API. We'd appreciate your feedback. 10 | 11 | # Description 12 | 13 | The User Agent (UA) is a piece of information regarding the user's OS, application, and version. The browser/webcontrol sends the User Agent to the HTTP server. 14 | 15 | The User Agent property lets developers modify WebView2's User Agent. A key scenario is to allow end developers to get the current User Agent from the WebView and modify it based on an event. 16 | 17 | Ex. Update the User Agent to emulate a different browser version upon navigation to a specific website. 18 | 19 | # Examples 20 | 21 | The following code snippet demonstrates how the User Agent property can be used: 22 | 23 | ## Win32 C++ 24 | 25 | ```cpp 26 | m_webView->add_NavigationStarting( 27 | Callback( 28 | [this](ICoreWebView2 *sender, 29 | ICoreWebView2NavigationStartingEventArgs *args) -> HRESULT { 30 | static const PCWSTR url_compare_example = L"fourthcoffee.com"; 31 | wil::unique_cotaskmem_string uri; 32 | CHECK_FAILURE(args->get_Uri(&uri)); 33 | wil::unique_bstr domain = GetDomainOfUri(uri.get()); 34 | const wchar_t *domains = domain.get(); 35 | wil::com_ptr settings; 36 | CHECK_FAILURE(m_webView->get_Settings(&m_settings)); 37 | if (wcscmp(url_compare_example, domains) == 0) { 38 | // Upon navigation to a specified url 39 | // Change the user agent to emulate a mobile device 40 | CHECK_FAILURE(settings->put_UserAgent(GetMobileUserAgent())); 41 | } else { 42 | // Change the user agent back to desktop 43 | CHECK_FAILURE(settings->put_UserAgent(GetDesktopUserAgent())); 44 | } 45 | return S_OK; 46 | }) 47 | .Get(), 48 | &m_navigationStartingToken); 49 | ``` 50 | 51 | ## .NET and WinRT 52 | 53 | ```c # 54 | webView2Control.NavigationStarting += SetUserAgent; 55 | 56 | private void SetUserAgent(CoreWebView2 sender, CoreWebView2NavigationStartingEventArgs e) 57 | { 58 | var settings = webView2Control.CoreWebView2.Settings; 59 | // Note: Oversimplified test. Need to support idn, case-insensitivity, etc. 60 | if (new Uri(e.Uri).Host == "fourthcoffee.com") { 61 | settings.UserAgent = GetMobileUserAgent(); 62 | } else { 63 | settings.UserAgent = GetDesktopUserAgent(); 64 | } 65 | } 66 | ``` 67 | 68 | # API Notes 69 | 70 | See [API Details](#api-details) section below for API reference. 71 | 72 | # API Details 73 | 74 | ## Win32 C++ 75 | 76 | ```IDL 77 | // This is the ICoreWebView2Settings interface. 78 | [uuid(684cbeef-47ba-4d4a-99f4-976113f9f10a), object, pointer_default(unique)] 79 | interface ICoreWebView2Settings2 : ICoreWebView2Settings { 80 | /// `UserAgent` . Returns the User Agent. The default value is the 81 | /// default User Agent of the Edge browser. 82 | [propget] HRESULT UserAgent([ out, retval ] LPWSTR * userAgent); 83 | /// Sets the `UserAgentString` property. This property may be overriden if 84 | /// the User-Agent header is set in a request. If the parameter is empty 85 | /// the User Agent will not be updated and the current User Agent will remain. 86 | [propput] HRESULT UserAgent([in] LPCWSTR userAgent); 87 | } 88 | ``` 89 | ## .NET and WinRT 90 | 91 | ```c# 92 | namespace Microsoft.Web.WebView2.Core 93 | { 94 | public partial class CoreWebView2Settings 95 | { 96 | public string UserAgent { get; set; }; 97 | } 98 | } 99 | ``` 100 | -------------------------------------------------------------------------------- /specs/UserDataFolder.md: -------------------------------------------------------------------------------- 1 | 2 | Title 3 | === 4 | UserDataFolder API 5 | 6 | # Background 7 | You may have a need to cleanup or possibly add to the data being 8 | stored in the WebView2 user data directory. This directory can be either 9 | configured by you during creation of the webview2 control or calculated 10 | at runtime by the control if it wasn't set during creation. 11 | 12 | The current WebView2 code defaults the user data folder to the directory that 13 | contains the hosting application's executable. This has resulted in issues 14 | if running from a folder for which the WebView2 process doesn't have write access 15 | such as a Program Files folder. Work is in progress to change that default and 16 | will be forthcoming in later changes. 17 | 18 | With the current implementation it is possible for you to have built 19 | logic into your application with an assumption where the User Data is 20 | located. WebView2 changing that default can then result in a code error or 21 | possible crash. 22 | 23 | This api will provide you a way to get the directory that is 24 | currently being used by the WebView for storage of the user data. 25 | 26 | Using this returned directory is safer for the long run so that if WebView2 27 | changes the underlying path default logic the application will be able to adapt 28 | automatically. 29 | 30 | # Description 31 | 32 | Returns the user data folder that all CoreWebView2's created from this 33 | environment are using. 34 | This could be either the value passed in by you when creating the 35 | environment object or the calculated one for default handling. It will 36 | always be an absolute path. 37 | 38 | 39 | # Examples 40 | 41 | ```cpp 42 | HRESULT UserDataFolder() 43 | { 44 | Microsoft::WRL::ComPtr WebViewEnvironment6; 45 | m_webViewEnvironment->QueryInterface(IID_PPV_ARGS(&WebViewEnvironment6)); 46 | 47 | if (WebViewEnvironment6 != NULLPTR) 48 | { 49 | // get the current user data folder from the webview environment object 50 | wil::unique_cotaskmem_string userDataFolder; 51 | WebViewEnvironment6->get_UserDataFolder(&userDataFolder); 52 | 53 | // using the folder 54 | WriteAppLog(userDataFolder.get(), "Logging information"); 55 | } 56 | }``` 57 | 58 | ```c# 59 | 60 | /// Webview creation and setup of completion handler are out of scope of sample 61 | void WebView_CoreWebView2InitializationCompleted(object sender, CoreWebView2InitializationCompletedEventArgs e) 62 | { 63 | if (e.IsSuccess) 64 | { 65 | // Get the current user data folder 66 | String userDataFolder = webView.CoreWebView2.Environment.UserDataFolder(); 67 | 68 | // using the folder 69 | WriteAppLog(userDataFolder, "Logging information"); 70 | } 71 | } 72 | 73 | ``` 74 | 75 | # API Details 76 | ```c# (but really MIDL3) 77 | /// This interface is an extension of the ICoreWebView2Environment. An object 78 | /// implementing the ICoreWebView2Environment6 interface will also 79 | /// implement ICoreWebView2Environment. 80 | [ 81 | uuid(083CB0D7-E464-4108-807E-80AE4EAA3B28), object, 82 | pointer_default(unique) 83 | ] interface ICoreWebView2Environment6 : ICoreWebView2Environment5 { 84 | /// Returns the user data folder that all CoreWebView2's created from this 85 | /// environment are using. 86 | /// This could be either the value passed in by the developer when creating the 87 | /// environment object or the calculated one for default handling. And will 88 | /// always be an absolute path. 89 | /// 90 | /// \snippet AppWindow.cpp GetUserDataFolder 91 | 92 | [propget] HRESULT UserDataFolder([ out, retval ] LPWSTR * value); 93 | } 94 | ``` 95 | 96 | ```c# (but really MIDL3) 97 | namespace Microsoft.Web.WebView2.Core 98 | { 99 | runtimeclass CoreWebView2Environment 100 | { 101 | [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Environment6")] 102 | { 103 | // ICoreWebView2ExperimentalEnvironment5 members 104 | String UserDataFolder { get; }; 105 | } 106 | } 107 | } 108 | ``` -------------------------------------------------------------------------------- /specs/images/EdgeSettingsAppearance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftEdge/WebView2Feedback/08c19658c259637dda8ae4dca7a6705fae89a172/specs/images/EdgeSettingsAppearance.png -------------------------------------------------------------------------------- /specs/images/TrackingPreventionLevels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MicrosoftEdge/WebView2Feedback/08c19658c259637dda8ae4dca7a6705fae89a172/specs/images/TrackingPreventionLevels.png -------------------------------------------------------------------------------- /specs/wv2winrt-cacheable-properties.md: -------------------------------------------------------------------------------- 1 | wv2winrt Cacheable Properties 2 | === 3 | 4 | # Background 5 | 6 | WebView2 supports WinRT projection into JavaScript similar to how the previous edgehtml 7 | WebView support WinRT projection. However unlike the previous WebView, for WebView2 the 8 | WinRT objects live in a different process from the JavaScript that invokes the WinRT. 9 | Because of this cross-process access, performance is something we're working on improving. 10 | To that end, this feature allows you to mark individual runtimeclass properties as 11 | cacheable so that the JavaScript running in the renderer process can cache the result of 12 | the property value the first time and avoid subsequent cross-process calls each time the 13 | property is accessed. Working with partner apps with existing JavaScript that uses WinRT 14 | this was identified as something in particular that could help improve runtime 15 | performance. 16 | 17 | # Examples 18 | 19 | ```c# (but really MIDL3) 20 | [default_interface] 21 | runtimeclass Toaster 22 | { 23 | // This property changes value throughout the lifetime of the object so is not 24 | // marked readonly. 25 | Boolean Available { get; }; 26 | 27 | // This property has one value for the lifetime of the object so we mark it 28 | // cacheable to improve runtime performance. 29 | [cacheable] 30 | String Model { get; }; 31 | 32 | // ... 33 | } 34 | ``` 35 | 36 | # API Details 37 | 38 | ```c# (but really MIDL3) 39 | namespace Microsoft.Web.WebView2.Core 40 | { 41 | /// You can use the `cacheable` attribute on a runtimeclass property 42 | /// or runtimeclass method to indicate that the property value or 43 | /// method return value can be cached. 44 | /// 45 | /// You can apply it to an instance property if the property 46 | /// value doesn't change for the lifetime of its object instance. 47 | /// You can apply it to a static property if the property value 48 | /// doesn't change for the lifetime of the process. 49 | /// You can apply it to an instance method if when the method is called 50 | /// with the same parameters it always returns the same value for the 51 | /// lifetime of its object instance. 52 | /// You can apply it to a static method if when the method is called 53 | /// with the same parameters it always returns the same value for the 54 | /// lifetime of the process. 55 | /// 56 | /// When an object is projected into JavaScript via 57 | /// `CoreWebView2.AddHostObjectToScript`, WebView2 will cache property values 58 | /// marked with this attribute. This can potentially improve performance by 59 | /// reducing the number of cross-process calls to obtain the latest value. 60 | [attributeusage(target_property, target_method)] 61 | [attributename("cacheable")] 62 | attribute CacheableAttribute 63 | { 64 | } 65 | } 66 | ``` 67 | 68 | # Appendix 69 | 70 | Names considered for the attribute: 71 | * **Cacheable**: A familiar term also used by python that more closely matches this feature. 72 | * **ReadOnly**: Similar to C#'s readonly keyword which indicates a value won't change (once 73 | initialized). But does not convey that the implementer cannot change the value. 74 | * **Immutable**: Similar to readonly 75 | * **Const**: Does a better job indicating that the value does not change even by the 76 | implementer. 77 | * **Memoizable**: A broader term than cacheable that also applies to methods but more specific 78 | than cacheable in that it better defines the kind of caching. 79 | 80 | For the sample code, the only code you have to write is applying the attribute to the 81 | property. The only effect this has is to potentially improve performance so there's no other 82 | code to demonstrate anything. Accordingly, not sure what else to do in the sample code other 83 | than the MIDL3. 84 | --------------------------------------------------------------------------------